ฉันอยากรู้ว่าผู้ชายกับเด็กมีอะไรเหมือนกันและแตกต่างกันอย่างไร
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
เพื่อหากำไรจากมรดก (ดูวิกิพีเดีย ) การอ้างอิงเล็ก ๆ :
... การสืบทอดในภาษาเชิงวัตถุที่อิงคลาสส่วนใหญ่เป็นกลไกที่อ็อบเจ็กต์หนึ่งได้รับคุณสมบัติและพฤติกรรมทั้งหมดของอ็อบเจ็กต์พาเรนต์ การสืบทอดช่วยให้โปรแกรมเมอร์สามารถ: สร้างคลาสที่สร้างขึ้นจากคลาสที่มีอยู่ ...
implements
จะมีมากขึ้นสำหรับความหลากหลาย (ดูวิกิพีเดีย ) การอ้างอิงเล็ก ๆ :
... ความหลากหลายคือการจัดเตรียมอินเทอร์เฟซเดียวสำหรับเอนทิตีประเภทต่างๆ ...
ดังนั้นเราสามารถมีแผนผังการสืบทอดที่แตกต่างกันclass Man
ไป
class Man extends Human ...
แต่ถ้าเราประกาศด้วยว่าเราสามารถแสร้งทำเป็นประเภทอื่นได้ - Person
:
class Man extends Human
implements Person ...
.. แล้วเราสามารถใช้งานได้ทุกที่ที่Person
จำเป็น เราก็ต้องตอบสนองคนของ(เช่นใช้สิ่งที่ประชาชนทุกคน)"interface"
implement
ชั้นอื่น ๆ ? นั่นคือสิ่งที่เจ๋งจริงๆใบหน้าที่สวยงามของ Javascript (ประโยชน์อย่างหนึ่ง)คือการรองรับการพิมพ์ Duck ในตัว ( ดูวิกิพีเดีย ) การอ้างอิงเล็ก ๆ :
“ ถ้ามันเดินเหมือนเป็ดและมันไม่เหมือนเป็ดมันก็ต้องเป็นเป็ด”
ดังนั้นใน 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
มีชื่อทรัพย์สินหรือไม่
ใน typescript (และภาษา OO อื่น ๆ ) คุณมีคลาสและอินเทอร์เฟซ
อินเทอร์เฟซไม่มีการใช้งาน แต่เป็นเพียง "สัญญา" ของสิ่งที่สมาชิก / วิธีการประเภทนี้มี
ตัวอย่างเช่น:
interface Point {
x: number;
y: number;
distance(other: Point): number;
}
อินสแตนซ์ที่ใช้Point
อินเทอร์เฟซนี้ต้องมีสมาชิกของ type number สองตัว: 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 {}
มีข้อผิดพลาดในการคอมไพล์แจ้งว่า:
คลาส 'ชาย' ใช้อินเทอร์เฟซ 'บุคคล' ไม่ถูกต้อง
ไม่มี "ชื่อ" คุณสมบัติในประเภท "ชาย"
และนั่นเป็นเพราะอินเทอร์เฟซขาดการใช้งาน
ดังนั้นหากคุณ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 ในขณะที่คลาส man ต้องใช้ทุกอย่างจาก Person เอง
หากเราจะลบบางสิ่งออกจากคลาส man ตัวอย่างเช่นวิธีการเดินเราจะได้รับข้อผิดพลาดเวลาคอมไพล์ดังต่อไปนี้:
คลาส 'man' ใช้คลาส 'Person' อย่างไม่ถูกต้อง คุณต้องการขยาย 'บุคคล' และสืบทอดสมาชิกเป็นคลาสย่อยหรือไม่? คุณสมบัติ 'walk' หายไปในประเภท 'man' แต่จำเป็นต้องใช้ในประเภท 'Person' (2720)