rwson

rwson

一个前端开发

javascript组合模式

组合模式:

在组合模式中,对象有两种形式,一种是叶子对象,一种是组合对象,其中组合对象是叶子对象的组成,有时候我们需要通过简单的控制来完成工作,组合模式就派上了用场。

下面我们模拟一个场景,模拟公司内部的一个,上级(组合对象)只要交代给部门领导(组合对象),再由部门领导交付具体的指令给具体的员工(叶子对象)来完成具体的工作。

先来看看传统的做法:

/**
  *
  * 公司类
  **/
function Org(name){
    this.name = name;
    this.depts = [];
}
Org.prototype = {
    "constructor":Org,
    "addDepts":function(child){
        this.depts.push(child);
        return this;
        //  添加部门,return this 提供链式调用
    },
    "getDepts":function(){
        return this.depts;
        //  获取部门
    }
};

/**
  *
  * 部门类
  **/
function Dept(name){
    this.name = name;
    this.persons = [];
}
Dept.prototype = {
    "constructor":Dept,
    "addPersons":function(child){
        this.persons.push(child);
        return this;
        //  添加部门员工
    },
    "getPersons":function(){
        return this.persons;
        //  获取部门员工
    }
};

/**
  *
  * 员工类
  **/
function Person(name){
    this.name = name;
}
commonUtil.wrap(Person.prototype,{
    "constructor":Person,
    "hardWorking":function(){
        console.log(this.name + " ... 努力工作!");
        //  xxx ... 努力工作
    },
    "sleeping":function(){
        console.log(this.name + "睡觉!");
        //  xxx 睡觉!
    }
});

var p1 = new Person("张1"),
    p2 = new Person("张2"),
    p3 = new Person("张3"),
    p4 = new Person("张4"),
    p5 = new Person("张5"),
    p6 = new Person("张6"),
    dept1 = new Dept("开发"),
    dept2 = new Dept("销售"),
    org = new Org("某某公司");
//  实例化对象    

dept1.addPersons(p1).addPersons(p2).addPersons(p3);
dept2.addPersons(p4).addPersons(p5).addPersons(p6);
org.addDepts(dept1).addDepts(dept2);
//  添加部门和部门员工

for(var i = 0,depts = org.getDepts();i < depts.length;i ++){
    for(j = 0,persons = depts[i].getPersons();j < persons.length;j ++){
        if(persons[j]["name"] === "张3"){
            persons[j].hardWorking();
        }
    }
}
//  具体的让张3努力工作

在上面的例子我们可以看到,如果想要"张三"这个人执行hardWorking方法,需要写两层循环,现在只是两层结构,要是在多层的情况下,可能就需要递归神马了,甚是麻烦。

再来看看组合模式吧!这边的commomUtil下的方法和工厂模式里面的用的一样的。

var CompositeInterface = new commonUtil.Interface("CompositeInterface",["addChild","getChild"]),
LeafInterface = new commonUtil.Interface("LeafInterface",["hardWorking","sleeping"]);
        //  定义组合对象和叶子对象需要实现的接口
        
/**
 * 组合对象
 * @param name
 * @constructor
 */
function Composite(name){
    this.name = name;
    this.type = "Composite";
    //  说明当前对象类型
    this.children = [];
    //  承装孩子(叶子节点)的数组
}
commonUtil.wrap(Composite.prototype,{
    "constructor":Composite,
    "addChild":function(child){
        this.children.push(child);
        return this;
    },
    "getChild":function(name){
        var list = [],
            pushLeaf = function(item){
                if(this.name === name || item["type"] === "Composite"){
                      item["children"].each(arguments.callee);
                     // pushLeaf(item["children"]);
                }else if(item["type"] === "Leaf") {
                    list.push(item);
                }
            };
        if(name && this.name !== name){
            //  返回指定类型的叶子对象
            this.children.each(function(item){
                if(item["name"] === name && item["type"] === "Composite"){
                    item["children"].each(pushLeaf);
                }
                //  二级节点
                if(item["name"] !== name && item["type"] === "Composite"){
                    item["children"].each(arguments.callee);
                }
                //  三级、四级...
                if(item["name"] === name && item["type"] === "Leaf"){
                    list.push(item);
                }
            });
        }else{
            //  返回所有叶子对象
            this.children.each(pushLeaf);
        }
        return list;
    },
    "hardWorking":function(name){
        var leafObjects = this.getChild(name);
        //  得到所有的叶子类型对象
        for(var i = 0,l = leafObjects.length;i < l;i ++){
            leafObjects[i] && leafObjects[i].hardWorking(leafObjects[i]["name"]);
        }
    },
    "sleeping":function(name){
        var leafObjects = this.getChild(name);
        //  得到所有的叶子类型对象
        for(var i = 0,l = leafObjects.length;i < l;i ++){
            leafObjects[i].sleeping(leafObjects[i]["name"]);
        }
    }
});
    
/**
 * 叶子对象
 * @param name
 * @constructor
 */
function Leaf(name){
    this.name = name;
    this.type = "Leaf";
    //  说明当前对象类型
}
commonUtil.wrap(Leaf.prototype,{
    "constructor":Leaf,
    "addChild":function(child){
        throw new Error("this method is disabled");
        //  叶子节点下没有添加子节点的方法,所以调用的时候抛异常
    },
    "getChild":function(name){
        if(this.name === name){
            return this;
        }
        return null;
    },
    "hardWorking":function(){
        console.log(this.name + " ... 努力工作!");
    },
    "sleeping":function(name){
        console.log(this.name + " ... 睡觉!");
    }
});

var p1 = new Leaf("张1"),
    p2 = new Leaf("张2"),
    p3 = new Leaf("张3"),
    p4 = new Leaf("张4"),
    p5 = new Leaf("张5"),
    p6 = new Leaf("张6"),
    p7 = new Leaf("张7"),
    p8 = new Leaf("张8"),
    p9 = new Leaf("张9"),
    p10 = new Leaf("张10"),
    p11 = new Leaf("张11"),
    p12 = new Leaf("张12"),
    dept1 = new Composite("南京开发部"),
    dept2 = new Composite("南京销售部"),
    dept3 = new Composite("杭州开发部"),
    dept4 = new Composite("杭州销售部"),
    org = new Composite("xx公司"),
    org2 = new Composite("南京分公司"),
    org3 = new Composite("杭州分公司");
    //  实例化一些对象

    dept1.addChild(p1).addChild(p2).addChild(p3);
    dept2.addChild(p4).addChild(p5).addChild(p6);
    dept3.addChild(p7).addChild(p8).addChild(p9);
    dept4.addChild(p10).addChild(p11).addChild(p12);
    //  组装二级、三级、叶子节点

    org2.addChild(dept1).addChild(dept2);
    org3.addChild(dept3).addChild(dept4);
    org.addChild(org2).addChild(org3);
    //  组装分公司和总公司

    org.hardWorking();  
    //  总公司下面的人都执行hardWork方法
    org.hardWorking("南京分公司");  
    //  南京分公司下面的人都执行hardWork方法
    org.hardWorking("杭州开发部");  
    //  某级子节点(组合对象)下面的人都执行hardWork方法
    org.hardWorking("张12");  
    //  具体某人执行hardWork方法

怎么样,看完这个例子是不是感觉比传统的调用方法简单多了,现在就2种类型的对象,虽然组合对象下封装的方法,只要传入具体的某个部门或者员工就能走它下面的方法;这么好的模式,何乐而不为?