組合模式設(shè)計

一、設(shè)計模式

javascript里面給我們提供了很多種設(shè)計模式:

工廠、橋、組合、門面、適配器、裝飾者、享元、代理、觀察者、命令、責(zé)任鏈

在前面我們實(shí)現(xiàn)了工廠模式和橋模式

工廠模式 :

核心:為了生產(chǎn)對象,實(shí)現(xiàn)解耦。

橋接模式 :

(橋接模式是一種既能把兩個對象連接在一起,又能避免二者間的強(qiáng)耦合的方法。通過“橋”把彼此聯(lián)系起來,同時又允許他們各自獨(dú)立變化)

主要作用:主要作用表現(xiàn)為將抽象與其實(shí)現(xiàn)隔離開來,以便二者獨(dú)立化。

組合模式 :

(組合模式是一種專門為創(chuàng)建Web上的動態(tài)用戶界面而量身制定的模式。使用這種模式可以用一條命令在多個對象上激發(fā)復(fù)雜的或遞歸的行為。這可以簡化粘合性代碼,使其更容易維護(hù),而那些復(fù)雜行為則被委托給各個對象。)

優(yōu)點(diǎn) :

1 你可以用同樣的方法處理對象的集合與其中的特定子對象。

2 它可以用來把一批子對象組織成樹形結(jié)構(gòu),并且使整棵樹都可以被遍歷。

場景 :

1 存在一批組織成某種層次體系的對象

2 希望對這批對象或其中的一部分對象實(shí)施一個操作。

特點(diǎn) :

1 組合模式中只有兩種類型對象:組合對象、葉子對象

2 這兩種類型都實(shí)現(xiàn)同一批接口

3 一般我們會在組合對象中調(diào)用其方法并隱式調(diào)用"下級對象"的方法(這里我們一般采用遞歸的形式去做)

后面的模式后面具體用到在細(xì)說

