TypeScript學習5-接口與類的應用

概述和對比

接口和類在實際使用中,通常都是配合使用的。咱們來對比一下: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.`);
  }
}

到此介紹完了接口和類的基本使用場景,再次體會一下關鍵字:抽象、繼承對象

相關文章
相關標籤/搜索