這篇文章主要講解了“有哪些常見的設(shè)計(jì)模式”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“有哪些常見的設(shè)計(jì)模式”吧!
在上猶等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站建設(shè) 網(wǎng)站設(shè)計(jì)制作按需求定制設(shè)計(jì),公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),營銷型網(wǎng)站建設(shè),成都外貿(mào)網(wǎng)站建設(shè)公司,上猶網(wǎng)站建設(shè)費(fèi)用合理。
一、建造者模式
建造者模式(Builder Pattern)將一個(gè)復(fù)雜對象分解成多個(gè)相對簡單的部分,然后根據(jù)不同需要分別創(chuàng)建它們,最后構(gòu)建成該復(fù)雜對象。
一輛小汽車 ? 通常由 發(fā)動機(jī)、底盤、車身和電氣設(shè)備 四大部分組成。汽車電氣設(shè)備的內(nèi)部構(gòu)造很復(fù)雜,簡單起見,我們只考慮三個(gè)部分:引擎、底盤和車身。
在現(xiàn)實(shí)生活中,小汽車也是由不同的零部件組裝而成,比如上圖中我們把小汽車分成引擎、底盤和車身三大部分。下面我們來看一下如何使用建造者模式來造車子。
1.1 實(shí)現(xiàn)代碼
class Car { constructor( public engine: string, public chassis: string, public body: string ) {} } class CarBuilder { engine!: string; // 引擎 chassis!: string; // 底盤 body!: string; // 車身 addChassis(chassis: string) { this.chassis = chassis; return this; } addEngine(engine: string) { this.engine = engine; return this; } addBody(body: string) { this.body = body; return this; } build() { return new Car(this.engine, this.chassis, this.body); } }
在以上代碼中,我們定義一個(gè) CarBuilder 類,并提供了 addChassis、addEngine和 addBody 3 個(gè)方法用于組裝車子的不同部位,當(dāng)車子的 3 個(gè)部分都組裝完成后,調(diào)用build 方法就可以開始造車。
1.2 使用示例
const car = new CarBuilder() .addEngine('v12') .addBody('鎂合金') .addChassis('復(fù)合材料') .build();
1.3 應(yīng)用場景及案例
需要生成的產(chǎn)品對象有復(fù)雜的內(nèi)部結(jié)構(gòu),這些產(chǎn)品對象通常包含多個(gè)成員屬性。
需要生成的產(chǎn)品對象的屬性相互依賴,需要指定其生成順序。
隔離復(fù)雜對象的創(chuàng)建和使用,并使得相同的創(chuàng)建過程可以創(chuàng)建不同的產(chǎn)品。
Github - node-sql-query:https://github.com/dresende/node-sql-query
二、工廠模式
在現(xiàn)實(shí)生活中,工廠是負(fù)責(zé)生產(chǎn)產(chǎn)品的,比如牛奶、面包或禮物等,這些產(chǎn)品滿足了我們?nèi)粘5纳硇枨蟆?/p>
在眾多設(shè)計(jì)模式當(dāng)中,有一種被稱為工廠模式的設(shè)計(jì)模式,它提供了創(chuàng)建對象的最佳方式。工廠模式可以分為:簡單工廠模式、工廠方法模式和抽象工廠模式。
2.1 簡單工廠
簡單工廠模式又叫 靜態(tài)方法模式,因?yàn)楣S類中定義了一個(gè)靜態(tài)方法用于創(chuàng)建對象。簡單工廠讓使用者不用知道具體的參數(shù)就可以創(chuàng)建出所需的 ”產(chǎn)品“ 類,即使用者可以直接消費(fèi)產(chǎn)品而不需要知道產(chǎn)品的具體生產(chǎn)細(xì)節(jié)。
在上圖中,阿寶哥模擬了用戶購車的流程,小王和小秦分別向 BMW 工廠訂購了 BMW730 和 BMW840 型號的車型,接著工廠會先判斷用戶選擇的車型,然后按照對應(yīng)的模型進(jìn)行生產(chǎn)并在生產(chǎn)完成后交付給用戶。
下面我們來看一下如何使用簡單工廠來描述 BMW 工廠生產(chǎn)指定型號車子的過程。
2.1.1 實(shí)現(xiàn)代碼
abstract class BMW { abstract run(): void; } class BMW730 extends BMW { run(): void { console.log("BMW730 發(fā)動咯"); } } class BMW840 extends BMW { run(): void { console.log("BMW840 發(fā)動咯"); } } class BMWFactory { public static produceBMW(model: "730" | "840"): BMW { if (model === "730") { return new BMW730(); } else { return new BMW840(); } } }
在以上代碼中,我們定義一個(gè) BMWFactory 類,該類提供了一個(gè)靜態(tài)的 produceBMW()方法,用于根據(jù)不同的模型參數(shù)來創(chuàng)建不同型號的車子。
2.1.2 使用示例
const bmw730 = BMWFactory.produceBMW("730"); const bmw840 = BMWFactory.produceBMW("840"); bmw730.run(); bmw840.run();
2.1.3 應(yīng)用場景
工廠類負(fù)責(zé)創(chuàng)建的對象比較少:由于創(chuàng)建的對象比較少,不會造成工廠方法中業(yè)務(wù)邏輯過于復(fù)雜。
客戶端只需知道傳入工廠類靜態(tài)方法的參數(shù),而不需要關(guān)心創(chuàng)建對象的細(xì)節(jié)。
2.2 工廠方法
工廠方法模式(Factory Method Pattern)又稱為工廠模式,也叫多態(tài)工廠(Polymorphic Factory)模式,它屬于類創(chuàng)建型模式。
在工廠方法模式中,工廠父類負(fù)責(zé)定義創(chuàng)建產(chǎn)品對象的公共接口,而工廠子類則負(fù)責(zé)生成具體的產(chǎn)品對象, 這樣做的目的是將產(chǎn)品類的實(shí)例化操作延遲到工廠子類中完成,即通過工廠子類來確定究竟應(yīng)該實(shí)例化哪一個(gè)具體產(chǎn)品類。
2.2.1 實(shí)現(xiàn)代碼
abstract class BMWFactory { abstract produceBMW(): BMW; } class BMW730Factory extends BMWFactory { produceBMW(): BMW { return new BMW730(); } } class BMW840Factory extends BMWFactory { produceBMW(): BMW { return new BMW840(); } }
在以上代碼中,我們分別創(chuàng)建了 BMW730Factory 和 BMW840Factory 兩個(gè)工廠類,然后使用這兩個(gè)類的實(shí)例來生產(chǎn)不同型號的車子。
2.2.2 使用示例
const bmw730Factory = new BMW730Factory(); const bmw840Factory = new BMW840Factory(); const bmw730 = bmw730Factory.produceBMW(); const bmw840 = bmw840Factory.produceBMW(); bmw730.run(); bmw840.run();
2.2.3 應(yīng)用場景
一個(gè)類不知道它所需要的對象的類:在工廠方法模式中,客戶端不需要知道具體產(chǎn)品類的類名,只需要知道所對應(yīng)的工廠即可,具體的產(chǎn)品對象由具體工廠類創(chuàng)建;客戶端需要知道創(chuàng)建具體產(chǎn)品的工廠類。
一個(gè)類通過其子類來指定創(chuàng)建哪個(gè)對象:在工廠方法模式中,對于抽象工廠類只需要提供一個(gè)創(chuàng)建產(chǎn)品的接口,而由其子類來確定具體要創(chuàng)建的對象,利用面向?qū)ο蟮亩鄳B(tài)性和里氏代換原則,在程序運(yùn)行時(shí),子類對象將覆蓋父類對象,從而使得系統(tǒng)更容易擴(kuò)展。
2.3 抽象工廠
抽象工廠模式(Abstract Factory Pattern),提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而無須指定它們具體的類。
在工廠方法模式中具體工廠負(fù)責(zé)生產(chǎn)具體的產(chǎn)品,每一個(gè)具體工廠對應(yīng)一種具體產(chǎn)品,工廠方法也具有唯一性,一般情況下,一個(gè)具體工廠中只有一個(gè)工廠方法或者一組重載的工廠方法。但是有時(shí)候我們需要一個(gè)工廠可以提供多個(gè)產(chǎn)品對象,而不是單一的產(chǎn)品對象。
2.3.1 實(shí)現(xiàn)代碼
abstract class BMWFactory { abstract produce730BMW(): BMW730; abstract produce840BMW(): BMW840; } class ConcreteBMWFactory extends BMWFactory { produce730BMW(): BMW730 { return new BMW730(); } produce840BMW(): BMW840 { return new BMW840(); } }
2.3.2 使用示例
const bmwFactory = new ConcreteBMWFactory(); const bmw730 = bmwFactory.produce730BMW(); const bmw840 = bmwFactory.produce840BMW(); bmw730.run(); bmw840.run();
2.3.3 應(yīng)用場景
一個(gè)系統(tǒng)不應(yīng)當(dāng)依賴于產(chǎn)品類實(shí)例如何被創(chuàng)建、組合和表達(dá)的細(xì)節(jié),這對于所有類型的工廠模式都是重要的。
系統(tǒng)中有多于一個(gè)的產(chǎn)品族,而每次只使用其中某一產(chǎn)品族。
系統(tǒng)提供一個(gè)產(chǎn)品類的庫,所有的產(chǎn)品以同樣的接口出現(xiàn),從而使客戶端不依賴于具體實(shí)現(xiàn)。
三、單例模式
單例模式(Singleton Pattern)是一種常用的模式,有一些對象我們往往只需要一個(gè),比如全局緩存、瀏覽器中的 window 對象等。單例模式用于保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。
在上圖中,阿寶哥模擬了借車的流程,小王臨時(shí)有急事找阿寶哥借車子,阿寶哥家的車子剛好沒用,就借給小王了。當(dāng)天,小秦也需要用車子,也找阿寶哥借車,因?yàn)榘毟缂依镏挥幸惠v車子,所以就沒有車可借了。
對于車子來說,它雖然給生活帶來了很大的便利,但養(yǎng)車也需要一筆不小的費(fèi)用(車位費(fèi)、油費(fèi)和保養(yǎng)費(fèi)等),所以阿寶哥家里只有一輛車子。
在開發(fā)軟件系統(tǒng)時(shí),如果遇到創(chuàng)建對象時(shí)耗時(shí)過多或耗資源過多,但又經(jīng)常用到的對象,我們就可以考慮使用單例模式。
下面我們來看一下如何使用 TypeScript 來實(shí)現(xiàn)單例模式。
3.1 實(shí)現(xiàn)代碼
class Singleton { // 定義私有的靜態(tài)屬性,來保存對象實(shí)例 private static singleton: Singleton; private constructor() {} // 提供一個(gè)靜態(tài)的方法來獲取對象實(shí)例 public static getInstance(): Singleton { if (!Singleton.singleton) { Singleton.singleton = new Singleton(); } return Singleton.singleton; } }
3.2 使用示例
let instance1 = Singleton.getInstance(); let instance2 = Singleton.getInstance(); console.log(instance1 === instance2); // true
3.3 應(yīng)用場景
需要頻繁實(shí)例化然后銷毀的對象。
創(chuàng)建對象時(shí)耗時(shí)過多或耗資源過多,但又經(jīng)常用到的對象。
系統(tǒng)只需要一個(gè)實(shí)例對象,如系統(tǒng)要求提供一個(gè)唯一的序列號生成器或資源管理器,或者需要考慮資源消耗太大而只允許創(chuàng)建一個(gè)對象。
四、適配器模式
在實(shí)際生活中,也存在適配器的使用場景,比如:港式插頭轉(zhuǎn)換器、電源適配器和 USB 轉(zhuǎn)接口。而在軟件工程中,適配器模式的作用是解決兩個(gè)軟件實(shí)體間的接口不兼容的問題。使用適配器模式之后,原本由于接口不兼容而不能工作的兩個(gè)軟件實(shí)體就可以一起工作。
4.1 實(shí)現(xiàn)代碼
interface Logger { info(message: string): Promise<void>; } interface CloudLogger { sendToServer(message: string, type: string): Promise<void>; } class AliLogger implements CloudLogger { public async sendToServer(message: string, type: string): Promise<void> { console.info(message); console.info('This Message was saved with AliLogger'); } } class CloudLoggerAdapter implements Logger { protected cloudLogger: CloudLogger; constructor (cloudLogger: CloudLogger) { this.cloudLogger = cloudLogger; } public async info(message: string): Promise<void> { await this.cloudLogger.sendToServer(message, 'info'); } } class NotificationService { protected logger: Logger; constructor (logger: Logger) { this.logger = logger; } public async send(message: string): Promise<void> { await this.logger.info(`Notification sended: ${message}`); } }
在以上代碼中,因?yàn)?Logger 和 CloudLogger 這兩個(gè)接口不匹配,所以我們引入了 CloudLoggerAdapter 適配器來解決兼容性問題。
4.2 使用示例
(async () => { const aliLogger = new AliLogger(); const cloudLoggerAdapter = new CloudLoggerAdapter(aliLogger); const notificationService = new NotificationService(cloudLoggerAdapter); await notificationService.send('Hello semlinker, To Cloud'); })();
4.3 應(yīng)用場景及案例
以前開發(fā)的系統(tǒng)存在滿足新系統(tǒng)功能需求的類,但其接口同新系統(tǒng)的接口不一致。
使用第三方提供的組件,但組件接口定義和自己要求的接口定義不同。
Github - axios-mock-adapter:https://github.com/ctimmerm/axios-mock-adapter
五、觀察者模式 & 發(fā)布訂閱模式
5.1 觀察者模式
觀察者模式,它定義了一種一對多的關(guān)系,讓多個(gè)觀察者對象同時(shí)監(jiān)聽某一個(gè)主題對象,這個(gè)主題對象的狀態(tài)發(fā)生變化時(shí)就會通知所有的觀察者對象,使得它們能夠自動更新自己。
在觀察者模式中有兩個(gè)主要角色:Subject(主題)和 Observer(觀察者)。
在上圖中,Subject(主題)就是阿寶哥的 TS 專題文章,而觀察者就是小秦和小王。由于觀察者模式支持簡單的廣播通信,當(dāng)消息更新時(shí),會自動通知所有的觀察者。
下面我們來看一下如何使用 TypeScript 來實(shí)現(xiàn)觀察者模式。
5.1.1 實(shí)現(xiàn)代碼
interface Observer { notify: Function; } class ConcreteObserver implements Observer{ constructor(private name: string) {} notify() { console.log(`${this.name} has been notified.`); } } class Subject { private observers: Observer[] = []; public addObserver(observer: Observer): void { console.log(observer, "is pushed!"); this.observers.push(observer); } public deleteObserver(observer: Observer): void { console.log("remove", observer); const n: number = this.observers.indexOf(observer); n != -1 && this.observers.splice(n, 1); } public notifyObservers(): void { console.log("notify all the observers", this.observers); this.observers.forEach(observer => observer.notify()); } }
5.1.2 使用示例
const subject: Subject = new Subject(); const xiaoQin = new ConcreteObserver("小秦"); const xiaoWang = new ConcreteObserver("小王"); subject.addObserver(xiaoQin); subject.addObserver(xiaoWang); subject.notifyObservers(); subject.deleteObserver(xiaoQin); subject.notifyObservers();
5.1.3 應(yīng)用場景及案例
一個(gè)對象的行為依賴于另一個(gè)對象的狀態(tài)。或者換一種說法,當(dāng)被觀察對象(目標(biāo)對象)的狀態(tài)發(fā)生改變時(shí) ,會直接影響到觀察對象的行為。
RxJS Subject:https://github.com/ReactiveX/rxjs/blob/master/src/internal/Subject.ts
RxJS Subject 文檔:https://rxjs.dev/guide/subject
5.2 發(fā)布訂閱模式
在軟件架構(gòu)中,發(fā)布/訂閱是一種消息范式,消息的發(fā)送者(稱為發(fā)布者)不會將消息直接發(fā)送給特定的接收者(稱為訂閱者)。而是將發(fā)布的消息分為不同的類別,然后分別發(fā)送給不同的訂閱者。 同樣的,訂閱者可以表達(dá)對一個(gè)或多個(gè)類別的興趣,只接收感興趣的消息,無需了解哪些發(fā)布者存在。
在發(fā)布訂閱模式中有三個(gè)主要角色:Publisher(發(fā)布者)、 Channels(通道)和 Subscriber(訂閱者)。
在上圖中,Publisher(發(fā)布者)是阿寶哥,Channels(通道)中 Topic A 和 Topic B 分別對應(yīng)于 TS 專題和 Deno 專題,而 Subscriber(訂閱者)就是小秦、小王和小池。
下面我們來看一下如何使用 TypeScript 來實(shí)現(xiàn)發(fā)布訂閱模式。
5.2.1 實(shí)現(xiàn)代碼
type EventHandler = (...args: any[]) => any; class EventEmitter { private c = new Map<string, EventHandler[]>(); // 訂閱指定的主題 subscribe(topic: string, ...handlers: EventHandler[]) { let topics = this.c.get(topic); if (!topics) { this.c.set(topic, topics = []); } topics.push(...handlers); } // 取消訂閱指定的主題 unsubscribe(topic: string, handler?: EventHandler): boolean { if (!handler) { return this.c.delete(topic); } const topics = this.c.get(topic); if (!topics) { return false; } const index = topics.indexOf(handler); if (index < 0) { return false; } topics.splice(index, 1); if (topics.length === 0) { this.c.delete(topic); } return true; } // 為指定的主題發(fā)布消息 publish(topic: string, ...args: any[]): any[] | null { const topics = this.c.get(topic); if (!topics) { return null; } return topics.map(handler => { try { return handler(...args); } catch (e) { console.error(e); return null; } }); } }
5.2.2 使用示例
const eventEmitter = new EventEmitter(); eventEmitter.subscribe("ts", (msg) => console.log(`收到訂閱的消息:${msg}`) ); eventEmitter.publish("ts", "TypeScript發(fā)布訂閱模式"); eventEmitter.unsubscribe("ts"); eventEmitter.publish("ts", "TypeScript發(fā)布訂閱模式");
5.2.3 應(yīng)用場景
對象間存在一對多關(guān)系,一個(gè)對象的狀態(tài)發(fā)生改變會影響其他對象。
作為事件總線,來實(shí)現(xiàn)不同組件間或模塊間的通信。
BetterScroll - EventEmitter:https://github.com/ustbhuangyi/better-scroll/blob/dev/packages/shared-utils/src/events.ts
EventEmitter 在插件化架構(gòu)的應(yīng)用:https://mp.weixin.qq.com/s/N4iw3bi0bxJ57J8EAp5ctQ
六、策略模式
策略模式(Strategy Pattern)定義了一系列的算法,把它們一個(gè)個(gè)封裝起來,并且使它們可以互相替換。策略模式的重心不是如何實(shí)現(xiàn)算法,而是如何組織、調(diào)用這些算法,從而讓程序結(jié)構(gòu)更靈活、可維護(hù)、可擴(kuò)展。
目前在一些主流的 Web 站點(diǎn)中,都提供了多種不同的登錄方式。比如賬號密碼登錄、手機(jī)驗(yàn)證碼登錄和第三方登錄。為了方便維護(hù)不同的登錄方式,我們可以把不同的登錄方式封裝成不同的登錄策略。
下面我們來看一下如何使用策略模式來封裝不同的登錄方式。
6.1 實(shí)現(xiàn)代碼
為了更好地理解以下代碼,我們先來看一下對應(yīng)的 UML 類圖:
interface Strategy { authenticate(...args: any): any; } class Authenticator { strategy: any; constructor() { this.strategy = null; } setStrategy(strategy: any) { this.strategy = strategy; } authenticate(...args: any) { if (!this.strategy) { console.log('尚未設(shè)置認(rèn)證策略'); return; } return this.strategy.authenticate(...args); } } class WechatStrategy implements Strategy { authenticate(wechatToken: string) { if (wechatToken !== '123') { console.log('無效的微信用戶'); return; } console.log('微信認(rèn)證成功'); } } class LocalStrategy implements Strategy { authenticate(username: string, password: string) { if (username !== 'abao' && password !== '123') { console.log('賬號或密碼錯(cuò)誤'); return; } console.log('賬號和密碼認(rèn)證成功'); } }
6.2 使用示例
const auth = new Authenticator(); auth.setStrategy(new WechatStrategy()); auth.authenticate('123456'); auth.setStrategy(new LocalStrategy()); auth.authenticate('abao', '123');
6.3 應(yīng)用場景及案例
一個(gè)系統(tǒng)需要動態(tài)地在幾種算法中選擇一種時(shí),可將每個(gè)算法封裝到策略類中。
多個(gè)類只區(qū)別在表現(xiàn)行為不同,可以使用策略模式,在運(yùn)行時(shí)動態(tài)選擇具體要執(zhí)行的行為。
一個(gè)類定義了多種行為,并且這些行為在這個(gè)類的操作中以多個(gè)條件語句的形式出現(xiàn),可將每個(gè)條件分支移入它們各自的策略類中以代替這些條件語句。
Github - passport-local:https://github.com/jaredhanson/passport-local
Github - passport-oauth3:https://github.com/jaredhanson/passport-oauth3
Github - zod:https://github.com/vriad/zod/blob/master/src/types/string.ts
七、職責(zé)鏈模式
職責(zé)鏈模式是使多個(gè)對象都有機(jī)會處理請求,從而避免請求的發(fā)送者和接受者之間的耦合關(guān)系。在職責(zé)鏈模式里,很多對象由每一個(gè)對象對其下家的引用而連接起來形成一條鏈。請求在這個(gè)鏈上傳遞,直到鏈上的某一個(gè)對象決定處理此請求。
7.1 實(shí)現(xiàn)代碼
為了更好地理解以下代碼,我們先來看一下對應(yīng)的 UML 類圖:
interface IHandler { addMiddleware(h: IHandler): IHandler; get(url: string, callback: (data: any) => void): void; } abstract class AbstractHandler implements IHandler { next!: IHandler; addMiddleware(h: IHandler) { this.next = h; return this.next; } get(url: string, callback: (data: any) => void) { if (this.next) { return this.next.get(url, callback); } } } // 定義Auth中間件 class Auth extends AbstractHandler { isAuthenticated: boolean; constructor(username: string, password: string) { super(); this.isAuthenticated = false; if (username === 'abao' && password === '123') { this.isAuthenticated = true; } } get(url: string, callback: (data: any) => void) { if (this.isAuthenticated) { return super.get(url, callback); } else { throw new Error('Not Authorized'); } } } // 定義Logger中間件 class Logger extends AbstractHandler { get(url: string, callback: (data: any) => void) { console.log('/GET Request to: ', url); return super.get(url, callback); } } class Route extends AbstractHandler { URLMaps: {[key: string]: any}; constructor() { super(); this.URLMaps = { '/api/todos': [{ title: 'learn ts' }, { title: 'learn react' }], '/api/random': Math.random(), }; } get(url: string, callback: (data: any) => void) { super.get(url, callback); if (this.URLMaps.hasOwnProperty(url)) { callback(this.URLMaps[url]); } } }
7.2 使用示例
const route = new Route(); route.addMiddleware(new Auth('abao', '123')).addMiddleware(new Logger()); route.get('/api/todos', data => { console.log(JSON.stringify({ data }, null, 2)); }); route.get('/api/random', data => { console.log(data); });
7.3 應(yīng)用場景
可處理一個(gè)請求的對象集合應(yīng)被動態(tài)指定。
想在不明確指定接收者的情況下,向多個(gè)對象中的一個(gè)提交一個(gè)請求。
有多個(gè)對象可以處理一個(gè)請求,哪個(gè)對象處理該請求運(yùn)行時(shí)自動確定,客戶端只需要把請求提交到鏈上即可。
八、模板方法模式
模板方法模式由兩部分結(jié)構(gòu)組成:抽象父類和具體的實(shí)現(xiàn)子類。通常在抽象父類中封裝了子類的算法框架,也包括實(shí)現(xiàn)一些公共方法以及封裝子類中所有方法的執(zhí)行順序。子類通過繼承這個(gè)抽象類,也繼承了整個(gè)算法結(jié)構(gòu),并且可以選擇重寫父類的方法。
8.1 實(shí)現(xiàn)代碼
為了更好地理解以下代碼,我們先來看一下對應(yīng)的 UML 類圖:
import fs from 'fs'; abstract class DataParser { data: string = ''; out: any = null; // 這就是所謂的模板方法 parse(pathUrl: string) { this.readFile(pathUrl); this.doParsing(); this.printData(); } readFile(pathUrl: string) { this.data = fs.readFileSync(pathUrl, 'utf8'); } abstract doParsing(): void; printData() { console.log(this.out); } } class CSVParser extends DataParser { doParsing() { this.out = this.data.split(','); } } class MarkupParser extends DataParser { doParsing() { this.out = this.data.match(/<\w+>.*<\/\w+>/gim); } }
8.2 使用示例
const csvPath = './data.csv'; const mdPath = './design-pattern.md'; new CSVParser().parse(csvPath); new MarkupParser().parse(mdPath);
8.3 應(yīng)用場景
算法的整體步驟很固定,但其中個(gè)別部分易變時(shí),這時(shí)候可以使用模板方法模式,將容易變的部分抽象出來,供子類實(shí)現(xiàn)。
當(dāng)需要控制子類的擴(kuò)展時(shí),模板方法只在特定點(diǎn)調(diào)用鉤子操作,這樣就只允許在這些點(diǎn)進(jìn)行擴(kuò)展。
感謝各位的閱讀,以上就是“有哪些常見的設(shè)計(jì)模式”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對有哪些常見的設(shè)計(jì)模式這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!
本文標(biāo)題:有哪些常見的設(shè)計(jì)模式
網(wǎng)址分享:http://jinyejixie.com/article40/gdpgho.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供做網(wǎng)站、網(wǎng)站設(shè)計(jì)公司、網(wǎng)站內(nèi)鏈、定制網(wǎng)站、用戶體驗(yàn)、小程序開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)