1. 程式人生 > >JavaScript設計模式——工廠模式

JavaScript設計模式——工廠模式

  在介紹工廠模式之前,首先我們要理解一下什麼是設計模式?什麼是設計原則?

  設計模式:

    通常在我們解決問題的時候,很多時候不是隻有一種方式,我們通常有多種方式來解決;但是肯定會有一種通用且高效的解決方案,這種解決方案在軟體開發中我們稱它為設計模式;

    設計模式並不是一種固定的公式,而是一種思想,是一種解決問題的思路;恰當的使用設計模式,可以實現程式碼的複用和提高可維護性;

  設計原則:

    通常在做很多事情的時候,都會有一定的規範制約;在軟體開發的過程中,我們可以將設計原則視為一種開發規範,但不是必須要遵循的,只是不遵循的話,程式碼後期的維護和複用都會變得很糟糕;

    遵循設計原則可以幫助我們寫出高內聚、低耦合的程式碼,當然程式碼的複用性、健壯性、可維護性也會更好;

 

  有哪些設計模式:

    在程式設計中我們通常認為是有23種設計模式,根據分類分別為:

   建立型:

    1. 抽象工廠模式  
    2. 工廠方法模式
    3. 構建者模式
    4. 原型模式
    5. 單例模式

   結構型:

    1. 介面卡模式
    2. 橋接模式
    3. 組合模式
    4. 裝飾者模式
    5. 外觀模式
    6. 享元模式
    7. 代理模式

  行為型:

    1. 職責鏈模式
    2. 命名模式
    3. 直譯器模式
    4. 迭代器模式
    5. 中介者模式
    6. 備忘錄模式
    7. 觀察者模式
    8. 狀態模式
    9. 策略模式
    10. 訪問者模式
    11. 模板方法模式  

  有哪些設計原則:

    根據英文首單詞我們又稱為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); //聯想 鍵盤

 

  抽象工廠模式一般用於嚴格要求以面向物件思想進行開發的超大型專案中,我們一般常規的開發的話一般就是簡單工廠和工廠方法模式會用的比較多一些;

 

  大白話解釋:簡單工廠模式就是你給工廠什麼,工廠就給你生產什麼;

        工廠方法模式就是你找工廠生產產品,工廠是外包給下級分工廠來代加工,需要先評估一下能不能代加工;能做就接,不能做就找其他工廠;

        抽象工廠模式就是工廠接了某項產品訂單但是做不了,上級集團公司新建一個工廠來專門代加工某項產品;

&n