JavaScript高级---组合模式设计

一、设计模式

javascript里面给我们提供了很多种设计模式:

工厂、桥、组合、门面、适配器、装饰者、享元、代理、观察者、命令、责任链

在前面我们实现了工厂模式和桥模式

工厂模式 :

核心:为了生产对象,实现解耦。

桥接模式 :

(桥接模式是一种既能把两个对象连接在一起,又能避免二者间的强耦合的方法。通过“桥”把彼此联系起来,同时又允许他们各自独立变化)

主要作用:主要作用表现为将抽象与其实现隔离开来,以便二者独立化。

组合模式 :

(组合模式是一种专门为创建Web上的动态用户界面而量身制定的模式。使用这种模式可以用一条命令在多个对象上激发复杂的或递归的行为。这可以简化粘合性代码,使其更容易维护,而那些复杂行为则被委托给各个对象。)

优点 :

1 你可以用同样的方法处理对象的集合与其中的特定子对象。

2 它可以用来把一批子对象组织成树形结构,并且使整棵树都可以被遍历。

场景 :

1 存在一批组织成某种层次体系的对象

2 希望对这批对象或其中的一部分对象实施一个操作。

特点 :

1 组合模式中只有两种类型对象:组合对象、叶子对象

2 这两种类型都实现同一批接口

3 一般我们会在组合对象中调用其方法并隐式调用"下级对象"的方法(这里我们一般采用递归的形式去做)

后面的模式后面具体用到在细说

看实例:

