日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

Scala 与设计模式(四):Factory 工厂模式

發(fā)布時間:2023/12/20 asp.net 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Scala 与设计模式(四):Factory 工厂模式 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在中國歷史上,房子常常與當(dāng)下一樣稀缺,住房問題同樣是一個讓百姓苦惱的社會熱點。

在拆違章建筑還不盛行的年代,我們可以選擇在深山老林里自己修建住所。在 Java 中可能是這樣實現(xiàn)的:

class BuildingA {private String name;public BuildingA(String name) {this.name = name;}public void build() {System.out.println(name + " is building");} }class BuildingB {private String name;public BuildingB(String name) {this.name = name;}public void build() {System.out.println(name + " is building");} }// 使用BuildingA buildingA = new BuildingA("bedroom");BuildingB buildingB = new BuildingB("kitchen");buildingA.build();buildingB.build();復(fù)制代碼

村里的牛大哥在建完兩間房子之后,后知后覺:自己想要的房間格局不同,但是風(fēng)格得相同,可以把公共的部分抽離出來:

interface IBuilding {void build(); }abstract class AbstractBuilding implements IBuilding {protected void buildCommon(){System.out.println("Europe style"); // 公共的部分} }class BuildingAs extends AbstractBuilding {private String name;public BuildingAs(String name){this.name = name;}@Overridepublic void build() {this.buildCommon();System.out.println(name + " is building");} }class BuildingBs extends AbstractBuilding {private String name;public BuildingBs(String name) {this.name = name;}@Overridepublic void build() {this.buildCommon();System.out.println(name + " is building");} }// 使用 BuildingAs buildingA = new BuildingAs("bedroom"); BuildingBs buildingB = new BuildingBs("kitchen"); buildingA.build(); buildingB.build();復(fù)制代碼

但是這么做之后,牛大哥發(fā)現(xiàn)在建造的時候并沒有省力,他向村口的王師傅請教,為什么我考慮了很多反而沒什么作用呢?

簡單工廠模式

王師傅告訴他:雖然你找出了一些公共的流程,但在實際建造過程中,你還是完整的過了所有的流程(構(gòu)造方法不同,每次都要 new 對象)。另外,

另外,你對房屋的需求并不多,所以優(yōu)勢不夠明顯。

說著掏出一個寶盒,盒子里有很多設(shè)計圖:下次你可以委托我來造一些組件(不再需要自己 new):

public class SimpleFactory {public static IBuilding getProduct(String name){if("bedroom".equals(name)){return new BuildingA(name);}else if("kitchen".equals(name)){return new BuildingB(name);}else{throw new IllegalArgumentException();}} }// 使用 IBuilding buildingA = SimpleFactory.getProduct("bedroom"); IBuilding buildingB = SimpleFactory.getProduct("kitchen"); buildingA.build(); buildingB.build();復(fù)制代碼

王師傅幫助下的牛大哥在后面的建造中感覺輕松多了。

這就是「簡單工廠模式」,也稱作「靜態(tài)工廠方法模式」。

優(yōu)點

它有以下幾個優(yōu)點:

  • 簡化對象創(chuàng)建的 API
  • 減少 new 關(guān)鍵字對代碼的干擾
  • 代碼更精簡優(yōu)雅

而牛二哥明顯沒有那么幸運,他的妻子追求個性,并且很善變,總是在建造過程中更改需求。

缺點

雖然牛二哥也去王師傅那獲取組件,每次王師傅都要拿出他的寶盒,在里面翻一遍,再告訴牛二哥 —— 這個我不會造。站在 OCP(開放封閉原則)的角度講,該模式的擴展不夠良好,每次有新的模型后都要修改工廠。

工廠方法模式

老王師傅也經(jīng)不起折騰,想著不能閉關(guān)鎖國,就把自己會建造的組件貼在顯眼的地方,有新的組件直接加在上面就好:

interface IFactory {public IBuilding createBuilding(); }class FactoryA implements IFactory{@Overridepublic IBuilding createBuilding() {// 可以進行復(fù)雜的處理,每一種方法對應(yīng)一種模型return new BuildingA("bedroom");} }class FactoryB implements IFactory{@Overridepublic IBuilding createBuilding() {return new BuildingA("kitchen");} }class FactoryC implements IFactory{@Overridepublic IBuilding createBuilding() {return new BuildingA("restroom");} }// 使用 FactoryA factoryA = new FactoryA(); FactoryB factoryB = new FactoryB(); FactoryC factoryC = new FactoryC(); factoryA.createBuilding(); factoryB.createBuilding(); factoryC.createBuilding();復(fù)制代碼

這樣大家的溝通是方便了很多,而且老王也不用每次都搜一遍傳家寶盒。

這種模式被 GOF 稱作「工廠方法模式」。

定義

工廠方法模式(Factory Method Pattern)是一種實現(xiàn)了「工廠」概念的面向?qū)ο笤O(shè)計模式。就像其他創(chuàng)建型模式一樣,它也是 處理在不指定對象具體類型的情況 下創(chuàng)建對象的問題。定義如下:

定義一個用于創(chuàng)建對象的接口,讓子類決定實例化哪一個類。Factory Method 使一個類的實例化延遲到其子類。 — 《設(shè)計模式》 GOF

從以上也可看出:工廠做的事很簡單 —— 封裝內(nèi)部的實現(xiàn)細節(jié)

優(yōu)點

它可以帶來以下好處:

