創建型:工廠模式-工廠方法、抽象工廠

来源:https://www.cnblogs.com/longbensong/archive/2023/03/07/17188197.html
-Advertisement-
Play Games

簡單工廠問題 簡單工廠中我們通過參數來返回不同的產品對象,如果管理的對象過多,這個工廠函數會比較龐大,且當我們需要增加一個新的產品時,需要修改這個工廠方法,違反開閉原則(對拓展開放,對修改關閉)。 為瞭解決簡單工廠模式的問題,出現了工廠方法模式。 解決簡單工廠思路 簡單工廠類圖關係類似如下: 如上圖 ...


簡單工廠問題

簡單工廠中我們通過參數來返回不同的產品對象,如果管理的對象過多,這個工廠函數會比較龐大,且當我們需要增加一個新的產品時,需要修改這個工廠方法,違反開閉原則(對拓展開放,對修改關閉)。

為瞭解決簡單工廠模式的問題,出現了工廠方法模式。

解決簡單工廠思路

簡單工廠類圖關係類似如下:

如上圖當我們需要增加一個產品時,我們需要修改create 方法增加相關判斷的邏輯,這不符合開閉原則。

假如一個工廠只負責他自己的產品,那麼新增產品也只是新增一個工廠以及對應的產品,那麼簡單工廠的問題是不是也解決了。

總結:將對象的創建與實例化延遲到子類,這樣的工廠設計就符合“開閉原則”了,擴展時不必去修改原來的代碼

工廠方法模式

如上圖當我們增加一個產品時,只需要增加一個工廠(實現抽象類),然後在各自的工廠返回自己需要的產品即可;

工廠方法由4個要素組成:

  1. 抽象工廠 AbstractFactory: 這個是工廠方法模式的核心,定義用來生產對應產品的方法,是具體工廠必須實現的介面或者必須繼承的父類,通常使用中它由抽象類或者介面來實現。
  2. 具體工廠 Factory:被應用程式調用以創建具體產品的對象,含有和具體業務邏輯有關的代碼。
  3. 抽象產品 AbstractProduct:把產品共有的特征抽象,通常使用中它由抽象類或者介面來實現。
  4. 具體產品 Product:具體工廠所創建的產品(對象)。

 

如果只是接觸了js,可能對抽象不太瞭解 ,其實抽象只是一種思考的問題的方式。

抽象的定義是從眾多的事物中抽取出共同的、本質性的特征,而捨棄其非本質的特征的過程

簡單的理解其實就是共有的特征、特性,比如我們要規範人這個對象具有的特點,就用一個介面或者抽象類聲明一些共有的屬性、方法,具體的子類在實現這個介面或者抽象類,這樣子類也有這些屬性、方法。

這樣做的好處就是約束子類,保證子類都有這些屬性、方法,不會存在亂七八糟的對象,這也符合我們大腦工作方式。

ts模擬工廠方法模式

  工廠方法是將實際創建對象的工作推遲到子類中,這樣核心類就變成了抽象類。但是在JavaScript中很難像傳統面向對象那樣去實現創建抽象類。所以在JavaScript中我們只需要參考它的核心思想即可。我們可以將工廠方法看作是一個實例化對象的工廠類。雖然ES6也沒有實現abstract,但是我們可以使用new.target來模擬出抽象類。new.target指向直接被new執行的構造函數,我們對new.target進行判斷,如果指向了該類則拋出錯誤來使得該類成為抽象類。

ts 擴展了js,所以這裡我用ts 來模擬

/*
工廠方法是簡單工廠的優化版本,在之前把生成具體產品的實例邏輯都寫在了工廠方法中,
導致增加一個產品,這個工廠方法需要修改。
所以工廠方法主要是把這一部分功能獨立出來了,一個工廠負責一個產品
工廠方法核心結構有四個角色
  1、抽象工廠
  2、具體工廠
  3、抽象產品
  4、具體產品
因為js不支持沒有抽象類這裡用ts 代替,只要符合核心思想即可
*/
// 抽象工廠
abstract class CardFactor{
  abstract getCardInstance(name:string, time:string):Card
}
// 抽象產品
abstract class Card {
  carName: string;
  time: string;
  abstract getCarDesc():void
}

// 具體產品-BydCar
class BydCar extends Card {
  constructor (name, time) {
    super()
    this.carName = name
    this.time = time
  }
  runCarName () {
    console.log(this.carName)
  }
  getCarDesc () {
    console.log(`我是${this.carName},生產於:${this.time}`)
  }
}
// 具體產品-JeepCar
class JeepCar extends Card {
  constructor (name, time) {
    super()
    this.carName = name
    this.time = time
  }
  runCarName () {
    console.log(this.carName)
  }
  getCarDesc () {
    console.log(`我是${this.carName},生產於:${this.time}`)
  }
}
// 具體產品-BenzCar
class BenzCar extends Card {
  carName: string
  time: string
  constructor (name, time) {
    super()
    this.carName = name
    this.time = time
  }
  runCarName () {
    console.log(this.carName)
  }
  getCarDesc () {
    console.log(`我是${this.carName},生產於:${this.time}`)
  }
}

