摘要:基于工廠角色和產品角色的多態性設計是工廠方法模式的關鍵。工廠方法模式之所以又被稱為多態工廠模式,是因為所有的具體工廠類都具有同一抽象父類。工廠方法模式總結工廠方法模式是簡單工廠模式的進一步抽象和推廣。
JavaScript工廠模式
首先需要說一下工廠模式。工廠模式根據抽象程度的不同分為三種
簡單工廠模式
工廠方法模式
抽象工廠模式
1.簡單工廠模式簡單工廠模式:又稱為靜態工廠方法模式,它屬于類創建型模式。
在簡單工廠模式中,可以根據參數的不同返回不同類的實例。
由工廠對象決定創建某一種產品對象類的實例。
// #簡單工廠模式第一種 /** * 足球類 */ var FootBall = function () { this.play = function () { console.log("我在踢足球"); } } /** * 籃球類 */ var BasketBall = function () { this.play = function () { console.log("我在打籃球"); } } var football = new FootBall(); football.play(); var basketball = new BasketBall(); basketball.play(); /** * 球類工廠 */ var Ball = function(name) { switch (name) { case "足球": return new FootBall(); break; case "籃球": return new BasketBall(); break; } } var football = Ball("足球"); football.play(); var basketball = Ball("籃球"); basketball.play(); // #簡單工廠模式第一種end
這段案例可以簡單的這么去理解,假設我們需要多個球,我們希望在使用球的時候,只需要告訴管理員我們需要的球的類型,不需要一個個去找對應的球這個管理員就相對于工廠函數。
簡單講就是使用簡單工廠模式,那么你就不需要關心它的具體實現,你只需要知道你要使用的類型,那么工廠函數會自動幫你去做對應的事情
// #簡單工廠模式第二種 /** * 球類工廠 */ var Ball = function(name) { // 創建一個對象,對對象擴展擴展屬性還有方法 var o = new Object(); o.name = name; //默認的方法 如果在加上一個羽毛球類,這時候就不需要補充play方法 o.play = function () { console.log("我在打"+name); } if (name === "足球") { o.play = function () { console.log("我在踢"+name); } }else if (name === "籃球") { o.play = function () { console.log("我在打"+name); } } // 將對象返回 return o; } var football = Ball("足球"); football.play(); var basketball = Ball("籃球"); basketball.play(); // #簡單工廠模式第二種end
這段案例是用對象的方式代替多個類,把相同點抽離出來,
不同點在一一做類型判斷,這樣也是簡單工廠模式實現的另一種方式
簡單工廠模式的優點:
工廠類含有必要的判斷邏輯,可以決定在什么時候創建哪一個產品類的實例,客戶端可以免除直接創建產品對象的責任,而僅僅“消費”產品;簡單工廠模式通過這種做法實現了對責任的分割,它提供了專門的工廠類用于創建對象
客戶端無須知道所創建的具體產品類的類名,只需要知道具體產品類所對應的參數即可,對于一些復雜的類名,通過簡單工廠模式可以減少使用者的記憶量。
簡單工廠模式的缺點
由于工廠類集中了所有產品創建邏輯,一旦不能正常工作,整個系統都要受到影響。
使用簡單工廠模式將會增加系統中類的個數,在一定程序上增加了系統的復雜度和理解難度。
系統擴展困難,一旦添加新產品就不得不修改工廠邏輯,在產品類型較多時,有可能造成工廠邏輯過于復雜,不利于系統的擴展和維護。
簡單工廠模式的適用情況
在以下情況下可以使用簡單工廠模式:
工廠類負責創建的對象比較少:由于創建的對象較少,不會造成工廠方法中的業務邏輯太過復雜。
客戶端只知道傳入工廠類的參數,對于如何創建對象不關心:客戶端既不需要關心創建細節,甚至連類名都不需要記住,只需要知道類型所對應的參數。
簡單工廠模式總結
簡單工廠模式的要點在于:當你需要什么,只需要傳入一個正確的參數,就可以獲取你所需要的對象,而無須知道其創建細節。
簡單工廠模式最大的優點在于實現對象的創建和對象的使用分離,將對象的創建交給專門的工廠類負責,但是其最大的缺點在于工廠類不夠靈活,增加新的具體產品需要修改工廠類的判斷邏輯代碼,而且產品較多時,工廠方法代碼將會非常復雜。
2.工廠方法模式工廠方法模式:又稱為工廠模式,也叫虛擬構造器模式或者多態工廠模式它屬于類創建型模式。在工廠方法模式中,工廠父類負責定義創建產品對象的公共接口,而工廠子類則負責生成具體的產品對象,這樣做的目的是將產品類的實例化操作延遲到工廠子類中完成,即通過工廠子類來確定究竟應該實例化哪一個具體產品類這樣解釋可能會有點抽象。
// # 工廠方法模式 // 安全模式創建工廠類 var Ball = function (type,name) { /** * 安全模式 Ball也可以運行處new Ball的效果 */ if(this instanceof Ball) { var s = new this[type](name); return s; }else { return new Ball(type,name); } } // 工廠原型中設置創建所有類型數據對象的基類 Ball.prototype = { basketBall: function(name) { this.play = function() { console.log("我在打"+name); } }, footBall: function(name) { this.play = function() { console.log("我在踢"+name); } }, badmintonBall: function(name) { this.play = function() { console.log("我在打"+name); } }, // .... } var football = new Ball("footBall","足球"); football.play(); var basketball = new Ball("basketBall","籃球"); basketball.play(); var badmintonball = new Ball("badmintonBall","羽毛球"); badmintonball.play(); // # 工廠方法模式end
這段案例是這么去理解的,我們先創建一個球類工廠,這個球類工廠是一個抽象的,不做具體的實現,然后我們在這個球類工廠里面在去定義對應的球類實現,如籃球,羽毛球,足球等實現,在工廠方法模式中,抽象類工廠只是負責定義一個對外的公共接口,而工廠子類則負責生成具體的產品對象。
這樣做的目的是將產品類的實例化操作延遲到工廠子類中完成,即通過工廠子類來確定究竟應該實例化哪一個具體產品類如果這時候在出現一個新的球類運動,只需要為這種新類型的球類創建一個具體的球類實現就可以,這一特點無疑使得工廠方法模式具有超越簡單工廠模式的優越性,更加符合“開閉原則”
上面案例包含了一個安全模式的知識點
// 安全模式創建工廠類 var Ball = function (type,name) { /** * 安全模式 Ball也可以運行處new Ball的效果 */ if(this instanceof Ball) { var s = new this[type](name); return s; }else { return new Ball(type,name); } }
這段代碼主要解決的問題是,有些同學使用工廠類的時候,忘記使用關鍵字new,得不到預期想要的效果這邊的解決方案就是,在構造函數開始時先判斷當前對象this指代是不是當前工廠類,如果不是則通過new關鍵字創建對象返回,這樣就可以實現不使用new關鍵詞也可以達到相同的效果了
工廠方法模式的優點:
在工廠方法模式中,工廠方法用來創建客戶所需要的產品,同時還向客戶隱藏了哪種具體產品類將被實例化這一細節,用戶只需要關心所需產品對應的工廠,無須關心創建細節,甚至無須知道具體產品類的類名。
基于工廠角色和產品角色的多態性設計是工廠方法模式的關鍵。它能夠使工廠可以自主確定創建何種產品對象,而如何創建這個對象的細節則完全封裝在具體工廠內部。工廠方法模式之所以又被稱為多態工廠模式,是因為所有的具體工廠類都具有同一抽象父類。
使用工廠方法模式的另一個優點是在系統中加入新產品時,無須修改抽象工廠和抽象產品提供的接口,無須修改客戶端,也無須修改其他的具體工廠和具體產品,而只要添加一個具體工廠和具體產品就可以了。這樣,系統的可擴展性也就變得非常好,完全符合“開閉原則”。
工廠方法模式的缺點:
在添加新產品時,需要編寫新的具體產品類,而且還要提供與之對應的具體工廠類,系統中類的個數將成對增加,在一定程度上增加了系統的復雜度,有更多的類需要編譯和運行,會給系統帶來一些額外的開銷。
由于考慮到系統的可擴展性,需要引入抽象層,在客戶端代碼中均使用抽象層進行定義,增加了系統的抽象性和理解難度
工廠方法模式的適用情況
在以下情況下可以使用工廠方法模式:
一個類不知道它所需要的對象的類:在工廠方法模式中,客戶端不需要知道具體產品類的類名,只需要知道所對應的工廠即可,具體的產品對象由具體工廠類創建;客戶端需要知道創建具體產品的工廠類。
一個類通過其子類來指定創建哪個對象:在工廠方法模式中,對于抽象工廠類只需要提供一個創建產品的接口,而由其子類來確定具體要創建的對象,利用面向對象的多態性和里氏代換原則,在程序運行時,子類對象將覆蓋父類對象,從而使得系統更容易擴展。
將創建對象的任務委托給多個工廠子類中的某一個,客戶端在使用時可以無須關心是哪一個工廠子類創建產品子類,需要時再動態指定,可將具體工廠類的類名存儲在配置文件或數據庫中。
工廠方法模式總結
工廠方法模式是簡單工廠模式的進一步抽象和推廣。由于使用了面向對象的多態性,工廠方法模式保持了簡單工廠模式的優點,而且克服了它的缺點。在工廠方法模式中,核心的工廠類不再負責所有產品的創建,而是將具體創建工作交給子類去做。這個核心類僅僅負責給出具體工廠必須實現的接口,而不負責產品類被實例化這種細節,這使得工廠方法模式可以允許系統在不修改工廠角色的情況下引進新產品。
工廠方法模式的主要優點是增加新的產品類時無須修改現有系統,并封裝了產品對象的創建細節,系統具有良好的靈活性和可擴展性;其缺點在于增加新產品的同時需要增加新的工廠,導致系統類的個數成對增加,在一定程度上增加了系統的復雜性。
抽象工廠模式:通過對類的工廠抽象使其業務用于對產品類簇的創建,而不是負責創建某一類產品的實例,屬于對象創建型模式。
抽象類一直出現在我們的文章中,那么這邊先來解釋一下什么是抽象類
抽象類是一種聲明但不能使用的類,當你使用時就會報錯,在JavaScript中abstract還是一個保留字,所以目前來說還不能像
傳統面向對象語言那么輕松的去創建抽象類.
不過JavaScript有自己的實現方式,可以模擬出抽象類
來一段代碼
// 抽象類的介紹 var Ball = function () {} Ball.prototype = { play: function () { return new Error("抽象方法不能調用"); } }
解釋:
我們可以看到創建的Ball類其實什么都不能做,創建時沒有任何屬性,原型定義的方法也不能使用,否則就會報錯。但是在繼承上卻是很有用的,
因為定義了一種類,并定義了該類所具備的方法,如果沒有在子類中重寫這寫方法,那么調用的時候就會報錯。
這一特點可以很好的提醒子類去重寫這一方法,不然會在調用的時候提示錯誤那么在了解了什么是抽象類的情況下,我們在來比較一下工廠方法模式與抽象工廠模式的不同點,以方便我們更好的去理解抽象工廠模式
工廠方法模式與抽象工廠模式的對比
在工廠方法模式中具體工廠負責生產具體的產品,每一個具體工廠對應一種具體產品,工廠方法也具有唯一性,一般情況下,一個具體工廠中只有一個工廠方法或者一組重載的工廠方法。但是有時候我們需要一個工廠可以提供多個產品對象,而不是單一的產品對象。
為了更清晰地理解抽象工廠模式,需要先引入兩個概念:
產品等級結構 :產品等級結構即產品的繼承結構,如一個抽象類是電視機,其子類有海爾電視機、海信電視機、TCL電視機,則抽象電視機與具體品牌的電視機之間構成了一個產品等級結構,抽象電視機是父類,而具體品牌的電視機是其子類。
產品族 :在抽象工廠模式中,產品族是指由同一個工廠生產的,位于不同產品等級結構中的一組產品,如海爾電器工廠生產的
海爾電視機、海爾電冰箱,海爾電視機位于電視機產品等級結構中,海爾電冰箱位于電冰箱產品等級結構中。
抽象工廠模式與工廠方法模式最大的區別在于,工廠方法模式針對的是一個產品等級結構,而抽象工廠模式則需要面對多個產品等級結構,一個工廠等級結構可以負責多個不同產品等級結構中的產品對象的創建。當一個工廠等級結構可以創建出分屬于不同產品等級結構的一個產品族中的所有對象時,抽象工廠模式比工廠方法模式更為簡單、有效率。
這句話比較簡單的理解方式就是:如果一個工廠只需要生產一個類型的產品比如說電視機,那么用工廠方法模式是比較合理的,如果這個工廠又需要成產電視機,又需要生產冰箱之類的,那么這時候用工廠抽象模式就是最合適的。
// # 抽象工廠模式 var Sport = function(subType, superType) { if( typeof Sport[superType] === "function"){ // 緩存類 function F() {}; // 繼承父類屬性和方法 F.prototype = new Sport[superType](); // 將子類constructor 指向子類 subType.constructor = subType; // 子類原型繼承 “父類” subType.prototype = new F(); }else { // 不存在抽象類則拋出錯誤 throw new Error("未創建該抽象類"); } } // 球類運動抽象類 Sport.Ball = function () { this.type = "ball"; } Sport.Ball.prototype = { play: function () { return new Error("抽象方法不能調用"); } } // 力量型運動抽象類 Sport.Power = function () { this.type = "power"; } Sport.Power.prototype = { play: function () { return new Error("抽象方法不能調用"); } } // 速度型運動抽象類 Sport.Speed = function () { this.type = "speed"; } Sport.Speed.prototype = { play: function () { return new Error("抽象方法不能調用"); } } // 籃球類 var BasketBall = function (name) { this.name = name; }; // 抽象工廠實現對球類運動的繼承 Sport(BasketBall,"Ball"); BasketBall.prototype.play = function () { console.log("我在玩"+this.name); } // 舉重類 var WeightLifting = function (name) { this.name = name; }; // 抽象工廠實現對力量型運動的繼承 Sport(WeightLifting,"Power"); WeightLifting.prototype.play = function () { console.log("我在玩"+this.name); } // 跑步類 var Running = function (name) { this.name = name; }; // 抽象工廠實現對速度運動的繼承 Sport(Running,"Speed"); Running.prototype.play = function () { console.log("我在"+this.name); } // 抽象工廠模式實現 var basketBall = new BasketBall("籃球"); console.log(basketBall.type);//ball basketBall.play(); var weightLifting = new WeightLifting("舉重"); console.log(weightLifting.type);//power weightLifting.play(); var running = new Running("跑步"); console.log(running.type);//ball running.play(); /** 輸出結果 * ball * 我在玩籃球 * power * 我在玩舉重 * speed * 我在跑步 */ // # 抽象工廠模式end
這段栗子先是創建一個運動類的抽象工廠,通過這個暴露外部調用的接口,傳遞2個參數,一個是subType,當前實例化的對象,也就是子類,
一個是superType,需要繼承的父類(抽象類)的名稱,在工廠函數中實現了子類對父類的繼承。
在繼承過程中有一個地方需要注意,就是在對過渡類繼承的時候,我們不是繼承父類原型,而是通過new關鍵字復制父類的一個實列,這樣做的目的是過渡類不僅僅繼承父類的原型方法,還需要繼承父類的對象屬性,所以通過new關鍵字的方式實現了繼承。
然后通過在抽象工廠類上面進行擴展對應的抽象類,也就是我們需要通過繼承的父類,我這邊添加了3個抽象類Ball,Power,Speed,分別給抽象類指定了type屬性,還有方法play,既然創建了抽象類,那么下面就是開始使用抽象工廠去創建子類,這邊分別對Ball,Power,Speed 3個抽象類進行了實現創建了BasketBall(球類),WeightLifting(力量),Running(速度)3個子類3個子類分別對play方法進行了實現最后就是對于子類的調用實現,在實現子類調用的時候,
我們可以獲取到繼承的父類當中對應的type
抽象工廠模式的優點:
當一個產品族中的多個對象被設計成一起工作時,它能夠保證客戶端始終只使用同一個產品族中的對象。
增加新的具體工廠和產品族很方便,無須修改已有系統,符合“開閉原則”。
抽象工廠模式的缺點:
開閉原則的傾斜性(增加新的工廠和產品族容易,增加新的產品等級結構麻煩)。
增加新的產品等級結構:對于增加新的產品等級結構,需要修改所有的工廠角色,包括抽象工廠類,在所有的工廠類中都需要增加生產新產品的方法,不能很好地支持“開閉原則”。
抽象工廠模式的適用情況:
在以下情況下可以使用抽象工廠模式:
一個系統不應當依賴于產品類實例如何被創建、組合和表達的細節,這對于所有類型的工廠模式都是重要的。
系統中有多于一個的產品族,而每次只使用其中某一產品族。屬于同一個產品族的產品將在一起使用,這一約束必須在系統的設計中體現出來。
系統提供一個產品類的庫,所有的產品以同樣的接口出現,從而使客戶端不依賴于具體實現。
抽象工廠模式總結
抽象工廠模式是所有形式的工廠模式中最為抽象和最具一般性的一種形態。抽象工廠模式與工廠方法模式最大的區別在于,工廠方法模式針對的是一個產品等級結構,而抽象工廠模式則需要面對多個產品等級結構。
抽象工廠模式適用情況包括:一個系統不應當依賴于產品類實例如何被創建、組合和表達的細節;系統中有多于一個的產品族,而每次只使用其中某一產品族;屬于同一個產品族的產品將在一起使用;系統提供一個產品類的庫,所有的產品以同樣的接口出現,從而使客戶端不依賴于具體實現。
4.三大工廠模式的關聯性當抽象工廠模式中每一個具體工廠類只創建一個產品對象,也就是只存在一個產品等級結構時,抽象工廠模式轉換成工廠方法模式;
當工廠方法模式中抽象工廠與具體工廠合并,提供一個統一的工廠來創建產品對象,并將創建對象的工廠方法設計為靜態方法時,工廠方法模式退化成簡單工廠模式。
注:根據實際適用情況去選擇對應的工廠模式
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/90572.html
摘要:設計模式工廠模式最近閱讀了幾本設計模式方面的書籍學習之余整理下來方便以后的歸納和梳理設計模式工廠模式創造工廠模式是一種創建性模式也就是一種創建對象的最佳實踐首先我們需要理解為什么我們需要工廠模式想象一個場景如果你要求去買一些東西板燒雞腿 Javascript設計模式-工廠模式 最近閱讀了幾本設計模式方面的書籍,學習之余整理下來,方便以后的歸納和梳理 設計模式-工廠模式 創造工廠模式是一...
摘要:從設計模式的分類來看簡單工廠模式是創建型模式。使用簡單工廠模式將會增加系統中類的個數,在一定程序上增加了系統的復雜度和理解難度。簡單工廠模式由于使用了靜態工廠方法,造成工廠角色無法形成基于繼承的等級結構。 簡單工廠模式提供了一個接口可以根據傳遞的參數的不同創建不同的對象,從而將對象自身的邏輯與對象的創建分離開。 從設計模式的分類來看簡單工廠模式是創建型模式。事實上與簡單工廠模式類似的還...
摘要:工廠方法模式,通過對產品類的抽象使其創建業務,主要負責創建多類產品的實例。安全模式類安全模式類可以屏蔽使用類的錯誤造成的錯誤。可以將工廠方法看作是一個實例化對象的工廠類,安全起見,采用安全模式類,將創建對象的基類放在工廠方法類的原型中即可。 工廠方法模式,通過對產品類的抽象使其創建業務,主要負責創建多類產品的實例。前面記錄了簡單工廠模式,但是需求時不斷變化的,當需求簡單時,直接創建對象...
摘要:設計模式共有種,我今天先來了解一下工廠模式,其他的模式將會在后續的博客中陸續為大家講解。工廠模式主要分為簡單工廠模式和抽象工廠模式。抽象工廠模式抽象工廠模式與簡單工廠函數不同的是,抽象工廠函數會先設計好接口,具體的實現在子類中進行。 設計模式 設計模式(design pattern)概念:是一套反復使用、思想成熟、經過分類和無數實戰設計經驗的總結。是為了代碼可重用、可擴展、可解耦、更容...
摘要:都是構造函數模式創建的原生構造函數。使用構造函數創建對象經歷了以下四個過程創建一個新對象構造函數的作用域交給新對象。 ??在創建對象的時候,使用對象字面量和 new Object() 構造函數的方式創建一個對象是最簡單最方便的方式。但是凡是處于初級階段的事物都會不可避免的存在一個問題,沒有普適性,意思就是說我要為世界上(程序中)的所有使用到的對象都使用一遍 var xxx = {} ,...
摘要:都是構造函數模式創建的原生構造函數。使用構造函數創建對象經歷了以下四個過程創建一個新對象構造函數的作用域交給新對象。 ??在創建對象的時候,使用對象字面量和 new Object() 構造函數的方式創建一個對象是最簡單最方便的方式。但是凡是處于初級階段的事物都會不可避免的存在一個問題,沒有普適性,意思就是說我要為世界上(程序中)的所有使用到的對象都使用一遍 var xxx = {} ,...
閱讀 3477·2021-09-22 15:02
閱讀 3524·2021-09-02 15:21
閱讀 2141·2019-08-30 15:55
閱讀 2789·2019-08-30 15:44
閱讀 789·2019-08-29 16:56
閱讀 2422·2019-08-23 18:22
閱讀 3349·2019-08-23 12:20
閱讀 3097·2019-08-23 11:28