摘要:概述和對比接口和類在實際使用中,一般都是配合使用的。接口是一個對外的協商約定。我們先實現一個交通工具的抽象類,然后繼承實現輪船類。我們可以發現抽象類已經實現的方法,子類是無需重復實現的。
概述和對比
接口和類在實際使用中,一般都是配合使用的。我們來對比一下:
接口可以聲明一個類的結構,包含屬性和方法,但它只是給出一個聲明,沒有訪問修飾符,沒有具體的方法實現,沒有構造函數,也不可以被實例化。
接口是一個對外的協商、約定。繼承后才可以實例化,繼承的時候必須實現聲明。可以多重繼承。
類是也是聲明一個類的結構,包含屬性和方法,有訪問修飾符,有具體的方法實現,有構造函數,可以實例化(抽象類下面說)。繼承的時候,可以覆蓋,也可以繼承使用父類實現。
抽象類也是類,不過它可以包含接口類似的特性:普通方法包含實現,抽象方法是不包含實現的;抽象類不能實例化。繼承后才可以實例化,繼承的時候必須實現抽象聲明,其他聲明和普通類一樣。
補充說明一下,這里的接口、類與純正的面向對象語言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的代碼還是有冗余的。這里我們就可以通過抽象類來做一些優化。
我們先實現一個交通工具的抽象類,然后繼承實現輪船類。我們可以發現抽象類已經實現的方法,子類是無需重復實現的。只有抽象出來的必須子類實現的才需要實現。
// 交通工具 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.`); } }
到此介紹完了接口和類的基本使用場景,再次體會一下關鍵字:抽象、繼承。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/110300.html
摘要:使用場景數據類型聲明和約束聲明數據類型使用數據類型面向對象編程這里和面向對象語言類似,用于定義對象接口,聲明對象的結構,定義類時可以實現接口,滿足這個接口定義的功能。 什么是接口 TypeScript的核心就是類型檢查,接口就是用于聲明類型,給內部或第三方使用者提供類型聲明和約束。 使用場景 數據類型聲明和約束 // 聲明數據類型 interface CustomerInfo { ...
摘要:靜態屬性靜態方法目前支持靜態方法表示,類屬性及靜態屬性目前作為提案還未正式成為標準。在中,抽象類不能用來實例化對象,主要做為其它派生類的基類使用。不同于接口,抽象類可以包含成員的實現細節。中也是這樣規定的抽象類不允許直接被實例化。 嘗試重寫 在此之前,通過《JavaScript => TypeScript 入門》已經掌握了類型聲明的寫法。原以為憑著那一條無往不利的規則,就可以開開心心的...
摘要:值得注意的是,的返回值復寫了原始的構造函數,原因是類裝飾器必須返回一個構造器函數。原始構造函數的原型被復制給的原型,以確保在創建一個的新實例時,操作符如愿以償,具體原因可參考鄙人另一篇文章原型與對象。 上一篇文章中,我們討論了TypeScript源碼中關于方法裝飾器的實現,搞明白了如下幾個問題: 裝飾器函數是如何被調用的? 裝飾器函數參數是如何傳入的? __decorate函數干了...
摘要:前言是面對對象的語言,因此有必要單獨紀錄下對象的各種定義和理解。面對對象基本概述概述是基于面向過程的變成思想,是對面向過程的一種封裝。面對對象開發就是不斷的創建對象,使用對象,指揮對象做事情。面對對象設計其實就是在管理和維護對象之間的關系。 前言 java是面對對象的語言,因此有必要單獨紀錄下對象的各種定義和理解。 面對對象,主要包括:面向對象思想,類與對象及其使用,對象的內存圖,成...
摘要:本文從裝飾模式出發,聊聊中的裝飾器和注解。該函數的函數名。不提供元數據的支持。中的元數據操作可以通過包來實現對于元數據的操作。 ??隨著Typescript的普及,在KOA2和nestjs等nodejs框架中經常看到類似于java spring中注解的寫法。本文從裝飾模式出發,聊聊Typescipt中的裝飾器和注解。 什么是裝飾者模式 Typescript中的裝飾器 Typescr...
閱讀 2680·2021-11-18 10:02
閱讀 3412·2021-09-28 09:35
閱讀 2593·2021-09-22 15:12
閱讀 750·2021-09-22 15:08
閱讀 3100·2021-09-07 09:58
閱讀 3472·2021-08-23 09:42
閱讀 733·2019-08-30 12:53
閱讀 2083·2019-08-29 13:51