<!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>组合设计模式</title>

        <!--
        @theme: javascript高级 组合模式设计
        @autor:EthanCoco
        @date:2015-11-22
        @email:[email protected]
        -->

        <script type=text/javascript charset=utf-8>
        //创建一个命名空间
        var LJL = {};

        /**
        *建一个接口
        *接口需要两个参数
        *参数1: 接口的名字(string)
        *参数2: 方法名称(数组(string))
        */
        LJL.Interface = function(name,methods){
            if(arguments.length !== 2){//判断接口参数个数是否正确
                throw new Error("参数个数不正确!");
            }
            this.name = name;
            this.methods = [];//定义一个内置的空数组接受方法名称里的元素
            for(var i = 0;i < methods.length;i++){
                if(typeof methods[i] !== ‘string‘){
                    throw new Error("方法名称错误,必须是字符串类型!");
                }
                //把传入参数的元素全部放到内置的methods中去
                this.methods.push(methods[i]);
            }

        };

        /**
        *接口静态方法
        *参数:object
        *检验接口里的方法是否实现
        *如果通过不做任何操作,如果不通过,抛出error
        *目的:检测方法是否全部实现
        *object 要求参数必须有两个以上
        *一个是对象实例
        *其它是要检验的接口对象
        */
        LJL.Interface.checkMethodsIsPass = function(object){
            if(arguments.length < 2){//判断参数,如果参数小于2,抛出异常
                throw new Error("要求参数必须有两个以上@param1=实例对象,其它参数是接口对象!");
            }
            //获得接口实例对象
            for(var i = 1;i<arguments.length;i++){//i=1是因为第二个参数是需要检测的接口
                var  instanceInterface = arguments[i];
                //判断参数是否是接口对象
                if(instanceInterface.constructor !== LJL.Interface){
                    throw new Error("参数是不是接口对象!");
                }
                //如果是,检测接口对象里的方法是否实现
                for(var j = 0;j<instanceInterface.methods.length;j++){
                    //用历史变量接受一个方法的名称,名称是字符串,如果不是就抛出error
                    var methodName = instanceInterface.methods[j];
                    //object[key]表示的就是方法
                    //方法是一个函数,需要判断
                    if(!object[methodName] || typeof object[methodName] !== ‘function‘){
                        throw new Error("这个方法 ‘" + methodName + "‘ 找不到!");
                    }
                }

            }

        };

        /**
         * 继承方法
         * @param {Object} sub
         * @param {Object} sup
         */
        /*
        LJL.extend=function(sub ,sup){
             // 目的: 实现只继承父类的原型对象
             var F = new Function();    // 1 创建一个空函数    目的:空函数进行中转
             F.prototype = sup.prototype; // 2 实现空函数的原型对象和超类的原型对象转换
             sub.prototype = new F();     // 3 原型继承
             sub.prototype.constructor = sub ; // 4还原子类的构造器
             //保存一下父类的原型对象: 一方面方便解耦  另一方面方便获得父类的原型对象
             sub.superClass = sup.prototype; //自定义一个子类的静态属性 接受父类的原型对象
             //判断父类的原型对象的构造器 (加保险)
             if(sup.prototype.constructor == Object.prototype.constructor){
                sup.prototype.constructor = sup ; //手动欢迎父类原型对象的构造器
             }
        };
        */
        /**
         * 扩展Array的原型对象 添加变量数组的每一个元素,并让每一个元素都执行fn函数 (可变量多维数组)
         * @param {Object} fn
         */
        Array.prototype.each = function(fn){
            try{
                //1 目的: 遍历数组的每一项 //计数器 记录当前遍历的元素位置
                this.i || (this.i=0);  //var i = 0 ;
                //2 严谨的判断什么时候去走each核心方法
                // 当数组的长度大于0的时候 && 传递的参数必须为函数
                if(this.length >0 && fn.constructor == Function){
                    // 循环遍历数组的每一项
                    while(this.i < this.length){    //while循环的范围
                        //获取数组的每一项
                        var e = this[this.i];
                        //如果当前元素获取到了 并且当前元素是一个数组
                        if(e && e.constructor == Array){
                            // 直接做递归操作
                            e.each(fn);
                        } else {
                            //如果不是数组 (那就是一个单个元素)
                            // 这的目的就是为了把数组的当前元素传递给fn函数 并让函数执行
                            //fn.apply(e,[e]);
                            fn.call(e,e);
                        }
                        this.i++ ;
                    }
                    this.i = null ; // 释放内存 垃圾回收机制回收变量
                }

            } catch(ex){
                // do something
            }
            return this ;
        }

        /********************************************************/
        ////////////////////////////////////////////////
        //以上都是为设计模式做必要的准备
        ////////////////////////////////////////////////

        //开始组合设计模式

        /**
          *  组合模式应用的场景和特点:
          *  场景:
          *  1 存在一批组织成某种层次体系的对象
          *  2 希望对这批对象或其中的一部分对象实施一个操作
          *
          *  应用特点:
          *  1 组合模式中只有两种类型对象:组合对象、叶子对象
          *  2 这两种类型都实现同一批接口
          *  3 一般我们会在组合对象中调用其方法并隐式调用"下级对象"的方法(这里我们一般采用递归的形式去做)
          *
          */
        /*
         * 场景模拟:
         *  -> 公司
         *       -> 北京分公司
         *                    -> 财务部门
         *                                -> 张1
         *                                -> 张2
         *                                -> 张3
         *                    -> 销售部门
         *                                -> 张4
         *                                -> 张5
         *                                -> 张6
                 -> 长沙分公司
         *                    -> 财务部门
         *                                -> 张7
         *                                -> 张8
         *                                -> 张9
         *                    -> 销售部门
         *                                -> 张10
         *                                -> 张11
         *                                -> 张12
         *
         *    实际的任务具体是落实到人上去实施的 也就是说只有人才具有具体的方法实现
         */        

        //创建组合对象的接口实例
        var CompositeInterface = new LJL.Interface(‘CompositeInterface‘ , [‘addChild‘,‘getChild‘]);
        //创建叶子对象的接口实例
        var LeafInterface = new LJL.Interface(‘LeafInterface‘ , [‘hardworking‘,‘sleeping‘]);
        /********************************************************/

        /***********************组合对象*********************************/
        //首先 : 组合模式中只有两种类型对象:组合对象、叶子对象
        //创建组合对象
        var Composite = function(name){
            this.name = name;
            this.type = ‘Composite‘;        //说明对象的类型(组合对象)
            this.children = [] ;             //承装孩子的数组
            //然后 :这两种类型都实现同一批接口
            //创建对象的最后要验证接口
            LJL.Interface.checkMethodsIsPass(this,CompositeInterface,LeafInterface);
        };

        //在原型对象上实现接口方法
        Composite.prototype = {
            constructor:Composite , //还原构造器
            //实现CompositeInterface接口的addChildh和getChild方法
            addChild:function(child){
            //添加子节点到children上
                this.children.push(child);
                return this;//返回控制权,实现链式操作
            },
            getChild:function(name){
                //定义一个数组接受叶子对象类型
                var elements = [] ;
                //判断对象是否是叶子对象类型,如果是添加到数组中去
                //如果不是,则运用递归继续调用
                var pushLeaf = function(item){
                    if(item.type === ‘Composite‘){
                            item.children.each(arguments.callee);
                    } else if(item.type === ‘Leaf‘){
                            elements.push(item);
                    }
                };

                // 根据name 让指定name下的所有的类型为Leaf的对象去执行操作
                if(name && this.name !== name){
                    this.children.each(function(item){
                        // 如果传递的name是2级节点名称
                        if(item.name === name && item.type === ‘Composite‘){
                            item.children.each(pushLeaf);
                        }
                        // 如果传递的name是3级节、4级、5级...N级
                        if(item.name !== name && item.type === ‘Composite‘){
                            item.children.each(arguments.callee);
                        }
                        // 如果传递的name是叶子节点的时候
                        if(item.name === name && item.type === ‘Leaf‘){
                            elements.push(item);
                        }
                    });
                }else{  // 不传递name 让整个公司所有类型为Leaf的对象去执行操作
                    this.children.each(pushLeaf);
                }
                return elements ;
            },
            //实现LeafInterface接口的hardworking和sleeping方法
            hardworking:function(name){
                //得到所有的Leaf类型的对象数组
                var leafObjects = this.getChild(name);
                for(var i = 0 ; i < leafObjects.length; i ++){
                    leafObjects[i].hardworking();
                }
            },
            sleeping:function(name){
                //得到所有的Leaf类型的对象数组
                var leafObjects = this.getChild(name);
                for(var i = 0 ; i < leafObjects.length; i ++){
                    leafObjects[i].sleeping();
                }
            }
        };
        /***********************组合对象*********************************/

        /***********************叶子对象*********************************/
        //同样在叶子原型对象上实现接口方法
        var Leaf = function(name){
            this.name = name;
            this.type = ‘Leaf‘;        //说明对象的类型(叶子对象)
            //创建对象的最后要验证接口
            LJL.Interface.checkMethodsIsPass(this,CompositeInterface,LeafInterface);
        };

        Leaf.prototype = {
            constructor:Leaf ,//还原构造器
            //实现CompositeInterface接口的addChildh和getChild方法
            addChild:function(child){
            //让其不能使用这个方法
                throw new Error(‘this method is disabled....‘);
            },
            getChild:function(name){
                if(this.name = name){
                    return this ;
                }
                return null ;
            },
            //实现LeafInterface接口的hardworking和sleeping方法
            hardworking:function(){
                document.write(this.name + ‘...努力工作!‘);
            },
            sleeping:function(){
                document.write(this.name + ‘...努力睡觉!‘);
            }
        };
         /***********************叶子对象*********************************/

         /***********************测试单元*********************************/
         //测试数据
         //创建人的叶子对象
         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‘);

         //创建公司部门
         var dept1 = new Composite(‘北京开发部门‘);
         //把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(‘长沙开发部门‘);
         dept3.addChild(p7).addChild(p8).addChild(p9);
         var dept4 = new Composite(‘长沙销售部门‘);
         dept4.addChild(p10).addChild(p11).addChild(p12);    

         //创建组织分公司
         var org1 = new Composite(‘北京分公司‘);
         //把dept1和dept2指定到org1中去
         org1.addChild(dept1).addChild(dept2);
         var org2 = new Composite(‘长沙分公司‘);
         org2.addChild(dept3).addChild(dept4);    

         //创建总部
         var org = new Composite(‘尚学堂总部‘);
         //把分公司挂到总部
         org.addChild(org1).addChild(org2);

         // 让整个公司下所有的员工都去努力工作
         org.hardworking();     //尚学堂总部
         document.write(‘<Br>----------------------------------<Br>‘);
         // name为总公司的直接子节点的时候
         org.hardworking(‘长沙分公司‘);
         document.write(‘<Br>----------------------------------<Br>‘);
         // name为总公司的间接子节点的时候(类型不为leaf)(3级4级...N级)
         org.hardworking(‘长沙开发部门‘);
         document.write(‘<Br>----------------------------------<Br>‘);
         // name为leaf对象的时候
         org.hardworking(‘张5‘);
         document.write(‘<Br>----------------------------------<Br>‘);
        /***********************测试单元*********************************/
        </script>
    </head>
    <body>
    </body>
