中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

有哪些常見的設計模式

發布時間:2021-10-26 16:44:23 來源:億速云 閱讀:155 作者:iii 欄目:web開發

這篇文章主要講解了“有哪些常見的設計模式”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“有哪些常見的設計模式”吧!

一、建造者模式

建造者模式(Builder Pattern)將一個復雜對象分解成多個相對簡單的部分,然后根據不同需要分別創建它們,最后構建成該復雜對象。

一輛小汽車 ? 通常由 發動機、底盤、車身和電氣設備  四大部分組成。汽車電氣設備的內部構造很復雜,簡單起見,我們只考慮三個部分:引擎、底盤和車身。

有哪些常見的設計模式

在現實生活中,小汽車也是由不同的零部件組裝而成,比如上圖中我們把小汽車分成引擎、底盤和車身三大部分。下面我們來看一下如何使用建造者模式來造車子。

1.1 實現代碼

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);   } }

在以上代碼中,我們定義一個 CarBuilder 類,并提供了 addChassis、addEngine和 addBody 3  個方法用于組裝車子的不同部位,當車子的 3 個部分都組裝完成后,調用build 方法就可以開始造車。

1.2 使用示例

const car = new CarBuilder()   .addEngine('v12')   .addBody('鎂合金')   .addChassis('復合材料')   .build();

1.3 應用場景及案例

需要生成的產品對象有復雜的內部結構,這些產品對象通常包含多個成員屬性。

需要生成的產品對象的屬性相互依賴,需要指定其生成順序。

隔離復雜對象的創建和使用,并使得相同的創建過程可以創建不同的產品。

Github - node-sql-query:https://github.com/dresende/node-sql-query

二、工廠模式

在現實生活中,工廠是負責生產產品的,比如牛奶、面包或禮物等,這些產品滿足了我們日常的生理需求。

有哪些常見的設計模式

在眾多設計模式當中,有一種被稱為工廠模式的設計模式,它提供了創建對象的最佳方式。工廠模式可以分為:簡單工廠模式、工廠方法模式和抽象工廠模式。

2.1 簡單工廠

簡單工廠模式又叫 靜態方法模式,因為工廠類中定義了一個靜態方法用于創建對象。簡單工廠讓使用者不用知道具體的參數就可以創建出所需的 ”產品“  類,即使用者可以直接消費產品而不需要知道產品的具體生產細節。

有哪些常見的設計模式

在上圖中,阿寶哥模擬了用戶購車的流程,小王和小秦分別向 BMW 工廠訂購了 BMW730 和 BMW840  型號的車型,接著工廠會先判斷用戶選擇的車型,然后按照對應的模型進行生產并在生產完成后交付給用戶。

下面我們來看一下如何使用簡單工廠來描述 BMW 工廠生產指定型號車子的過程。

2.1.1 實現代碼

abstract class BMW {   abstract run(): void; }  class BMW730 extends BMW {   run(): void {     console.log("BMW730 發動咯");   } }  class BMW840 extends BMW {   run(): void {     console.log("BMW840 發動咯");   } }  class BMWFactory {   public static produceBMW(model: "730" | "840"): BMW {     if (model === "730") {       return new BMW730();     } else {       return new BMW840();     }   } }

在以上代碼中,我們定義一個 BMWFactory 類,該類提供了一個靜態的  produceBMW()方法,用于根據不同的模型參數來創建不同型號的車子。

2.1.2 使用示例

const bmw730 = BMWFactory.produceBMW("730"); const bmw840 = BMWFactory.produceBMW("840");  bmw730.run(); bmw840.run();

2.1.3 應用場景

  • 工廠類負責創建的對象比較少:由于創建的對象比較少,不會造成工廠方法中業務邏輯過于復雜。

  • 客戶端只需知道傳入工廠類靜態方法的參數,而不需要關心創建對象的細節。

2.2 工廠方法

工廠方法模式(Factory Method Pattern)又稱為工廠模式,也叫多態工廠(Polymorphic  Factory)模式,它屬于類創建型模式。

在工廠方法模式中,工廠父類負責定義創建產品對象的公共接口,而工廠子類則負責生成具體的產品對象,  這樣做的目的是將產品類的實例化操作延遲到工廠子類中完成,即通過工廠子類來確定究竟應該實例化哪一個具體產品類。

有哪些常見的設計模式

2.2.1 實現代碼

abstract class BMWFactory {   abstract produceBMW(): BMW; }  class BMW730Factory extends BMWFactory {   produceBMW(): BMW {     return new BMW730();   } }  class BMW840Factory extends BMWFactory {   produceBMW(): BMW {     return new BMW840();   } }

在以上代碼中,我們分別創建了 BMW730Factory 和 BMW840Factory 兩個工廠類,然后使用這兩個類的實例來生產不同型號的車子。

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 應用場景

  • 一個類不知道它所需要的對象的類:在工廠方法模式中,客戶端不需要知道具體產品類的類名,只需要知道所對應的工廠即可,具體的產品對象由具體工廠類創建;客戶端需要知道創建具體產品的工廠類。

  • 一個類通過其子類來指定創建哪個對象:在工廠方法模式中,對于抽象工廠類只需要提供一個創建產品的接口,而由其子類來確定具體要創建的對象,利用面向對象的多態性和里氏代換原則,在程序運行時,子類對象將覆蓋父類對象,從而使得系統更容易擴展。