看實(shí)例:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>組合設(shè)計模式</title>
        
        <!-- 
        @theme: javascript高級 組合模式設(shè)計
        @autor:EthanCoco
        @date:2015-11-22
        @email:lijianlin0204@163.com
        -->
        
        
        
        <script type=text/javascript charset=utf-8>
        //創(chuàng)建一個命名空間
        var LJL = {};
        
        /**
        *建一個接口
        *接口需要兩個參數(shù)
        *參數(shù)1: 接口的名字(string)
        *參數(shù)2: 方法名稱(數(shù)組(string))
        */
        LJL.Interface = function(name,methods){
            if(arguments.length !== 2){//判斷接口參數(shù)個數(shù)是否正確
                throw new Error("參數(shù)個數(shù)不正確!");
            }
            this.name = name;
            this.methods = [];//定義一個內(nèi)置的空數(shù)組接受方法名稱里的元素
            for(var i = 0;i < methods.length;i++){
                if(typeof methods[i] !== 'string'){
                    throw new Error("方法名稱錯誤,必須是字符串類型!");
                }
                //把傳入?yún)?shù)的元素全部放到內(nèi)置的methods中去
                this.methods.push(methods[i]);
            }
            
        };
        
        /**
        *接口靜態(tài)方法
        *參數(shù):object
        *檢驗(yàn)接口里的方法是否實(shí)現(xiàn)
        *如果通過不做任何操作,如果不通過,拋出error
        *目的:檢測方法是否全部實(shí)現(xiàn)
        *object 要求參數(shù)必須有兩個以上
        *一個是對象實(shí)例
        *其它是要檢驗(yàn)的接口對象
        */
        LJL.Interface.checkMethodsIsPass = function(object){
            if(arguments.length < 2){//判斷參數(shù),如果參數(shù)小于2,拋出異常
                throw new Error("要求參數(shù)必須有兩個以上@param1=實(shí)例對象,其它參數(shù)是接口對象!");
            }
            //獲得接口實(shí)例對象
            for(var i = 1;i<arguments.length;i++){//i=1是因?yàn)榈诙€參數(shù)是需要檢測的接口
                var  instanceInterface = arguments[i];
                //判斷參數(shù)是否是接口對象
                if(instanceInterface.constructor !== LJL.Interface){
                    throw new Error("參數(shù)是不是接口對象!");
                }
                //如果是,檢測接口對象里的方法是否實(shí)現(xiàn)
                for(var j = 0;j<instanceInterface.methods.length;j++){
                    //用歷史變量接受一個方法的名稱,名稱是字符串,如果不是就拋出error
                    var methodName = instanceInterface.methods[j];
                    //object[key]表示的就是方法
                    //方法是一個函數(shù),需要判斷
                    if(!object[methodName] || typeof object[methodName] !== 'function'){
                        throw new Error("這個方法 '" + methodName + "' 找不到!");
                    } 
                }
            
            }
            
        };
        
        /**
         * 繼承方法
         * @param {Object} sub
         * @param {Object} sup
         */    
        /*
        LJL.extend=function(sub ,sup){
             // 目的: 實(shí)現(xiàn)只繼承父類的原型對象
             var F = new Function();    // 1 創(chuàng)建一個空函數(shù)    目的:空函數(shù)進(jìn)行中轉(zhuǎn)
             F.prototype = sup.prototype; // 2 實(shí)現(xiàn)空函數(shù)的原型對象和超類的原型對象轉(zhuǎn)換
             sub.prototype = new F();     // 3 原型繼承 
             sub.prototype.constructor = sub ; // 4還原子類的構(gòu)造器
             //保存一下父類的原型對象: 一方面方便解耦  另一方面方便獲得父類的原型對象
             sub.superClass = sup.prototype; //自定義一個子類的靜態(tài)屬性 接受父類的原型對象
             //判斷父類的原型對象的構(gòu)造器 (加保險)
             if(sup.prototype.constructor == Object.prototype.constructor){
                sup.prototype.constructor = sup ; //手動歡迎父類原型對象的構(gòu)造器
             }
        };
        */
        /**
         * 擴(kuò)展Array的原型對象 添加變量數(shù)組的每一個元素,并讓每一個元素都執(zhí)行fn函數(shù) (可變量多維數(shù)組)
         * @param {Object} fn
         */
        Array.prototype.each = function(fn){
            try{
                //1 目的: 遍歷數(shù)組的每一項(xiàng) //計數(shù)器 記錄當(dāng)前遍歷的元素位置
                this.i || (this.i=0);  //var i = 0 ;
                //2 嚴(yán)謹(jǐn)?shù)呐袛嗍裁磿r候去走each核心方法
                // 當(dāng)數(shù)組的長度大于0的時候 && 傳遞的參數(shù)必須為函數(shù)
                if(this.length >0 && fn.constructor == Function){
                    // 循環(huán)遍歷數(shù)組的每一項(xiàng)
                    while(this.i < this.length){    //while循環(huán)的范圍 
                        //獲取數(shù)組的每一項(xiàng)
                        var e = this[this.i];
                        //如果當(dāng)前元素獲取到了 并且當(dāng)前元素是一個數(shù)組
                        if(e && e.constructor == Array){
                            // 直接做遞歸操作
                            e.each(fn);
                        } else {
                            //如果不是數(shù)組 (那就是一個單個元素)
                            // 這的目的就是為了把數(shù)組的當(dāng)前元素傳遞給fn函數(shù) 并讓函數(shù)執(zhí)行
                            //fn.apply(e,[e]);
                            fn.call(e,e);
                        }
                        this.i++ ;
                    }
                    this.i = null ; // 釋放內(nèi)存 垃圾回收機(jī)制回收變量
                }
                
            } catch(ex){
                // do something 
            }
            return this ;
        }

        /********************************************************/
        ////////////////////////////////////////////////
        //以上都是為設(shè)計模式做必要的準(zhǔn)備
        ////////////////////////////////////////////////
        
        
        //開始組合設(shè)計模式
        
        
        /**
          *  組合模式應(yīng)用的場景和特點(diǎn):
          *  場景:
          *  1 存在一批組織成某種層次體系的對象
          *  2 希望對這批對象或其中的一部分對象實(shí)施一個操作
          *  
          *  應(yīng)用特點(diǎn):
          *  1 組合模式中只有兩種類型對象:組合對象、葉子對象
          *  2 這兩種類型都實(shí)現(xiàn)同一批接口
          *  3 一般我們會在組合對象中調(diào)用其方法并隱式調(diào)用"下級對象"的方法(這里我們一般采用遞歸的形式去做)
          * 
          */                
        /*
         * 場景模擬:
         *  -> 公司 
         *       -> 北京分公司
         *                    -> 財務(wù)部門
         *                                -> 張1
         *                                -> 張2
         *                                -> 張3
         *                    -> 銷售部門
         *                                -> 張4
         *                                -> 張5
         *                                -> 張6
                 -> 長沙分公司 
         *                    -> 財務(wù)部門
         *                                -> 張7
         *                                -> 張8
         *                                -> 張9
         *                    -> 銷售部門
         *                                -> 張10
         *                                -> 張11
         *                                -> 張12                     
         *    
         *    實(shí)際的任務(wù)具體是落實(shí)到人上去實(shí)施的 也就是說只有人才具有具體的方法實(shí)現(xiàn)
         */        
        
        //創(chuàng)建組合對象的接口實(shí)例
        var CompositeInterface = new LJL.Interface('CompositeInterface' , ['addChild','getChild']);
        //創(chuàng)建葉子對象的接口實(shí)例
        var LeafInterface = new LJL.Interface('LeafInterface' , ['hardworking','sleeping']);
        /********************************************************/
        
        
        
        /***********************組合對象*********************************/
        //首先 : 組合模式中只有兩種類型對象:組合對象、葉子對象
        //創(chuàng)建組合對象
        var Composite = function(name){
            this.name = name;
            this.type = 'Composite';        //說明對象的類型(組合對象)
            this.children = [] ;             //承裝孩子的數(shù)組
            //然后 :這兩種類型都實(shí)現(xiàn)同一批接口
            //創(chuàng)建對象的最后要驗(yàn)證接口
            LJL.Interface.checkMethodsIsPass(this,CompositeInterface,LeafInterface);
        };
        
        //在原型對象上實(shí)現(xiàn)接口方法
        Composite.prototype = {
            constructor:Composite , //還原構(gòu)造器
            //實(shí)現(xiàn)CompositeInterface接口的addChildh和getChild方法
            addChild:function(child){
            //添加子節(jié)點(diǎn)到children上
                this.children.push(child);
                return this;//返回控制權(quán),實(shí)現(xiàn)鏈?zhǔn)讲僮?            },
            getChild:function(name){
                //定義一個數(shù)組接受葉子對象類型
                var elements = [] ;
                //判斷對象是否是葉子對象類型,如果是添加到數(shù)組中去
                //如果不是,則運(yùn)用遞歸繼續(xù)調(diào)用
                var pushLeaf = function(item){
                    if(item.type === 'Composite'){
                            item.children.each(arguments.callee);
                    } else if(item.type === 'Leaf'){
                            elements.push(item);
                    }
                };
                
                // 根據(jù)name 讓指定name下的所有的類型為Leaf的對象去執(zhí)行操作
                if(name && this.name !== name){ 
                    this.children.each(function(item){
                        // 如果傳遞的name是2級節(jié)點(diǎn)名稱
                        if(item.name === name && item.type === 'Composite'){
                            item.children.each(pushLeaf);
                        }
                        // 如果傳遞的name是3級節(jié)、4級、5級...N級 
                        if(item.name !== name && item.type === 'Composite'){
                            item.children.each(arguments.callee);
                        }
                        // 如果傳遞的name是葉子節(jié)點(diǎn)的時候
                        if(item.name === name && item.type === 'Leaf'){
                            elements.push(item);
                        }
                    });
                }else{  // 不傳遞name 讓整個公司所有類型為Leaf的對象去執(zhí)行操作
                    this.children.each(pushLeaf);
                }
                return elements ;
            },
            //實(shí)現(xiàn)LeafInterface接口的hardworking和sleeping方法
            hardworking:function(name){
                //得到所有的Leaf類型的對象數(shù)組
                var leafObjects = this.getChild(name);
                for(var i = 0 ; i < leafObjects.length; i ++){
                    leafObjects[i].hardworking();
                }
            },
            sleeping:function(name){
                //得到所有的Leaf類型的對象數(shù)組
                var leafObjects = this.getChild(name);
                for(var i = 0 ; i < leafObjects.length; i ++){
                    leafObjects[i].sleeping();
                }            
            }
        };
        /***********************組合對象*********************************/
        
        /***********************葉子對象*********************************/
        //同樣在葉子原型對象上實(shí)現(xiàn)接口方法
        var Leaf = function(name){
            this.name = name;
            this.type = 'Leaf';        //說明對象的類型(葉子對象)
            //創(chuàng)建對象的最后要驗(yàn)證接口
            LJL.Interface.checkMethodsIsPass(this,CompositeInterface,LeafInterface);
        };
        
        Leaf.prototype = {
            constructor:Leaf ,//還原構(gòu)造器
            //實(shí)現(xiàn)CompositeInterface接口的addChildh和getChild方法
            addChild:function(child){
            //讓其不能使用這個方法
                throw new Error('this method is disabled....');
            },
            getChild:function(name){
                if(this.name = name){
                    return this ; 
                }
                return null ;
            },
            //實(shí)現(xiàn)LeafInterface接口的hardworking和sleeping方法
            hardworking:function(){
                document.write(this.name + '...努力工作!');
            },
            sleeping:function(){
                document.write(this.name + '...努力睡覺!');
            }                
        }; 
         /***********************葉子對象*********************************/
         
         
         /***********************測試單元*********************************/
         //測試數(shù)據(jù)
         //創(chuàng)建人的葉子對象
         var p1 = new Leaf('張1');
         var p2 = new Leaf('張2');
         var p3 = new Leaf('張3');
         var p4 = new Leaf('張4');
         var p5 = new Leaf('張5');
         var p6 = new Leaf('張6');
         var p7 = new Leaf('張7');
         var p8 = new Leaf('張8');
         var p9 = new Leaf('張9');
         var p10 = new Leaf('張10');
         var p11 = new Leaf('張11');
         var p12 = new Leaf('張12');
         
         //創(chuàng)建公司部門
         var dept1 = new Composite('北京開發(fā)部門');
         //把p1,p2,p3三個人指定到dept1中去
         dept1.addChild(p1).addChild(p2).addChild(p3);
         var dept2 = new Composite('北京銷售部門');
         dept2.addChild(p4).addChild(p5).addChild(p6);
         var dept3 = new Composite('長沙開發(fā)部門');
         dept3.addChild(p7).addChild(p8).addChild(p9);
         var dept4 = new Composite('長沙銷售部門');
         dept4.addChild(p10).addChild(p11).addChild(p12);    
         
         //創(chuàng)建組織分公司
         var org1 = new Composite('北京分公司');
         //把dept1和dept2指定到org1中去
         org1.addChild(dept1).addChild(dept2);    
         var org2 = new Composite('長沙分公司');
         org2.addChild(dept3).addChild(dept4);    
         
         //創(chuàng)建總部
         var org = new Composite('尚學(xué)堂總部');
         //把分公司掛到總部
         org.addChild(org1).addChild(org2);
         
                     
         // 讓整個公司下所有的員工都去努力工作
         org.hardworking();     //尚學(xué)堂總部
         document.write('<Br>----------------------------------<Br>');
         // name為總公司的直接子節(jié)點(diǎn)的時候
         org.hardworking('長沙分公司');
         document.write('<Br>----------------------------------<Br>');
         // name為總公司的間接子節(jié)點(diǎn)的時候(類型不為leaf)(3級4級...N級)
         org.hardworking('長沙開發(fā)部門');
         document.write('<Br>----------------------------------<Br>');    
         // name為leaf對象的時候
         org.hardworking('張5');
         document.write('<Br>----------------------------------<Br>');                         
        /***********************測試單元*********************************/
        </script>
    </head>
    <body>
    </body>
</html>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1 場景問題# 1.1 發(fā)送提示消息## 考慮這樣一個實(shí)際的業(yè)務(wù)功能:發(fā)送提示消息?;旧纤袔I(yè)務(wù)流程處理的系統(tǒng)...
    七寸知架構(gòu)閱讀 5,217評論 5 63
  • 一、使用組合模式的場景 把部分和整體的關(guān)系用樹形結(jié)構(gòu)來表示,從而使客戶端可以用統(tǒng)一的方式處理部分對象和整體對象 二...
    yjaal閱讀 425評論 0 0
  • 設(shè)計模式匯總 一、基礎(chǔ)知識 1. 設(shè)計模式概述 定義:設(shè)計模式(Design Pattern)是一套被反復(fù)使用、多...
    MinoyJet閱讀 4,074評論 1 15
  • 一、設(shè)計模式的分類 總體來說設(shè)計模式分為三大類: 創(chuàng)建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者...
    RamboLI閱讀 825評論 0 1
  • 【今日種下的與此目標(biāo)相關(guān)的種子】 1. 早晨持續(xù)給龍稱法王日行一善捐款,讓慈悲心逐日成長,讓每天的這滴水融入大海以...
    李鮮花閱讀 496評論 0 4

友情鏈接更多精彩內(nèi)容