</html>
时间: 2024-12-25 10:27:13

JavaScript高级---组合模式设计的相关文章

JavaScript高级---门面模式设计

门面模式 两个作用: 1.简化类的接口 2.消除类与使用它的客户代码之间的耦合 门面模式常常是开发人员最亲密的朋友.它几乎是所有javascript库的核心原则 门面模式的目的是为了让开发人员用更简单的方法调用一些相对复杂或组合的方法,主要就是简化开发的复杂性,提供一个相对容易的API去调用内部的方法供外界去使用,这样程序员开发会变得轻松些,编写一次组合代码后可以反复的去使用它,有助于节省时间和精力 注意: 不要滥用门面模式,所以使用你心仪的门面之前一定要三思而定,搞不好你就会小题大做 引入概念

JavaScript高级---工厂模式设计

1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <ti

javascript高级程序设计---模式设计

1.工厂方式 创建对象car var oCar = new Object; oCar.color = "red"; oCar.doors = 4; oCar.mpg = 23; oCar.showColor = function(){ alert(this.corlor); }; 创建多个car function createCar(color, doors, mpg) { var tempcar = new Object; tempcar.color = color; tempcar

javascript设计模式-组合模式

组合模式所要解决的问题: 可以使用简单的对象组合成复杂的对象,而这个复杂对象有可以组合成更大的对象.可以把简单这些对象定义成类,然后定义一些容器类来存储这些简单对象. 客户端代码必须区别对象简单对象和容器对象,而实际上大多数情况下用户认为它们是一样的.对这些类区别使用,使得程序更加复杂.递归使用的时候跟麻烦,而我们如何使用递归组合, 使得用户不必对这些类进行区别呢? 概念: 将对象组合成树形结构以表示“部分-整体”的层次结构.Composite使得用户对单个对象和组合对象的使用具有一致性. 有时

设计模式:组合模式(Composite)

将对象组合成属性结构以表示"部分-总体"的层次结构.组合使得用户和单个对象和组合对象的使用具有一致性. 组合模式设计的角色: 1. Component:是组合中的对象声明接口.在适当的情况下.实现全部类共同拥有接口的默认行为.声明一个接口用于訪问和管理Component. 2. Leaf:在组合中表示叶子节点对象.叶子节点没有子节点. 3. Composite:定义树枝节点行为.用来存储子部件.在Component接口中实现与子部件有关操作,如增加和删除等. 举个简单样例(树枝和叶子)

java设计模式之组合模式

树形结构在软件中随处可见,例如操作系统中的目录结构.应用软件中的菜单.办公系统中的公司组织结构等等,如何运用面向对象的方式来处理这种树形结构是组合模式需要解决的问题,组合模式通过一种巧妙的设计方案使得用户可以一致性地处理整个树形结构或者树形结构的一部分,也可以一致性地处理树形结构中的叶子节点(不包含子节点的节点)和容器节点(包含子节点的节点).下面将学习这种用于处理树形结构的组合模式. 11.1 设计杀毒软件的框架结构 Sunny软件公司欲开发一个杀毒(AntiVirus)软件,该软件既可以对某

JavaScript高级---装饰者模式设计

一.设计模式 javascript里面给我们提供了很多种设计模式: 工厂.桥.组合.门面.适配器.装饰者.享元.代理.观察者.命令.责任链 在前面我们实现了工厂模式和桥模式 工厂模式 : 核心:为了生产对象,实现解耦. 桥接模式 : (桥接模式是一种既能把两个对象连接在一起,又能避免二者间的强耦合的方法.通过“桥”把彼此联系起来,同时又允许他们各自独立变化) 主要作用:主要作用表现为将抽象与其实现隔离开来,以便二者独立化. 组合模式 : (组合模式是一种专门为创建Web上的动态用户界面而量身制定

javascript设计模式学习之十——组合模式

一.组合模式定义及使用场景 组合模式将对象组合成树形结构,用以表示“部分—整体”的层次结构,除了用来表示树形结构之外,组合模式还可以利用对象的多态性表现,使得用户对单个对象和组合对象的使用具有一致性. 实现组合模式的关键: 在java等静态语言中,需要单个对象和组合对象都实现同样的抽象接口,这可以通过抽象类或者接口来实现. 在javascript中,对象的多态性是与生俱来的,没有编译器去检查对象的类型,因此实现组合模式的要点是保证组合兑现个单个对象用友同样的方法,这通常需要使用“鸭子类型”的思想

深入理解JavaScript系列(40):设计模式之组合模式

介绍 组合模式(Composite)将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性. 常见的场景有asp.net里的控件机制(即control里可以包含子control,可以递归操作.添加.删除子control),类似的还有DOM的机制,一个DOM节点可以包含子节点,不管是父节点还是子节点都有添加.删除.遍历子节点的通用功能.所以说组合模式的关键是要有一个抽象类,它既可以表示子元素,又可以表示父元素. 正文 举个例子,有家餐厅提供了各种各