设计模式——组合模式

组合模式

定义:组合模式(Composite Pattern)将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户可以使用一致的方法操作单个对象和组合对象。
UML图:

image

(1)Component:抽象根节点,为组合中的对象声明接口。在适当的情况下,实现所有类共有接口的缺省行为。声明一个接口用于访问和管理Component的子节点。可在递归结构中定义一个接口,用于访问一个父节点,并在合适的情况下实现它。

(2)Composite:定义有子节点的那些枝干节点行为,存储子节点,在Component接口中实现与子节点有关的操作。

(3)Leaf:在组合中表示叶子节点对象,叶子节点没有子节点,在组合中定义节点对象的行为。

(4)Client:通过Component接口操纵组合节点的对象。

适用场景:

● 维护和展示部分-整体关系的场景,如树形菜单、文件和文件夹管理。

● 从一个整体中能够独立出部分模块或功能的场景。

安全组合模式

即是上面的UML图
安全组合模式中,在抽象构件Component中没有声明任何用于管理成员对象的方法,而是在Composite类中声明并实现这些方法。这种做法是安全的,因为根本不向叶子对象提供这些管理成员对象的方法,对于叶子对象,客户端不可能调用到这些方法,所以是安全。

举例:一个公司的架构层次
Member即是上面的Component

public abstract class Member {
    public String mName;
    public int mLevel;

    public Member(String name) {
        mName = name;
    }

    public abstract void descript();
    public abstract String getInfo();

    public void setLevel(int level) {
        mLevel = level;
    }

    public void setName(String name) {
        mName = name;
    }


}

部门,也是公司的一个”Member”,是Composite

public class Branch extends Member {
    public List<Member> mMembers = new ArrayList<>();

    public Branch(String name) {
        super(name);
    }

    @Override
    public void descript() {
        String str = "";
        for(int i = 0; i < mLevel; i++){
            str += "....";
        }
        System.out.println(str + getInfo());
        for(Member member : mMembers){
            member.descript();//遍历每一个分支
        }
    }

    @Override
    public String getInfo() {
        if(mLevel == 0){
            return "公司名称:" + mName;
        }
        return "部门名称:" + mName + " 部门人数:" + mMembers.size();
    }

    public void addMember(Member member){
        member.setLevel(mLevel + 1);
        mMembers.add(member);
    }

    public void removeMember(Member member){
        mMembers.remove(member);
    }

    public String getName() {
        return mName;
    }
}

普通员工,也就是Leaf

public class Worker extends Member {
    public Worker(String name) {
        super(name);
    }

    @Override
    public void descript() {
        String str = "";
        for(int i = 0; i < mLevel; i++){
            str += "....";
        }
        System.out.println(str + getInfo());
    }

    @Override
    public String getInfo() {
        return "职级:" + mLevel + " 姓名:" + mName;
    }
}

测试代码:

public class TextCompany {
    public static void main(String args[]){
        Branch company = new Branch("美丽人生公司");
        company.setLevel(0);

        Member member = new Worker("执行总裁");
        Branch technology = new Branch("技术部门");
        Branch product = new Branch("产品部门");
        Branch operation = new Branch("运营部门");
        //违反依赖倒置原则
        company.addMember(member);
        company.addMember(technology);
        company.addMember(product);
        company.addMember(operation);

        technology.addMember(new Worker("程序猿1"));
        technology.addMember(new Worker("程序猿2"));
        technology.addMember(new Worker("程序猿3"));
        technology.addMember(new Worker("程序猿4"));

        product.addMember(new Worker("产品经理1"));
        product.addMember(new Worker("产品经理2"));

        operation.addMember(new Worker("运营专员1"));
        operation.addMember(new Worker("运营专员2"));
        operation.addMember(new Worker("运营专员3"));

        company.descript();

    }
}

输出公司架构:

公司名称:美丽人生公司
....职级:1 姓名:执行总裁
....部门名称:技术部门 部门人数:4
........职级:2 姓名:程序猿1
........职级:2 姓名:程序猿2
........职级:2 姓名:程序猿3
........职级:2 姓名:程序猿4
....部门名称:产品部门 部门人数:2
........职级:2 姓名:产品经理1
........职级:2 姓名:产品经理2
....部门名称:运营部门 部门人数:3
........职级:2 姓名:运营专员1
........职级:2 姓名:运营专员2
........职级:2 姓名:运营专员3

安全组合模式违反了 6 个设计模式原则中依赖倒置原则,客户端不应该直接依赖于具体实现,而应该依赖于抽象,既然是面向接口编程,就应该把更多的焦点放在接口的设计上,于是这样就产生了透明的组合模式。
比如上面的addmember操作,依赖于Branch具体类,而不是依赖于接口。一旦Branch有改变,客户端也需要做相对应改变,比如把add方法名改了,就客户端所有的调用add的地方都要修改。

透明组合模式