// 具體的工廠-BydCarFactory
class BydCarFactory extends CardFactor {
  getCardInstance (name, time) {
    return new BydCar(name, time)
  }
}
// 具體的工廠-JeepCarFactory
class JeepCarFactory extends CardFactor{
  getCardInstance (name, time) {
    return new JeepCar(name, time)
  }
}
// 具體的工廠-BenzCarFactory
class BenzCarFactory extends CardFactor{
  getCardInstance (name, time) {
    return new BenzCar(name, time)
  }
}
// test 直接使用具體的工廠
const bydCar = new BydCarFactory().getCardInstance('byd 汽車', '2022-08-20')
const jeepCar = new JeepCarFactory().getCardInstance('jeep 汽車', '2022-08-21')
const benzCar = new BenzCarFactory().getCardInstance('benz 汽車', '2022-08-22')


bydCar.runCarName()
bydCar.getCarDesc()

jeepCar.runCarName()
jeepCar.getCarDesc()

benzCar.runCarName()
benzCar.getCarDesc()

 如果我們現在需要增加一種車型,那我們只需增加對應的工廠,跟產品類即可,我們對原有的工廠不會造成任何影響 所謂的“對拓展開放,對修改封閉”就這麼圓滿實現了。

工廠方法缺陷

  在工廠方法模式中,我們使用一個工廠創建一個產品,一個具體工廠對應一個具體產品,但有時候我們需要一個工廠能夠提供多個產品對象,而不是單一的對象,這個時候我們就需要使用抽象工廠模式。

  上面代碼中我們的比亞迪工廠只是生產一種產品,現實是一個工廠大概率是要生產很多種不同的產品,如比亞迪有漢dmi、dmp、唐suv等車型。這種一個工廠需要多種產品的時候,按照工廠方法的思路,我們需要寫很多個這種工廠類,這也非常繁瑣。

抽象工廠模式

  我們需要的是一個工廠可以生產多種不同的產品對象,按照設計模式的思路把變化的抽出來封裝。變的是一個工廠可以支持多個產品對象,不變的依舊是在工廠中拿到產品對象。按照工廠方法的思路,只需要在抽象工廠中增加創建對應的產品即可,以之前汽車的例子把工廠方法改成抽象工廠,只要把抽象工廠中增加對應的獲取產品,修改之後現在比亞迪工廠支持預設車型,漢車型,suv車型;

/*
抽象工廠:一個工廠可以生產多種不同的產品,它思路跟工廠方法基本一致。
抽象工廠核心結構有四個角色
  1、抽象工廠
  2、具體工廠
  3、抽象產品
  4、具體產品
因為js不支持沒有抽象類這裡用ts 代替,只要符合核心思想即可
*/
// 抽象工廠
abstract class CardFactor{
  // 預設的車型
  abstract getCardInstance(name:string, time:string):Card
  // 漢車型
  abstract getCardHanDmiInstance(name:string, time:string):Card
  // suv 車型
  abstract getCardSuvInstance(name:string, time:string):Card
}
// 抽象產品,同理:這裡也可以把產品進一步抽象,如漢的抽象產品,suv的抽象產品,這裡不在調整
abstract class Card {
  carName: string;
  time: string;
  abstract getCarDesc():void
}

// 具體產品-BydCar
class BydCar extends Card {
  constructor (name, time) {
    super()
    this.carName = name
    this.time = time
  }
  runCarName () {
    console.log(this.carName)
  }
  getCarDesc () {
    console.log(`我是${this.carName},生產於:${this.time}`)
  }
}

// 具體產品-BydHanCar
class BydHanCar extends Card {
  name = '中大型轎車漢'
  desc = '這是來自比亞迪的漢'
  constructor () {
    super()
  }
  runCarName () {
    console.log(this.carName)
  }
  getCarDesc () {
    console.log(`我是${this.carName},生產於:${this.time}`)
  }
}
// 具體產品-BydSuvCar
class BydSuvCar extends Card {
  name = 'suv'
  desc = '這是來自比亞迪的suv'
  constructor () {
    super()
  }
  runCarName () {
    console.log(this.carName)
  }
  getCarDesc () {
    console.log(`我是${this.carName},生產於:${this.time}`)
  }
}
// 具體的工廠-BydCarFactory
class BydCarFactory extends CardFactor {
  // 生產預設的byd 車型
  getCardInstance (name, time) {
    return new BydCar(name, time)
  }
  // 生產byd漢車型
  getCardHanDmiInstance () {
    return new BydHanCar()
  }
  // 生產byd suv車型
  getCardSuvInstance () {
    return new BydSuvCar()
  }
}