  • 降低耦合度。在工廠方法模式中,工廠方法用來創(chuàng)建用戶所需要的產(chǎn)品,同時還向用戶隱藏了哪種具體產(chǎn)品類將被實例化這一細節(jié),用戶只需要關(guān)心所需產(chǎn)品對應(yīng)的工廠,無須關(guān)心創(chuàng)建細節(jié),甚至無須知道具體產(chǎn)品類的類名。
  • 良好擴展性。需要新的產(chǎn)品類型時,只需要新增一個工廠類,不需要更改產(chǎn)品以及產(chǎn)品的接口以及用戶的使用方式。
  • 代碼結(jié)構(gòu)清晰。用戶使用時不需要構(gòu)造內(nèi)部結(jié)構(gòu),直接調(diào)用工廠方法即可。
  • 缺點

    我們可能會遇上以下問題:

  • 增加使用成本。使用工廠模式的時候一般都會采用接口或者抽象類,有時還會涉及到反射、DOM 等方式。
  • 增加系統(tǒng)復(fù)雜度(影響不顯著)。一個工廠類對應(yīng)一個產(chǎn)品,所以增加產(chǎn)品類的時候就需要增加工廠類。
  • 工廠方法模式針對的是一個產(chǎn)品等級結(jié)構(gòu),當(dāng)要處理多個產(chǎn)品等級結(jié)構(gòu)時(ex. 建立不同小區(qū),小區(qū)里有不同樓宇,樓里還有不同戶型),我們不希望對每個模型都建立一個工廠,這太糟糕了,來看看「抽象工廠模式」是如何解決的。

    抽象工廠模式

    定義

    為創(chuàng)建一組相關(guān)或相互依賴的對象提供一個接口,而且無需指定他們的具體類。

    我們也可把「一組相關(guān)或相互依賴的對象」稱作「產(chǎn)品族」。

    利用抽象工廠,我們可以這么寫:

    interface IBuildingA {void buildA(); }interface IBuildingB {void buildB(); }interface IFactory {public IBuildingA createBuildingA();public IBuildingB createBuildingB(); }class BuildingA implements IBuildingA {... // 省略構(gòu)造函數(shù)@Overridepublic void buildA() {System.out.println((name + "is building"));} }class BuildingB implements IBuildingB {... // 省略構(gòu)造函數(shù)@Overridepublic void buildB() {System.out.println(name + " is building");} }class Factory implements IFactory{@Overridepublic IBuildingA createBuildingA() {return new BuildingA("big bedroom");}@Overridepublic IBuildingB createBuildingB() {return new BuildingB("small bedroom");} }// 測試 Factory factory = new Factory(); factory.createBuildingA(); factory.createBuildingB();復(fù)制代碼

    我們可以直接在一個工廠類中實現(xiàn)多個方法,這樣不用管理多個工廠,使用和管理起來都更方便。

    如果說工廠方法解決問題的方式是「廣搜」,那抽象工廠亦可看作「深搜」。

    總結(jié)

    以上,我們使用到了三種設(shè)計模式:簡單工廠(靜態(tài)工廠方法)工廠方法抽象工廠
    在三種模式中,我們要做的都是將工廠的初始化與構(gòu)造分離

    雖然比起直接 new 要增加不少代碼,但在后期維護的時候,能給我們提供很多的便利。

    看完 Java 版本,我們再來看看 Scala 是如何實現(xiàn)的。

    Scala 實現(xiàn)