2.3 抽象工廠

抽象工廠模式(Abstract Factory Pattern),提供一個創建一系列相關或相互依賴對象的接口,而無須指定它們具體的類。

在工廠方法模式中具體工廠負責生產具體的產品,每一個具體工廠對應一種具體產品,工廠方法也具有唯一性,一般情況下,一個具體工廠中只有一個工廠方法或者一組重載的工廠方法。但是有時候我們需要一個工廠可以提供多個產品對象,而不是單一的產品對象。

有哪些常見的設計模式

2.3.1 實現代碼

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 應用場景

  • 一個系統不應當依賴于產品類實例如何被創建、組合和表達的細節,這對于所有類型的工廠模式都是重要的。

  • 系統中有多于一個的產品族,而每次只使用其中某一產品族。

  • 系統提供一個產品類的庫,所有的產品以同樣的接口出現,從而使客戶端不依賴于具體實現。

三、單例模式

單例模式(Singleton Pattern)是一種常用的模式,有一些對象我們往往只需要一個,比如全局緩存、瀏覽器中的 window  對象等。單例模式用于保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。

有哪些常見的設計模式

在上圖中,阿寶哥模擬了借車的流程,小王臨時有急事找阿寶哥借車子,阿寶哥家的車子剛好沒用,就借給小王了。當天,小秦也需要用車子,也找阿寶哥借車,因為阿寶哥家里只有一輛車子,所以就沒有車可借了。

對于車子來說,它雖然給生活帶來了很大的便利,但養車也需要一筆不小的費用(車位費、油費和保養費等),所以阿寶哥家里只有一輛車子。

在開發軟件系統時,如果遇到創建對象時耗時過多或耗資源過多,但又經常用到的對象,我們就可以考慮使用單例模式。

下面我們來看一下如何使用 TypeScript 來實現單例模式。

3.1 實現代碼

class Singleton {   // 定義私有的靜態屬性,來保存對象實例   private static singleton: Singleton;   private constructor() {}    // 提供一個靜態的方法來獲取對象實例   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 應用場景

  • 需要頻繁實例化然后銷毀的對象。

  • 創建對象時耗時過多或耗資源過多,但又經常用到的對象。

