(12)设计模式之组合模式

组合模式

组合模式(部分-整体模式):将对象组合成树形结构以表示 ‘ 部分-整体 ’ 的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。


以淘宝首页为例,假设服装节点下包含男装和女装,而男装作为节点又包含了夹克和衬衣,女装包含了裙子和套装,怎么使用代码体现呢?

这种类似于树的结构,可以使用组合模式来实现。

先来看一下以该例子写的组合模式的UML类图
在这里插入图片描述
其中clothes作为抽象类存在,定义了节点的删除增加和展示的方法。
composite继承了Component组件类,用来表示非叶子节点。
leaf同样继承了Component组件类,用来表示叶子节点。

只看UML类图就可以看出来该模式跟装饰模式有异曲同工之妙,装饰模式是具体的组件类和装饰类同级,可以借助接口进行相互调用,而组合模式是叶子类和非叶子类同级,也可以相互调用。

叶子节点和非叶子节点的唯一区别就是能不能继续添加节点,能不能对其子节点进行删除。

来看一下示例性代码:

package ch13.sjms.composite;

public abstract class clothes {//抽象的服装组件类
    protected String name;
    public clothes(String name){
        this.name=name;
    }
    public abstract void Add(clothes c);
    public abstract void Remove(clothes c);
    public abstract void Display(int depth);

}
package ch13.sjms.composite;

import java.util.ArrayList;
import java.util.List;

public class composite extends clothes{//非叶子节点
//由于非叶子节点可能有多个子节点,所以此处使用了List类型
    private List<clothes>children = new ArrayList<clothes>();
    //由于非叶子节点的子节点可能是叶子节点也可能是非叶子节点,所以List类型使用了clothes抽象的组件类
    //用来存放其子节点,保证List中既可以添加叶子节点也可以添加非叶子节点
    public composite(String name){
        super(name);
    }
    @Override
    public void Add(clothes c) {
        children.add(c);
    }

    @Override
    public void Remove(clothes c) {
        children.remove(c);
    }

    @Override
    public void Display(int depth) {
        for (int i = 0; i < depth; i++) {
            System.out.print("-");
        }
        System.out.println(name);//对非叶子节点进行输出的时候,先输出该节点
        for (clothes child : children) {//然后遍历其子节点
            child.Display(depth+2);
        }
    }
}
package ch13.sjms.composite;

public class leaf extends clothes{//叶子节点
    public leaf(String name){
        super(name);
    }
    @Override
    public void Add(clothes c) {
        System.out.println("不能添加树叶了!");
    }

    @Override
    public void Remove(clothes c) {
        System.out.println("不能移除树叶了");
    }

    @Override
    public void Display(int depth) {
        for (int i = 0; i < depth; i++) {
            System.out.print("-");
        }
        System.out.println(name);
    }
}
package ch13.sjms.composite;

public class client {
    public static void main(String[] args) {
        clothes root = new composite("服装");
        clothes clothes1 = new composite("男装");
        clothes clothes2 = new composite("女装");

        clothes1.Add(new leaf("夹克"));
        clothes1.Add(new leaf("衬衣"));

        clothes2.Add(new leaf("裙子"));
        clothes2.Add(new leaf("套装"));

        root.Add(clothes1);
        root.Add(clothes2);
        root.Display(1);

    }
}

看完UML类图再看代码,不难看出,UML类图中leaf类明明没有Add和Remove方法,虽然这两个方法对于叶子节点没有什么实际意义,可是代码中还是写了出来。

在上述代码中体现的组合模式的方式叫做透明方式。也就是说在Component中生命所有用来管理子对象的方法,其中包括Add、Remove等。这样实现Component接口的所有子类都具备了Add和Remove。这样做的好处就是叶节点和枝节点对于外界没有区别,它们具备完全一样的行为接口。但问题也很明显,因为leaf类本身不具备Add、Remove方法,所以实现它们是没有意义的。

和透明方式相对的就是安全方式。也就是在Component接口中不去声明Add和Remove方法,那么子类leaf也不需要去实现它,而是在Composite声明所有用来管理子类对象的方法,这样就不会出现透明方式提到的问题。不过由于不够透明,所以树叶和树枝类将不具有相同的接口,客户端调用还需要做相应的判断,带来了不便。

在开发的时候,应该结合实际情况而作出选择。

需求中是体现部分与整体层次的结构时,希望用户可以忽略组合对象与单个对象的不同,统一使用组合结构中的所有对象时,就应该考虑用组合模式。

组合模式定义了包含基本对象和组合对象的类层次结构。基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断地递归下去,客户代码中,任何用到基本对象地地方都可以使用组合对象了。

用户是不用关心到底是处理一个叶节点还是处理一个组合组件,也就用不着为定义组合而写一些选择判断语句了。也就是说,组合模式让客户可以一致地使用组合结构和单个对象。

组合模式的缺点:很难限制组合中的组件类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值