    在 Scala 中,依舊可以用類似 Java 的方式來實現(xiàn),只用把 Java 中的關(guān)鍵字 interface 換成 trait 即可,直接看代碼吧。

    簡單工廠模式

    trait IBuilding {def show() }case class SimpleBuilding(name: String)extends IBuilding {def show = println("SimpleBuilding " + name + " is building") }case class LuxuryBuilding(name: String) extends IBuilding{def show = println("LuxuryBuilding " + name + " is building") }object ConstructionFactory {def createBuilding(kind: String): IBuilding = kind match {case "Simple" => SimpleBuilding("Simple")case "Luxury" => LuxuryBuilding("Luxury")} }object Test extends App {val simpleBuilding: IBuilding = ConstructionFactory.createBuilding("Simple")val luxuryBuilding: IBuilding = ConstructionFactory.createBuilding("Luxury")simpleBuilding.show()luxuryBuilding.show() }復(fù)制代碼

    除了這種方式,Scala 還為我們提供了一種類似構(gòu)造器的語法 —— apply,通過這種方式,我們可以省略工廠類,只需增加產(chǎn)品類接口的伴生對象:

    object IBuilding {def apply(kind: String): IBuilding = kind match {case "Simple" => SimpleBuilding("Simple")case "Luxury" => LuxuryBuilding("Luxury")} }復(fù)制代碼

    調(diào)用者有更好的體驗:

    val simpleBuilding: IBuilding = IBuilding("Simple") val luxuryBuilding: IBuilding = IBuilding("Luxury") simpleBuilding.show() luxuryBuilding.show()復(fù)制代碼

    嚴(yán)格意義講,這種方法并不屬于 GOF 提到的工廠方法,它缺少了工廠模塊,我們可以稱之為「靜態(tài)工廠模式」。

    工廠方法與抽象工廠的實現(xiàn)與 Java 類似,代碼就不貼出來了。不了解 Scala 的同學(xué)可以參考源碼

    總結(jié)

    內(nèi)部組成

    以上,不難總結(jié)出工廠模式中的四種角色(簡單工廠模式中沒有抽象工廠):

    • 抽象產(chǎn)品:它是定義產(chǎn)品的接口,是工廠方法模式所創(chuàng)建對象的超類型,也就是產(chǎn)品對象的公共父類。(ex. 文中 IBuiiding)。
    • 具體產(chǎn)品:它實現(xiàn)了抽象產(chǎn)品接口,某種類型的具體產(chǎn)品由專門的具體工廠創(chuàng)建,具體工廠和具體產(chǎn)品之間一一對應(yīng)。(ex. 文中 Buiiding)
    • 抽象工廠: 在抽象工廠類中,聲明了工廠方法(Factory Method),用于返回一個產(chǎn)品。抽象工廠是工廠方法模式的核心,所有創(chuàng)建對象的工廠類都必須實現(xiàn)該接口。(ex. 文中 IFactory)
    • 具體工廠: 它是抽象工廠類的子類,實現(xiàn)了抽象工廠中定義的工廠方法,并可由客戶端調(diào)用,返回一個具體產(chǎn)品類的實例。(ex. 文中 ConstructionFactory)

    適用場景

    當(dāng)然,我們不能為了設(shè)計而設(shè)計,當(dāng)類結(jié)構(gòu)簡單的時候,我們可以直接使用 new 來創(chuàng)造,否則會增加不必要的代碼,反而使結(jié)構(gòu)復(fù)雜化。

    所有工廠模式適用場景類似:調(diào)用者無需知道他所使用的對象的類(實際上內(nèi)部結(jié)構(gòu)對調(diào)用者是透明的 ex. 簡單工廠)。

    但還是有所差異,以下為個人理解:

    名稱適用場景
    簡單工廠1. 工廠類負(fù)責(zé)創(chuàng)建的對象比較少
    2. 客戶只知道傳入工廠類的參數(shù),對于如何創(chuàng)建對象(邏輯)不關(guān)心
    工廠方法工廠類負(fù)責(zé)創(chuàng)建的對象復(fù)雜, 且內(nèi)部對象層級關(guān)系比較簡單
    抽象工廠工廠類負(fù)責(zé)創(chuàng)建的對象復(fù)雜, 且內(nèi)部對象層級關(guān)系比較復(fù)雜

    源碼鏈接

    如有錯誤和講述不恰當(dāng)?shù)牡胤竭€請指出,不勝感激!

    總結(jié)

    以上是生活随笔為你收集整理的Scala 与设计模式(四):Factory 工厂模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。