// test 直接使用具體的工廠
const bydCarFactory = new BydCarFactory()
// 現在這個工廠具備生產三種車的產品了
const bydCar = bydCarFactory.getCardInstance('預設車型', '2023-3-7');
const hanCar = bydCarFactory.getCardHanDmiInstance();
const suvCar = bydCarFactory.getCardSuvInstance();

 抽象工廠模式與工廠方法模式區別在於,工廠方法模式針對的是一個產品等級結構,而抽象工廠模式則需要面對多個產品等級結構,一個工廠等級結構可以負責多個不同產品等級結構中的產品對象的創建 。

 抽象工廠模式同工廠方法模式一樣,也是由4 個要素構成,但抽象工廠中方法個數不同,抽象產品的個數也不同。

  1. AbstractFactory:抽象工廠
  2. ConcreteFactory:具體工廠
  3. AbstractProduct:抽象產品
  4. Product:具體產品

這種管理多個產品結構的抽象類,就是抽象工廠模式,讓一個工廠具備管理多個產品結構。

抽象工廠模式相對於工廠方法模式來說,工廠方法模式是針對一個產品系列的,而抽象工廠模式是針對多個產品系列的,即工廠方法模式是一個產品系列一個工廠類,而抽象工廠模式是多個產品系列一個工廠類。

定義:提供一個介面,用於創建相關或依賴對象的家族,而不需要明確指定具體類。

工廠方法與抽象工廠

抽象工廠模式與工廠方法模式區別在於,工廠方法模式針對的是一個產品等級結構,而抽象工廠模式則需要面對多個產品等級結構,一個工廠結構可以負責多個不同產品等級結構中的產品對象的創建 。

(1)工廠方法只有一個抽象產品類和一個抽象工廠類,可以派生出多個具體產品類和具體工廠類,每個具體工廠類只能創建一個具體產品類的實例

(2)抽象工廠模式擁有多個抽象產品類(產品族)和一個抽象工廠類,每個抽象產品類可以派生出多個具體產品類;抽象工廠類也可以派生出多個具體工廠類,時每個具體工廠類可以創建多個具體產品類的實例

小結

  1. 工廠方法是一個工廠只生產一種產品,類似極端情況下的抽象工廠模式(即只生產一種產品的抽象工廠模式)
  2. 抽象工廠是一個工廠可以生產多種同類的產品(產品族)

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 以製作生產質量數據可視化看板為例,介紹用excel製作可視化看板的思路以及數據透視表、Vlookup、sumif、rank等常用函數的用法。提供完整數據和製作可視化看板的思路以及建立可視化看板的操作步驟,足夠支撐大家復現類似的可視化看板。 ...
  • 前言:最近幾年用MYSQL資料庫挺多的,發現了一些非常有用的小玩意,今天拿出來分享到大家,希望對你會有所幫助。 ...
  • 好家伙,本篇為《JS高級程式設計》第十章“期約與非同步函數”學習筆記 ES8 的 async/await 旨在解決利用非同步結構組織代碼的問題。 為為此增加了兩個新關鍵字:async 和 await。 1.async關鍵字 1.1.使用說明 async 關鍵字用於聲明非同步函數。 函數聲明、函數表達式、箭 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 本篇文章記錄仿寫一個el-button組件細節,從而有助於大家更好理解餓了麽ui對應組件具體工作細節。本文是elementui源碼學習仿寫系列的又一篇文章,後續空閑了會不斷更新並仿寫其他組件。源碼在github上,大家可以拉下來,npm ...
  • 我們在初學react時(有vue等其他基礎),我們在方法調用的時候通常是 方法名() 例如: import React from 'react' function test() { console.log('這是測試') } export default class Login extends Re ...
  • 什麼是單例模式 單例模式 (Singleton Pattern)又稱為單體模式,保證一個類只有一個實例,並提供一個訪問它的全局訪問點。也就是說,第二次使用同一個類創建新對象的時候,應該得到與第一次創建的對象完全相同的對象。 簡單的說就是保證一個類僅有一個實例,並提供一個訪問它的全局訪問點,這樣的模式 ...
  • 前言 最近需要用到多包管理 monorepo 開發新項目,所以提前預研一下項目搭建。 monorepo(monolithic repository)是一種項目架構,就是用一個倉庫管理多個項目(應用,庫),react和babel的源碼倉庫都是用這種方式在管理。 優缺點略過,可以參考:精讀《Monore ...
  • 首先需要明確一點,以往瀏覽器對css的支持是不同的,不同瀏覽器的樣式可能會存在差異,對待這種差異問題,需要寫幾套不同的css來相容(邊框、圓角、顏色等),這樣是非常麻煩的,瀏覽器css顯示差異化屬於瀏覽器自身的問題,跟我們的css是沒有關係的,好的瀏覽器就有好的顯示,糟糕的瀏覽器就只有普通顯示,我們 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...