和安全的组合模式差异就是在将 Composite 的操作放到了 Component 中,这就造成 Leaf 角色也要实现 Component 中的所有方法。实现的代码做出相应改变:

UML图如下:

image

举例子:一个公司的人员组织架构
公共的Component:包含所有客户需要的操作方法

public abstract class Member {
    public String mName;
    public int mLevel;

    public Member(String name) {
        mName = name;
    }

    public abstract void descript();
    public abstract String getInfo();

    public void setLevel(int level) {
        mLevel = level;
    }

    public void setName(String name) {
        mName = name;
    }

    public abstract void addMember(Member member);

    public abstract void removeMember(Member member);
}

公司管理层,即树干

public class Leader extends Member {

    private List<Member> mMembers = new ArrayList<>();

    public Leader(String name) {
        super(name);
    }

    @Override
    public void descript() {
        String str = "";
        for(int i = 0; i < mLevel; i++){
            str += "....";
        }
        System.out.println(str + getInfo());
        for(Member member : mMembers){
            member.descript();//遍历部下
        }
    }

    @Override
    public String getInfo() {
        return "职级:" + mLevel + " 名称:" + mName + " 直接下属:" + mMembers.size() + "个";
    }

    @Override
    public void addMember(Member member) {
        member.setLevel(mLevel + 1);
        mMembers.add(member);
    }

    @Override
    public void removeMember(Member member) {

    }
}

普通员工:也要实现Component所有方法

public class Worker extends Member {
    public Worker(String name) {
        super(name);
    }

    @Override
    public void descript() {
        String str = "";
        for(int i = 0; i < mLevel; i++){
            str += "....";
        }
        System.out.println(str + getInfo());
    }

    @Override
    public String getInfo() {
        return "职级:" + mLevel + " 姓名:" + mName;
    }

    @Override
    public void addMember(Member member) {

    }

    @Override
    public void removeMember(Member member) {

    }

}

测试:

public class TestTransparent {
    public static void main(String args[]){
        Member ceo = new Leader("总裁");
        ceo.setLevel(1);

        Member cto = new Leader("技术总监");
        Member cpo = new Leader("产品总监");
        Member coo = new Leader("运营总监");

        ceo.addMember(cto);
        ceo.addMember(cpo);
        ceo.addMember(coo);

        cto.addMember(new Worker("程序猿1"));
        cto.addMember(new Worker("程序猿2"));
        cto.addMember(new Worker("程序猿3"));
        cto.addMember(new Worker("程序猿4"));

        cpo.addMember(new Worker("产品经理1"));
        cpo.addMember(new Worker("产品经理2"));

        coo.addMember(new Worker("运营专员1"));
        coo.addMember(new Worker("运营专员2"));
        coo.addMember(new Worker("运营专员3"));

        ceo.descript();
    }
}

输出结果:

....职级:1 名称:总裁 直接下属:3........职级:2 名称:技术总监 直接下属:4............职级:3 姓名:程序猿1
............职级:3 姓名:程序猿2
............职级:3 姓名:程序猿3
............职级:3 姓名:程序猿4
........职级:2 名称:产品总监 直接下属:2............职级:3 姓名:产品经理1
............职级:3 姓名:产品经理2
........职级:2 名称:运营总监 直接下属:3............职级:3 姓名:运营专员1
............职级:3 姓名:运营专员2
............职级:3 姓名:运营专员3

由于是在 Component 类中定义了所有的行为,所以客户端就不用直接依赖于具体 Composite 和 Leaf 类的实现,遵循了依赖倒置原则——依赖抽象,而不依赖具体实现。但是也违反了单一职责原则与接口隔离原则让 Leaf 类继承了它本不应该有的方法,这样做的目的就是为了客户端可以透明的去调用对应组件的方法,将枝干节点和子节点一视同仁。

另外,将 Component 写成一个虚基类,并且实现所有的 Composite 方法(空方法),只让 Composite 去覆盖重写父类的方法,而 Leaf 类就不需要去实现 Composite 的相关方法,这么去实现当然也是可以的。

总结

View和ViewGroup就是组合模式的实现,不过View的视图层级使用的是安全的组合模式。ViewGroup相对于View增加了addView、removeView、getChildAt等方法.

优点

(1)组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,他让高层模块忽略了层次的差异,方便对整个层次结构进行控制。

(2)简化了高层模块的代码。

(3)在组合模式中增加新的枝干构件和叶子构件都很方便,无须对现有类库进行修改,符合“开闭原则”。

(4)对树形结构的控制变得简单。

缺点

组合模式不容易限制组合中的构件。因为大多数情况下,它们都来自于相同的抽象层,此时,必须进行类型检查来实现,这个实现过程较为复杂,比如我worker类后来有添加了一个TemWorker,无法静态(即编译时)判断添加到Branch的是一个worker还是TemWorker,只能在添加的时候动态(运行时候,比如用instanceof)的判断。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值