10.1 Podstawy polimorfizmu
Polimorfizm to jedna z kluczowych koncepcji w programowaniu obiektowym (OOP). W ogólnym sensie, polimorfizm umożliwia obiektom różnych klas przetwarzanie danych za pomocą tego samego interfejsu. W kontekście JavaScript oznacza to, że różne obiekty mogą mieć metody o tych samych nazwach, a te metody mogą być wywoływane na obiektach bez znajomości ich konkretnych typów.
Typy polimorfizmu
W JavaScript główne typy polimorfizmu to:
1. Polimorfizm ad-hoc (ad-hoc polymorphism):
- Polimorfizm metod, wywołanie metod o tej samej nazwie dla obiektów różnych typów
- Przykłady obejmują przeciążanie funkcji i operatorów (co nie jest bezpośrednio obsługiwane w JavaScript, ale może być symulowane)
2. Polimorfizm przez podtypy (Subtype polymorphism):
- Polimorfizm podtypów lub inkluzji, kiedy obiekty różnych klas, dziedziczących z tej samej klasy bazowej, mogą być traktowane jako obiekty klasy bazowej
- To podstawowy typ polimorfizmu, realizowany przez dziedziczenie i interfejsy
Korzyści z polimorfizmu:
- Uproszczenie kodu: polimorfizm pozwala pisać bardziej elastyczny i ogólny kod, który może działać z różnymi typami obiektów, nie znając ich konkretnych typów.
- Rozszerzalność: polimorfizm ułatwia dodawanie nowych typów i zachowań do systemu bez konieczności zmiany istniejącego kodu.
- Wsparcie: polimorfizm sprzyja lepszemu podziałowi obowiązków i zwiększa czytelność oraz konserwowalność kodu.
10.2 Przykłady polimorfizmu w JavaScript
Polimorfizm przez podtypy dzięki dziedziczeniu
Przykład 1: Przetwarzanie różnych typów obiektów za pomocą jednego interfejsu
W tym przykładzie funkcja playWithAnimal przyjmuje obiekt typu Animal i wywołuje metodę makeSound. Obiekty Dog i Cat, które dziedziczą po Animal, nadpisują metodę makeSound, dzięki czemu wywołanie tej metody na każdym obiekcie daje różne wyniki.
class Animal {
makeSound() {
console.log('Some generic sound');
}
}
class Dog extends Animal {
makeSound() {
console.log('Woof!');
}
}
class Cat extends Animal {
makeSound() {
console.log('Meow!');
}
}
function playWithAnimal(animal) {
animal.makeSound();
}
const dog = new Dog();
const cat = new Cat();
playWithAnimal(dog); // Wyświetli: Woof!
playWithAnimal(cat); // Wyświetli: Meow!
10.3 Polimorfizm przez interfejsy (Duck Typing)
W JavaScript nie ma wbudowanej obsługi interfejsów, jak w innych językach, takich jak TypeScript czy Java. Zamiast tego stosuje się podejście, zwane "Duck Typing". Oznacza to, że obiekt uznaje się za zgodny z interfejsem, jeśli ma wymagane metody i właściwości, niezależnie od jego konkretnego typu czy dziedziczenia.
Zasada kaczki (duck): jeśli coś wygląda jak kaczka, pływa jak kaczka i kwacze jak kaczka, to jest to najprawdopodobniej kaczka.
Przykład 2: Zastosowanie Duck Typing
W tym przykładzie funkcja takeOff przyjmuje dowolny obiekt, który ma metodę fly. Obiekty Bird i Airplane implementują metodę fly, dzięki czemu można je przekazać do takeOff.
class Bird {
fly() {
console.log('Flying...');
}
}
class Airplane {
fly() {
console.log('Jet engine roaring...');
}
}
function takeOff(flyingObject) {
flyingObject.fly();
}
const bird = new Bird();
const airplane = new Airplane();
takeOff(bird); // Wyświetli: Flying...
takeOff(airplane); // Wyświetli: Jet engine roaring...
10.4 Polimorfizm przez funkcje
W JavaScript funkcje są obiektami pierwszej klasy, można je przekazywać i używać do realizacji polimorficznego zachowania.
Przykład 3: Polimorfizm przez funkcje
W tym przykładzie funkcja greet przyjmuje inną funkcję jako argument i ją wywołuje. Dzięki temu można używać różnych funkcji do wykonania różnych działań.
function greetMorning() {
console.log('Good morning!');
}
function greetEvening() {
console.log('Good evening!');
}
function greet(greetingFunction) {
greetingFunction();
}
greet(greetMorning); // Wyświetli: Good morning!
greet(greetEvening); // Wyświetli: Good evening!
10.5 Polimorfizm przez przeciążenie metody (Symulacja)
JavaScript nie obsługuje bezpośredniego przeciążenia metod, jak niektóre inne języki programowania. Jednak można zasymulować przeciążenie metod za pomocą argumentów funkcji i ich typów.
Przykład 4: Symulacja przeciążenia metody
W tym przykładzie metoda add przyjmuje dwa argumenty i wykonuje różne działania w zależności od ich typów. Jeśli argumenty to liczby, metoda je dodaje. Jeśli argumenty to tablice, metoda je scala.
class Calculator {
add(a, b) {
if (typeof a === 'number' && typeof b === 'number') {
return a + b;
} else if (Array.isArray(a) && Array.isArray(b)) {
return a.concat(b);
} else {
throw new Error('Invalid arguments');
}
}
}
const calc = new Calculator();
console.log(calc.add(1, 2)); // Wyświetli: 3
console.log(calc.add([1, 2], [3, 4])); // Wyświetli: [1, 2, 3, 4]
GO TO FULL VERSION