接口和類在實際使用中,通常都是配合使用的。咱們來對比一下:javascript
補充說明一下,這裏的接口、類與純正的面嚮對象語言Java比,有一些不一樣的地方,有興趣的能夠自行了解。
這裏將給一個稍微複雜一點的例子:旅行社運送旅客。java
這裏咱們定義了幾類接口:旅客、載客、位置、運送,目的就是聲明規範,實現了這些接口的類就能夠被用來作這些事情。函數
// 旅客 interface Passgener { name: string; } // 載客 interface Carriable { passengers: Passgener[]; getUp (...passengers: Passgener[]): number; getOff (): number; } // 位置 interface Positioned { x: number; y: number; } // 常量:初始位置 const positionOrigin: Positioned = { x: 0, y: 0 }; // 運送 interface Moveable { position: Positioned; moveTo(Positioned: Positioned): Positioned; }
這裏我實現了兩個類:小汽車、巴士,這兩個類均實現了載客、運送接口,也就是說明它們是擁有這些能力的。工具
// 小汽車 class Car implements Carriable, Moveable { passengers: Passgener[]; position: Positioned; capacity: number; constructor(capacity: number) { this.passengers = []; this.position = positionOrigin; this.capacity = capacity; } getUp (...passengers: Passgener[]): number { if (passengers.length > this.capacity) { throw new Error(`This car can carry ${this.capacity} passengers!`); } console.log( `This car carries ${passengers.map(item => item.name).join(',')}` ); return this.passengers.push(...passengers); } getOff (): number { return this.passengers.splice(0).length; } moveTo(position: Positioned): Positioned { Object.assign(this.position, position); console.log( `This car carries ${this.passengers.map(item => item.name).join(',')} to [${ this.position.x }, ${this.position.y}]` ); return this.position; } } // 巴士 class Bus implements Carriable, Moveable { passengers: Passgener[]; position: Positioned; capacity: number; constructor(capacity: number) { this.passengers = []; this.position = positionOrigin; this.capacity = capacity; } getUp (...passengers: Passgener[]): number { if (passengers.length > this.capacity) { throw new Error(`This Bus can carry ${this.capacity} passengers!`); } console.log( `This Bus carries ${passengers.map(item => item.name).join(',')}` ); return this.passengers.push(...passengers); } getOff (): number { return this.passengers.splice(0).length; } moveTo(position: Positioned): Positioned { Object.assign(this.position, position); console.log( `This Bus carries ${this.passengers.map(item => item.name).join(',')} to [${ this.position.x }, ${this.position.y}]` ); return this.position; } }
具體類定義出來了,咱們就能夠實現功能,咱們定義一個旅行社,由旅行社來運送旅客。優化
// 旅行社 class TravelAgency { name: string; constructor(name: string) { this.name = name; } carrying (carrier: Carriable & Moveable, position: Positioned, ...passengers: Passgener[]): Positioned { carrier.getUp(...passengers); return carrier.moveTo(position); } } // 實例化對象 let t1 = new TravelAgency("t1"); let c1 = new Car(4); let b1 = new Bus(30); // 實現功能 t1.carrying(c1, {x: 10, y: 60}, {name: 'Jack'}, {name: 'Tom'}); t1.carrying(b1, {x: 10, y: 60}, {name: 'Jack'}, {name: 'Tom'}, {name: 'Mary'}, {name: 'Joe'});
上面已經把完整的功能實現出來了,可是咱們能夠看到,Car和Bus的代碼仍是有冗餘的。這裏咱們就能夠經過抽象類來作一些優化。this
咱們先實現一個交通工具的抽象類,而後繼承實現輪船類。咱們能夠發現抽象類已經實現的方法,子類是無需重複實現的。只有抽象出來的必須子類實現的才須要實現。code
// 交通工具 abstract class Vehicle implements Carriable, Moveable { name: string; passengers: Passgener[]; position: Positioned; capacity: number; // 抽象方法 abstract run(speed: number): void; getUp (...passengers: Passgener[]): number { if (passengers.length > this.capacity) { throw new Error(`This ${this.name} can carry ${this.capacity} passengers!`); } console.log( `This ${this.name} carries ${passengers.map(item => item.name).join(',')}` ); return this.passengers.push(...passengers); } getOff (): number { return this.passengers.splice(0).length; } moveTo(position: Positioned): Positioned { Object.assign(this.position, position); console.log( `This ${this.name} carries ${this.passengers.map(item => item.name).join(',')} to [${ this.position.x }, ${this.position.y}]` ); return this.position; } } // 輪船 class Ship extends Vehicle { constructor(capacity: number) { super(); this.passengers = []; this.position = positionOrigin; this.capacity = capacity; } // 抽象方法必須實現 run(speed: number) { // todo, run as a ship... console.log(`This ${this.name} running at ${speed}km/h.`); } }
到此介紹完了接口和類的基本使用場景,再次體會一下關鍵字:抽象、繼承。對象