Chciałbym wiedzieć, co łączy mężczyznę i dziecko i czym się różnią.
class Person {
name: string;
age: number;
}
class child extends Person {}
class man implements Person {}
Chciałbym wiedzieć, co łączy mężczyznę i dziecko i czym się różnią.
class Person {
name: string;
age: number;
}
class child extends Person {}
class man implements Person {}
Odpowiedzi:
extends
znaczy:Nowa klasa jest dzieckiem . Otrzymuje korzyści wynikające z dziedziczenia. Ma wszystkie właściwości, metody jako jego rodzic. Może zastąpić niektóre z nich i zaimplementować nowe, ale elementy nadrzędne są już uwzględnione.
implements
znaczy:Nowej klasy mogą być traktowane jako ten sam „kształtu” , a to nie jest dziecko . Można go przekazać do dowolnej metody, w której Person
jest wymagana, niezależnie od tego, czy ma innego rodzica niżPerson
W OOP (języki takie jak C #, Java) używalibyśmy
extends
czerpać korzyści z dziedziczenia (patrz wiki ). Mały cytat:
... Dziedziczenie w większości języków obiektowych opartych na klasach jest mechanizmem, w którym jeden obiekt przejmuje wszystkie właściwości i zachowania obiektu nadrzędnego. Dziedziczenie umożliwia programistom: tworzenie klas, które są zbudowane na podstawie istniejących klas ...
implements
będzie bardziej dla polimorfizmu (patrz wiki ). Mały cytat:
... polimorfizm to zapewnienie jednego interfejsu dla bytów różnych typów ...
Więc możemy mieć naprawdę inne drzewo dziedziczenia class Man
.
class Man extends Human ...
ale jeśli również zadeklarujemy, że możemy udawać innego typu - Person
:
class Man extends Human
implements Person ...
.. wtedy możemy go używać wszędzie tam, gdzie Person
jest to wymagane. Musimy tylko spełnić Persons "interface"
(tj. Wdrożyć wszystkie jej publiczne rzeczy) .
implement
inna klasa? To naprawdę fajna rzeczMiła twarz Javascript (jedną z zalet) to wbudowana obsługa pisania typu Duck ( zobacz wiki ). Mały cytat:
„Jeśli chodzi jak kaczka i kwacze jak kaczka, to musi to być kaczka”.
Tak więc, w Javascript, jeśli dwa różne obiekty ... miałyby jedną podobną metodę (np. render()
) , Można je przekazać do funkcji, która tego oczekuje:
function(engine){
engine.render() // any type implementing render() can be passed
}
Aby tego nie stracić - możemy zrobić to samo w Typescript - z większą obsługą pisania. I to jest gdzie
class implements class
ma swoją rolę tam, gdzie ma to sens
W językach OOP jako C#
... nie da się tego zrobić ...
Interfejsy rozszerzające klasy
Gdy typ interfejsu rozszerza typ klasy, dziedziczy elementy członkowskie klasy, ale nie ich implementacje. To tak, jakby interfejs zadeklarował wszystkie elementy członkowskie klasy bez dostarczania implementacji. Interfejsy dziedziczą nawet prywatne i chronione elementy członkowskie klasy bazowej. Oznacza to, że kiedy tworzysz interfejs, który rozszerza klasę o prywatne lub chronione elementy członkowskie, ten typ interfejsu może być implementowany tylko przez tę klasę lub jej podklasę.
Jest to przydatne, gdy masz dużą hierarchię dziedziczenia, ale chcesz określić, że kod działa tylko z podklasami, które mają określone właściwości. Podklasy nie muszą być powiązane poza dziedziczeniem po klasie bazowej. Na przykład:
class Control { private state: any; } interface SelectableControl extends Control { select(): void; } class Button extends Control implements SelectableControl { select() { } } class TextBox extends Control { select() { } } // Error: Property 'state' is missing in type 'Image'. class Image implements SelectableControl { private state: any; select() { } } class Location { }
Więc gdy
extends
oznacza - dostaje wszystko od swojego rodzicaimplements
w tym przypadku jest to prawie jak implementacja interfejsu. Obiekt potomny może udawać, że jest rodzicem ... ale nie otrzymuje żadnej implementacjiextends
-dostaje wszystko od swojego rodzica”, czy dotyczy to prywatnych członków? Na przykład class Person {private name: string} class man extends Person{gender: string;}
czy man
ma nazwę nieruchomości?
W maszynopisie (i niektórych innych językach obiektowych) masz klasy i interfejsy.
Interfejs nie ma implementacji, jest po prostu „kontraktem” elementów członkowskich / metody tego typu.
Na przykład:
interface Point {
x: number;
y: number;
distance(other: Point): number;
}
Instancje, które implementują ten Point
interfejs, muszą mieć dwa elementy członkowskie typu numer: x
i y
oraz jedną metodę, distance
która odbiera inne Point
wystąpienie i zwraca plik number
.
Interfejs nie implementuje żadnego z nich.
Zajęcia to implementacje:
class PointImplementation implements Point {
public x: number;
public y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
public distance(other: Point): number {
return Math.sqrt(Math.pow(this.x - other.x, 2) + Math.pow(this.y - other.y, 2));
}
}
W twoim przykładzie traktujesz swoją Person
klasę raz jako klasę, kiedy ją rozszerzasz, a raz jako interfejs, kiedy ją implementujesz.
Twój kod:
class Person {
name: string;
age: number;
}
class Child extends Person {}
class Man implements Person {}
Występuje błąd kompilacji mówiący:
Klasa „Man” nieprawidłowo implementuje interfejs „Person”.
Brak „nazwy” właściwości w typie „Man”.
A to dlatego, że interfejsy nie są implementowane.
Więc jeśli jesteś implement
klasą, bierzesz tylko jej „kontrakt” bez implementacji, więc musisz zrobić to:
class NoErrorMan implements Person {
name: string;
age: number;
}
Najważniejsze jest to, że w większości przypadków chcesz iść do extend
innej klasy, a nie do implement
niej.
Świetna odpowiedź od @ nitzan-tomer! Bardzo mi pomogło ... Rozszerzyłem nieco jego demo o:
IPoint interface;
Point implements IPoint;
Point3D extends Point;
I jak zachowują się w funkcjach oczekujących IPoint
typu.
Więc czego się do tej pory nauczyłem i używam jako reguły kciuka: jeśli używasz klas i metod oczekujących typów ogólnych, używaj interfejsów jako oczekiwanych typów. I upewnij się, że klasa nadrzędna lub klasa bazowa używa tego interfejsu. W ten sposób możesz użyć wszystkich podklas w tych, o ile implementują interfejs.
Tutaj rozszerzone demo
extends
skoncentruj się na dziedziczeniu i implements
skup się na ograniczeniach, czy to interfejsach, czy klasach.
extends
: Klasa potomna (która jest rozszerzona) odziedziczy wszystkie właściwości i metody klasy jest extendsimplements
: Klasa, która używa implements
słowa kluczowego, będzie musiała zaimplementować wszystkie właściwości i metody klasy, w której jest używaneimplements
Mówiąc prościej:
extends
: Tutaj otrzymujesz wszystkie te metody / właściwości z klasy nadrzędnej, więc nie musisz ich implementować samodzielnieimplements
: Oto kontrakt, którego klasa musi przestrzegać. Klasa musi implementować co najmniej następujące metody / właściwościclass Person {
name: string;
age: number;
walk(): void {
console.log('Walking (person Class)')
}
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
class child extends Person { }
// Man has to implements at least all the properties
// and methods of the Person class
class man implements Person {
name: string;
age: number
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
walk(): void {
console.log('Walking (man class)')
}
}
(new child('Mike', 12)).walk();
// logs: Walking(person Class)
(new man('Tom', 12)).walk();
// logs: Walking(man class)
W tym przykładzie możemy zauważyć, że klasa potomna dziedziczy wszystko po Person, podczas gdy klasa man musi zaimplementować wszystko od samej Osoby.
Gdybyśmy usunęli coś z klasy man, na przykład metodę walk, otrzymalibyśmy następujący błąd czasu kompilacji :
Klasa „man” nieprawidłowo implementuje klasę „Person”. Czy chodziło Ci o rozszerzenie „Person” i dziedziczenie jego członków jako podklasy? Brakuje właściwości „spacer” w typie „mężczyzna”, ale jest ona wymagana w typie „Osoba”. (2720)