Tôi muốn biết người đàn ông và đứa trẻ có điểm gì chung và chúng khác nhau như thế nào.
class Person {
name: string;
age: number;
}
class child extends Person {}
class man implements Person {}
Tôi muốn biết người đàn ông và đứa trẻ có điểm gì chung và chúng khác nhau như thế nào.
class Person {
name: string;
age: number;
}
class child extends Person {}
class man implements Person {}
Câu trả lời:
extends
có nghĩa:Lớp mới là trẻ em . Nó nhận được lợi ích đi kèm với thừa kế. Nó có tất cả các thuộc tính, phương thức làm cha mẹ của nó. Nó có thể ghi đè một số trong số này và triển khai mới, nhưng nội dung chính đã được bao gồm.
implements
có nghĩa:Lớp mới có thể được coi là "hình dạng" giống nhau , trong khi nó không phải là lớp con . Nó có thể được chuyển đến bất kỳ phương thức nào mà Person
yêu cầu, bất kể có cha mẹ khác vớiPerson
Trong OOP (các ngôn ngữ như C #, Java), chúng tôi sẽ sử dụng
extends
thu lợi nhuận từ thừa kế (xem wiki ). Trích dẫn nhỏ:
... Kế thừa trong hầu hết các ngôn ngữ hướng đối tượng dựa trên lớp là một cơ chế trong đó một đối tượng có được tất cả các thuộc tính và hành vi của đối tượng mẹ. Tính kế thừa cho phép lập trình viên: tạo các lớp được xây dựng dựa trên các lớp hiện có ...
implements
sẽ nhiều hơn cho tính đa hình (xem wiki ). Trích dẫn nhỏ:
... đa hình là việc cung cấp một giao diện duy nhất cho các thực thể thuộc các loại khác nhau ...
Vì vậy, chúng ta có thể có cây thừa kế thực sự khác nhau của chúng ta class Man
.
class Man extends Human ...
nhưng nếu chúng tôi cũng tuyên bố rằng chúng tôi có thể giả vờ là một kiểu khác - Person
:
class Man extends Human
implements Person ...
.. thì chúng ta có thể sử dụng nó ở bất cứ đâu, nơi Person
được yêu cầu. Chúng ta chỉ cần thực hiện các Nhân viên "interface"
(tức là triển khai tất cả các công cụ của nó) .
implement
lớp khác? Đó là thứ thực sự thú vịMặt đẹp của Javascript (một trong những lợi ích) là sự hỗ trợ tích hợp của kiểu gõ Duck ( xem wiki ). Trích dẫn nhỏ:
"Nếu nó đi như một con vịt và nó lang thang như một con vịt, thì nó phải là một con vịt."
Vì vậy, trong Javascript, nếu hai đối tượng khác nhau ... sẽ có một phương thức tương tự (ví dụ render()
), chúng có thể được chuyển đến một hàm mong đợi nó:
function(engine){
engine.render() // any type implementing render() can be passed
}
Để không làm mất điều đó - chúng ta cũng có thể làm như vậy trong Typescript - với nhiều hỗ trợ đánh máy hơn. Và đó là nơi
class implements class
có vai trò của nó, nơi nó có ý nghĩa
Trong các ngôn ngữ OOP như C#
... không có cách nào để làm điều đó ...
Các lớp mở rộng giao diện
Khi một kiểu giao diện mở rộng một kiểu lớp, nó kế thừa các thành viên của lớp nhưng không kế thừa các phần triển khai của chúng. Nó giống như thể giao diện đã khai báo tất cả các thành viên của lớp mà không cung cấp triển khai. Các giao diện kế thừa ngay cả các thành viên riêng tư và được bảo vệ của một lớp cơ sở. Điều này có nghĩa là khi bạn tạo một giao diện mở rộng một lớp với các thành viên riêng tư hoặc được bảo vệ, kiểu giao diện đó chỉ có thể được thực hiện bởi lớp đó hoặc một lớp con của nó.
Điều này hữu ích khi bạn có hệ thống phân cấp kế thừa lớn, nhưng muốn chỉ định rằng mã của bạn chỉ hoạt động với các lớp con có các thuộc tính nhất định. Các lớp con không cần phải liên quan ngoài việc kế thừa từ lớp cơ sở. Ví dụ:
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 { }
Vì vậy, trong khi
extends
có nghĩa là - nó nhận tất cả từ cha mẹ của nóimplements
trong trường hợp này gần giống như thực hiện một giao diện. Đối tượng con có thể giả vờ rằng nó là cha mẹ ... nhưng nó không nhận được bất kỳ triển khai nàoextends
-it get all from your parent", nó có áp dụng cho các thành viên riêng tư không? Ví dụ, class Person {private name: string} class man extends Person{gender: string;}
không man
có tên tài sản?
Trong bảng chữ (và một số ngôn ngữ OO khác), bạn có các lớp và giao diện.
Một giao diện không có triển khai, nó chỉ là một "hợp đồng" của những thành viên / phương thức mà loại này có.
Ví dụ:
interface Point {
x: number;
y: number;
distance(other: Point): number;
}
Các cá thể triển khai Point
giao diện này phải có hai thành viên kiểu số: x
và y
, và một phương thức distance
nhận một Point
cá thể khác và trả về a number
.
Giao diện không triển khai bất kỳ cái nào trong số đó.
Các lớp là triển khai:
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));
}
}
Trong ví dụ của bạn, bạn coi Person
lớp của mình một lần như một lớp khi bạn mở rộng nó và một lần như một giao diện khi bạn triển khai nó.
Ma cua ban:
class Person {
name: string;
age: number;
}
class Child extends Person {}
class Man implements Person {}
Có lỗi biên dịch cho biết:
Class 'Man' triển khai sai giao diện 'Person'.
Loại "Tên" thuộc tính bị thiếu trong loại "Người đàn ông".
Và đó là bởi vì các giao diện thiếu sự triển khai.
Vì vậy, nếu bạn implement
là một lớp thì bạn chỉ lấy "hợp đồng" của nó mà không cần triển khai, vì vậy bạn sẽ cần phải làm điều này:
class NoErrorMan implements Person {
name: string;
age: number;
}
Điểm mấu chốt là trong hầu hết các trường hợp, bạn muốn extend
học một lớp khác chứ không phải lớp implement
đó.
Câu trả lời tuyệt vời từ @ nitzan-tomer! Đã giúp tôi rất nhiều ... Tôi đã mở rộng bản demo của anh ấy một chút với:
IPoint interface;
Point implements IPoint;
Point3D extends Point;
Và cách chúng hoạt động trong các hàm mong đợi một IPoint
kiểu.
Vì vậy, những gì tôi đã học được cho đến nay và đang sử dụng như một quy tắc ngón tay cái: Nếu bạn đang sử dụng các lớp và phương thức mong đợi các kiểu chung, hãy sử dụng các giao diện làm các kiểu mong đợi. Và đảm bảo rằng lớp cha hoặc lớp cơ sở sử dụng giao diện đó. Bằng cách đó, bạn có thể sử dụng tất cả các lớp con trong những lớp đó trong chừng mực chúng triển khai giao diện.
Đây là bản demo mở rộng
extends
tập trung vào kế thừa và implements
tập trung vào ràng buộc cho dù giao diện hoặc lớp.
extends
: Lớp con (được mở rộng) sẽ kế thừa tất cả các thuộc tính và phương thức của lớp được mở rộngimplements
: Lớp sử dụng implements
từ khóa sẽ cần triển khai tất cả các thuộc tính và phương thức của lớp mà nóimplements
Nói một cách đơn giản hơn:
extends
: Ở đây bạn nhận được tất cả các phương thức / thuộc tính này từ lớp cha, do đó bạn không cần phải tự mình triển khaiimplements
: Đây là một hợp đồng mà lớp phải tuân theo. Lớp phải triển khai ít nhất các phương thức / thuộc tính sauclass 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)
Trong ví dụ, chúng ta có thể thấy rằng lớp con kế thừa mọi thứ từ Person trong khi lớp man phải thực thi mọi thứ từ chính Person.
Nếu chúng ta xóa một cái gì đó khỏi lớp người đàn ông, chẳng hạn như phương thức walk, chúng ta sẽ gặp lỗi thời gian biên dịch sau :
Class 'man' triển khai sai class 'Person'. Ý của bạn là mở rộng 'Person' và kế thừa các thành viên của nó như một lớp con? Thuộc tính "walk" bị thiếu trong loại "man" nhưng được yêu cầu trong loại "Person". (2720)