Я хотів би знати, що спільного між чоловіком і дитиною і чим вони відрізняються.
class Person {
name: string;
age: number;
}
class child extends Person {}
class man implements Person {}
Я хотів би знати, що спільного між чоловіком і дитиною і чим вони відрізняються.
class Person {
name: string;
age: number;
}
class child extends Person {}
class man implements Person {}
Відповіді:
extends
засоби:Новий клас є дитиною . Він отримує вигоди, що надходять із спадщиною. Він має всі властивості, методи як його батьківський. Він може змінити деякі з них і реалізувати нові, але материнські речі вже включені.
implements
засоби:До нового класу можна ставитися як до тієї ж «форми» , поки це не дитина . Він може бути переданий до будь-якого методу, де Person
необхідний, незалежно від того, чи є інший батьківський, ніжPerson
У OOP (такі мови, як C #, Java) ми б використовували
extends
отримати прибуток від спадщини (див. wiki ). Маленький цитат:
... Спадкування в більшості класових об'єктно-орієнтованих мов - це механізм, за допомогою якого один об'єкт набуває всіх властивостей і поведінки батьківського об'єкта. Спадщина дозволяє програмістам: створювати класи, побудовані на існуючих класах ...
implements
буде більше для поліморфізму (див. wiki ). Маленький цитат:
... поліморфізм - це надання єдиного інтерфейсу суб'єктам різних типів ...
Отже, у нас може бути справді інше дерево спадкування class Man
.
class Man extends Human ...
але якщо ми також заявляємо, що можемо претендувати на різний тип - Person
:
class Man extends Human
implements Person ...
.. тоді ми можемо використовувати його де завгодно, де Person
потрібно. Ми просто повинні виконати персони "interface"
(тобто реалізувати всі її публічні речі) .
implement
інший клас? Це справді класні речіГарне обличчя Javascript (одна з переваг) - це вбудована підтримка введення качки ( див. Вікі ). Маленький цитат:
"Якщо вона ходить, як качка, і хитається, як качка, то це повинна бути качка".
Отже, у Javascript, якщо два різних об'єкти ... будуть мати один подібний метод (наприклад render()
), вони можуть бути передані функції, яка очікує цього:
function(engine){
engine.render() // any type implementing render() can be passed
}
Щоб цього не втратити - ми можемо зробити і в Typescript те саме - з більш набраною підтримкою. І ось де
class implements class
має свою роль, де це має сенс
У мовах OOP як C#
... немає ніякого способу зробити це ...
Розширення класів інтерфейсів
Коли тип інтерфейсу розширює тип класу, він успадковує членів класу, але не їх реалізацію. Наче інтерфейс оголосив усіх членів класу, не надаючи реалізації. Інтерфейси успадковують навіть приватні та захищені члени базового класу. Це означає, що коли ви створюєте інтерфейс, який розширює клас із приватними або захищеними членами, цей тип інтерфейсу може бути реалізований лише тим класом або його підкласом.
Це корисно, коли у вас є велика ієрархія спадкування, але ви хочете вказати, що ваш код працює лише з підкласами, які мають певні властивості. Підкласи не повинні бути пов’язані, крім успадкування від базового класу. Наприклад:
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 { }
Отже, поки
extends
означає - отримує все від свого батькаimplements
у цьому випадку майже як реалізація інтерфейсу. Дочірній об’єкт може зробити вигляд, що він є батьківським ... але він не отримує жодної реалізаціїextends
отримує все від батьків", це стосується приватних членів? Наприклад, class Person {private name: string} class man extends Person{gender: string;}
чи man
є ім'я властивості?
У машинописі (та деяких інших мовах ОО) у вас є класи та інтерфейси.
Інтерфейс не має реалізації, це просто "договір" про те, які члени / метод має цей тип.
Наприклад:
interface Point {
x: number;
y: number;
distance(other: Point): number;
}
Примірники, які реалізують цей Point
інтерфейс, повинні мати два члени типу типу: x
і y
та один метод, distance
який отримує інший Point
екземпляр і повертає a number
.
Інтерфейс не реалізує жодного з них.
Класи є реалізаціями:
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));
}
}
( код на ігровому майданчику )
У своєму прикладі ви ставитесь до свого Person
класу один раз як до класу, коли ви розширюєте його, і один раз як інтерфейс, коли ви його реалізуєте.
Ваш код:
class Person {
name: string;
age: number;
}
class Child extends Person {}
class Man implements Person {}
Помилка компіляції:
Клас 'Man' неправильно реалізує інтерфейс 'Person'.
Властивості 'name' відсутнє в типі 'Man'.
І це тому, що в інтерфейсах бракує реалізації.
Тож якщо ви implement
клас, то ви приймаєте лише його "контракт" без реалізації, тому вам потрібно буде це зробити:
class NoErrorMan implements Person {
name: string;
age: number;
}
( код на ігровому майданчику )
Підсумок полягає в тому, що в більшості випадків ви хочете до extend
іншого класу, а не до implement
нього.
Чудовий відповідь від @ nitzan-tomer! Мені дуже допомогли ... Я трохи продовжив його демонстрацію за допомогою:
IPoint interface;
Point implements IPoint;
Point3D extends Point;
І як вони поводяться у функціях, що очікують IPoint
типу.
Тож, про що я дізнався до цих пір, і я використовую як правило: якщо ви використовуєте класи та методи, що очікують загальні типи, використовуйте інтерфейси як очікувані типи. І переконайтеся, що батьківський чи базовий клас використовує цей інтерфейс. Таким чином, ви можете використовувати всі підкласи в тих, наскільки вони реалізують інтерфейс.
extends
зосередити увагу на успадкуванні та implements
зосередитись на обмеженні, будь то інтерфейси чи класи.
extends
: Дочірній клас (який розширено) успадкує всі властивості та методи класу є розширенняimplements
: Клас, який використовує implements
ключове слово, повинен реалізувати всі властивості та методи класу, яким він єimplements
Простіше кажучи:
extends
: Тут ви отримуєте всі ці методи / властивості від батьківського класу, тому вам не доведеться реалізовувати це самостійноimplements
: Ось контракт, якого повинен дотримуватися клас. Клас повинен реалізувати принаймні такі методи / властивостіclass 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)
На прикладі ми можемо спостерігати, що дочірній клас успадковує все від Person, тоді як клас людини повинен реалізовувати все від Person.
Якби ми видаляли щось із класу man, наприклад метод walk, ми отримали б таку помилку часу компіляції :
Клас 'man' неправильно реалізує клас 'Person'. Ви мали намір поширити "Особу" та успадкувати її членів як підклас? Властивість "прогулянка" відсутня в типі "людина", але вимагається в типі "людина" (2720)