在介紹工廠模式之前,首先我們要理解一下什么是設計模式?什么是設計原則?
設計模式:
通常在我們解決問題的時候,很多時候不是只有一種方式,我們通常有多種方式來解決;但是肯定會有一種通用且高效的解決方案,這種解決方案在軟件開發中我們稱它為設計模式;
設計模式並不是一種固定的公式,而是一種思想,是一種解決問題的思路;恰當的使用設計模式,可以實現代碼的復用和提高可維護性;
設計原則:
通常在做很多事情的時候,都會有一定的規范制約;在軟件開發的過程中,我們可以將設計原則視為一種開發規范,但不是必須要遵循的,只是不遵循的話,代碼后期的維護和復用都會變得很糟糕;
遵循設計原則可以幫助我們寫出高內聚、低耦合的代碼,當然代碼的復用性、健壯性、可維護性也會更好;
有哪些設計模式:
在程序設計中我們通常認為是有23種設計模式,根據分類分別為:
創建型:
-
- 抽象工廠模式
- 工廠方法模式
- 建造者模式
- 原型模式
- 單例模式(又稱單體模式)
結構型:
-
- 適配器模式
- 橋接模式
- 組合模式
- 裝飾者模式
- 外觀模式
- 享元模式
- 代理模式
行為型:
-
- 職責鏈模式
- 命令模式
- 解釋器模式
- 迭代器模式
- 中介者模式
- 備忘錄模式
- 觀察者模式(又稱發布/訂閱模式)
- 狀態模式
- 策略模式
- 訪問者模式
- 模板方法模式
有哪些設計原則:
根據英文首單詞我們又稱為S.O.L.I.D.設計原則,一共有5種設計原則,根據分類分別為:
1、S(Single responsibility principle)——單一職責原則
一個程序或一個類或一個方法只做好一件事,如果功能過於復雜,我們就拆分開,每個方法保持獨立,減少耦合度;
2、O(Open Closed Principle)——開放封閉原則
對擴展開放,對修改封閉;增加新需求的時候,我們需要做的是增加新代碼,而非去修改源碼;
例如:我們在使用vue框架的時候,有很多第三方插件我們可以去使用,在使用的時候我們通常都是直接在vue-cli中增加引入代碼,而非去修改vue源碼來達到支持某種功能的目的;
3、L(Liskov Substitution Principle, LSP)——李氏置換原則
子類能覆蓋父類,父類能出現的地方子類就能出現;(在JS中沒有類概念,使用較少)
4、I (Interface Segregation Principle)——接口獨立原則
保持接口的單一獨立,類似於單一原則,不過接口獨立原則更注重接口;(在JS中沒有接口概念)
5、D(Dependence Inversion Principle ,DIP)——依賴倒置原則
面向接口編程,依賴於抽象而不依賴於具體,使用方只關注接口而不需要關注具體的實現;(JS中沒有接口概念)
作為前端開發人員來說,我們用的最多的設計原則是S(單一職責原則).O(開放封閉原則),所以在程序設計的時候我們重點關注這兩個即可 ;
設計模式——工廠模式:
所謂工廠模式就是像工廠一樣重復的產生類似的產品,工廠模式只需要我們傳入正確的參數,就能生產類似的產品;
工廠模式根據抽象程度依次分為簡單工廠模式、工廠方法模式、抽象工廠模式;
簡單工廠模式:
在我們的生活中很多時候就有這樣的場景,像在網站中有的頁面是需要根據賬號等級來決定是否有瀏覽權限的;賬號等級越高可瀏覽的就越多,反之就越少;
// JS設計模式之簡單工廠 function factory(role){ function superAdmin(){ this.name="超級管理員"; this.viewPage=["首頁","發現頁","通訊錄","應用數據","權限管理"]; } function admin(){ this.name="管理員"; this.viewPage=["首頁","發現頁","通訊錄","應用數據"]; } function user(){ this.name="普通用戶"; this.viewPage=["首頁","發現頁","通訊錄"]; } switch(role){ case "superAdmin": return new superAdmin(); break; case "admin": return new admin(); break; case "user": return new user(); break; } } let superAdmin = factory("superAdmin"); console.log(superAdmin); let admin = factory("admin"); console.log(admin); let user = factory("user"); console.log(user);
上述代碼中,factory就是一個工廠,factory有三個函數分別是對應不同的產品,switch中有三個選項,這三個選項相當於三個模具,當匹配到其中的模具之后,將會new一個構造函數去執行生產工廠中的function;但是我們發現上面的簡單工廠模式會有一定的局限性,就是如果我們需要去添加新的產品的時候,我們需要去修改兩處位置(需要修改function和switch)才能達到添加新產品的目的;
下面我們將簡單工廠模式進行改良:
// JS設計模式之簡單工廠改良版 function factory(role){ function user(opt){ this.name = opt.name; this.viewPage = opt.viewPage; } switch(role){ case "superAdmin": return new user({name:"superAdmin",viewPage:["首頁","發現頁","通訊錄","應用數據","權限管理"]}); break; case "admin": return new user({name:"admin",viewPage:["首頁","發現頁","通訊錄","應用數據"]}); break; case "normal": return new user({name:"normal",viewPage:["首頁","發現頁","通訊錄"]}); } } let superAdmin = factory("superAdmin"); console.log(superAdmin); let admin = factory("admin"); console.log(admin); let normal = factory("normal"); console.log(normal);
經過上面的修改之后,我們工廠里面的函數相當於一個萬能摸具,switch里面給我什么,我就加工成什么樣的;自然就解決了添加商品需要修改兩處代碼的問題;
工廠方法模式:
工廠方法模式是將創建對象的工作推到子類中進行;也就是相當於工廠總部不生產產品了,交給下轄分工廠進行生產;但是進入工廠之前,需要有個判斷來驗證你要生產的東西是否是屬於我們工廠所生產范圍,如果是,就丟給下轄工廠來進行生產,如果不行,那么要么新建工廠生產要么就生產不了;
// JS設計模式之工廠方法模式 function factory(role){ if(this instanceof factory){ var a = new this[role](); return a; }else{ return new factory(role); } } factory.prototype={ "superAdmin":function(){ this.name="超級管理員"; this.viewPage=["首頁","發現頁","通訊錄","應用數據","權限管理"]; }, "admin":function(){ this.name="管理員"; this.viewPage=["首頁","發現頁","通訊錄","應用數據"]; }, "user":function(){ this.name="普通用戶"; this.viewPage=["首頁","發現頁","通訊錄"]; } } let superAdmin = factory("superAdmin"); console.log(superAdmin); let admin = factory("admin"); console.log(admin); let user = factory("user"); console.log(user);
工廠方法模式關鍵核心代碼就是工廠里面的判斷this是否屬於工廠,也就是做了分支判斷,這個工廠只做我能生產的產品,如果你的產品我目前做不了,請找其他工廠代加工;
抽象工廠模式:
如果說上面的簡單工廠和工廠方法模式的工作是生產產品,那么抽象工廠模式的工作就是生產工廠的;
舉個例子:代理商找工廠進行合作,但是工廠沒有實際加工能力來進行代加工某產品;無奈又簽署了合同,這時,工廠上面的集團公司就出面了,集團公司承認該工廠是該集團下屬公司,所以集團公司就重新建造一個工廠來進行代加工某商品以達到履行合約;
//JS設計模式之抽象工廠模式 let agency = function(subType, superType) { //判斷抽象工廠中是否有該抽象類 if(typeof agency[superType] === 'function') { function F() {}; //繼承父類屬性和方法 F.prototype = new agency[superType] (); console.log(F.prototype); //將子類的constructor指向子類 subType.constructor = subType; //子類原型繼承父類 subType.prototype = new F(); } else { throw new Error('抽象類不存在!') } } //鼠標抽象類 agency.mouseShop = function() { this.type = '鼠標'; } agency.mouseShop.prototype = { getName: function(name) { // return new Error('抽象方法不能調用'); return this.name; } } //鍵盤抽象類 agency.KeyboardShop = function() { this.type = '鍵盤'; } agency.KeyboardShop.prototype = { getName: function(name) { // return new Error('抽象方法不能調用'); return this.name; } } //普通鼠標子類 function mouse(name) { this.name = name; this.item = "買我,我線長,玩游戲賊溜" } //抽象工廠實現鼠標類的繼承 agency(mouse, 'mouseShop'); //子類中重寫抽象方法 // mouse.prototype.getName = function() { // return this.name; // } //普通鍵盤子類 function Keyboard(name) { this.name = name; this.item = "行,你買它吧,沒鍵盤看你咋玩"; } //抽象工廠實現鍵盤類的繼承 agency(Keyboard, 'KeyboardShop'); //子類中重寫抽象方法 // Keyboard.prototype.getName = function() { // return this.name; // } //實例化鼠標 let mouseA = new mouse('聯想'); console.log(mouseA.getName(), mouseA.type,mouseA.item); //聯想 鼠標 //實例化鍵盤 let KeyboardA = new Keyboard('聯想'); console.log(KeyboardA.getName(), KeyboardA.type,KeyboardA.item); //聯想 鍵盤
抽象工廠模式一般用於嚴格要求以面向對象思想進行開發的超大型項目中,我們一般常規的開發的話一般就是簡單工廠和工廠方法模式會用的比較多一些;
大白話解釋:簡單工廠模式就是你給工廠什么,工廠就給你生產什么;
工廠方法模式就是你找工廠生產產品,工廠是外包給下級分工廠來代加工,需要先評估一下能不能代加工;能做就接,不能做就找其他工廠;
抽象工廠模式就是工廠接了某項產品訂單但是做不了,上級集團公司新建一個工廠來專門代加工某項產品;