  • 系統只需要一個實例對象,如系統要求提供一個唯一的序列號生成器或資源管理器,或者需要考慮資源消耗太大而只允許創建一個對象。

四、適配器模式

在實際生活中,也存在適配器的使用場景,比如:港式插頭轉換器、電源適配器和 USB  轉接口。而在軟件工程中,適配器模式的作用是解決兩個軟件實體間的接口不兼容的問題。使用適配器模式之后,原本由于接口不兼容而不能工作的兩個軟件實體就可以一起工作。

有哪些常見的設計模式

4.1 實現代碼

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}`);   } }

在以上代碼中,因為 Logger 和 CloudLogger 這兩個接口不匹配,所以我們引入了 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 應用場景及案例

  • 以前開發的系統存在滿足新系統功能需求的類,但其接口同新系統的接口不一致。

  • 使用第三方提供的組件,但組件接口定義和自己要求的接口定義不同。

  • Github -  axios-mock-adapter:https://github.com/ctimmerm/axios-mock-adapter

五、觀察者模式 & 發布訂閱模式

5.1 觀察者模式

觀察者模式,它定義了一種一對多的關系,讓多個觀察者對象同時監聽某一個主題對象,這個主題對象的狀態發生變化時就會通知所有的觀察者對象,使得它們能夠自動更新自己。

在觀察者模式中有兩個主要角色:Subject(主題)和 Observer(觀察者)。

有哪些常見的設計模式

在上圖中,Subject(主題)就是阿寶哥的 TS  專題文章,而觀察者就是小秦和小王。由于觀察者模式支持簡單的廣播通信,當消息更新時,會自動通知所有的觀察者。

下面我們來看一下如何使用 TypeScript 來實現觀察者模式。

5.1.1 實現代碼

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 應用場景及案例

  • 一個對象的行為依賴于另一個對象的狀態。或者換一種說法,當被觀察對象(目標對象)的狀態發生改變時 ,會直接影響到觀察對象的行為。

  • RxJS  Subject:https://github.com/ReactiveX/rxjs/blob/master/src/internal/Subject.ts

  • RxJS Subject 文檔:https://rxjs.dev/guide/subject

5.2 發布訂閱模式

在軟件架構中,發布/訂閱是一種消息范式,消息的發送者(稱為發布者)不會將消息直接發送給特定的接收者(稱為訂閱者)。而是將發布的消息分為不同的類別,然后分別發送給不同的訂閱者。  同樣的,訂閱者可以表達對一個或多個類別的興趣,只接收感興趣的消息,無需了解哪些發布者存在。

在發布訂閱模式中有三個主要角色:Publisher(發布者)、 Channels(通道)和 Subscriber(訂閱者)。

有哪些常見的設計模式

在上圖中,Publisher(發布者)是阿寶哥,Channels(通道)中 Topic A 和 Topic B 分別對應于 TS 專題和 Deno  專題,而 Subscriber(訂閱者)就是小秦、小王和小池。

下面我們來看一下如何使用 TypeScript 來實現發布訂閱模式。

5.2.1 實現代碼

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;   }    // 為指定的主題發布消息   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發布訂閱模式"); eventEmitter.unsubscribe("ts"); eventEmitter.publish("ts", "TypeScript發布訂閱模式");

5.2.3 應用場景

  • 對象間存在一對多關系,一個對象的狀態發生改變會影響其他對象。

  • 作為事件總線,來實現不同組件間或模塊間的通信。

  • BetterScroll -  EventEmitter:https://github.com/ustbhuangyi/better-scroll/blob/dev/packages/shared-utils/src/events.ts

  • EventEmitter 在插件化架構的應用:https://mp.weixin.qq.com/s/N4iw3bi0bxJ57J8EAp5ctQ

六、策略模式

策略模式(Strategy  Pattern)定義了一系列的算法,把它們一個個封裝起來,并且使它們可以互相替換。策略模式的重心不是如何實現算法,而是如何組織、調用這些算法,從而讓程序結構更靈活、可維護、可擴展。

有哪些常見的設計模式

目前在一些主流的 Web  站點中,都提供了多種不同的登錄方式。比如賬號密碼登錄、手機驗證碼登錄和第三方登錄。為了方便維護不同的登錄方式,我們可以把不同的登錄方式封裝成不同的登錄策略。

下面我們來看一下如何使用策略模式來封裝不同的登錄方式。

6.1 實現代碼

為了更好地理解以下代碼,我們先來看一下對應的 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('尚未設置認證策略');       return;     }     return this.strategy.authenticate(...args);   } }  class WechatStrategy implements Strategy {   authenticate(wechatToken: string) {     if (wechatToken !== '123') {       console.log('無效的微信用戶');       return;     }     console.log('微信認證成功');   } }  class LocalStrategy implements Strategy {   authenticate(username: string, password: string) {     if (username !== 'abao' && password !== '123') {       console.log('賬號或密碼錯誤');       return;     }     console.log('賬號和密碼認證成功');   } }

6.2 使用示例

const auth = new Authenticator();  auth.setStrategy(new WechatStrategy()); auth.authenticate('123456');  auth.setStrategy(new LocalStrategy()); auth.authenticate('abao', '123');

6.3 應用場景及案例

  • 一個系統需要動態地在幾種算法中選擇一種時,可將每個算法封裝到策略類中。

  • 多個類只區別在表現行為不同,可以使用策略模式,在運行時動態選擇具體要執行的行為。

  • 一個類定義了多種行為,并且這些行為在這個類的操作中以多個條件語句的形式出現,可將每個條件分支移入它們各自的策略類中以代替這些條件語句。

  • 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

七、職責鏈模式

職責鏈模式是使多個對象都有機會處理請求,從而避免請求的發送者和接受者之間的耦合關系。在職責鏈模式里,很多對象由每一個對象對其下家的引用而連接起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。

有哪些常見的設計模式

7.1 實現代碼

為了更好地理解以下代碼,我們先來看一下對應的 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 應用場景

可處理一個請求的對象集合應被動態指定。

想在不明確指定接收者的情況下,向多個對象中的一個提交一個請求。

有多個對象可以處理一個請求,哪個對象處理該請求運行時自動確定,客戶端只需要把請求提交到鏈上即可。

八、模板方法模式

模板方法模式由兩部分結構組成:抽象父類和具體的實現子類。通常在抽象父類中封裝了子類的算法框架,也包括實現一些公共方法以及封裝子類中所有方法的執行順序。子類通過繼承這個抽象類,也繼承了整個算法結構,并且可以選擇重寫父類的方法。

有哪些常見的設計模式

8.1 實現代碼

為了更好地理解以下代碼,我們先來看一下對應的 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 應用場景

算法的整體步驟很固定,但其中個別部分易變時,這時候可以使用模板方法模式,將容易變的部分抽象出來,供子類實現。

當需要控制子類的擴展時,模板方法只在特定點調用鉤子操作,這樣就只允許在這些點進行擴展。

感謝各位的閱讀,以上就是“有哪些常見的設計模式”的內容了,經過本文的學習后,相信大家對有哪些常見的設計模式這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

永兴县| 肥西县| 靖州| 仙游县| 肇东市| 齐齐哈尔市| 隆林| 黄龙县| 平阴县| 临沂市| 游戏| 张家港市| 凤冈县| 三都| 财经| 和田县| 颍上县| 内江市| 和平县| 旬阳县| 收藏| 清徐县| 岑溪市| 东乡| 阿巴嘎旗| 安泽县| 兴仁县| 东山县| 阿荣旗| 古浪县| 剑川县| 台东市| 团风县| 临西县| 兴国县| 承德县| 阜南县| 汝南县| 姚安县| 色达县| 曲阳县|