Java设计模式之合成模式

合成模式(composite pattern): 允许你将对象组合成树形结构来表现”整体/部分”层次结构. 合成模式能让客户以一致的方式处理个别对象以及对象组合.

合成模式的实现根据所实现接口的区别分为两种形式:安全式和透明式

安全式合成模式的详解

类图:
这里写图片描述

角色说明:
抽象构件角色(Component):这是一个抽象角色,它给参加组合的对象定义出公共的接口及其默认行为,可以用来管理所有的子对象。合成对象通常把它所包含的子对象当做类型为Component的对象。在安全式的合成模式里,构件角色并不定义出管理子对象的方法,这一定义由数字构件对象给出。

叶子构件角色(Leaf):叶子对象是没有下级子对象的对象,定义出参加组合的原始对象行为。

树枝构件角色(Composite):代表参加组合的又下级子对象的对象,树枝构件类给出所有的管理子对象的方法,如add()、remove()和getChild()。

代码演示,抽象构件类:

public interface Component {
    // 输出结构的名称
    public void showStructure(String str);
}

树枝构件类:

public class Composite implements Component {
    // 用来存储合成对象中的子构件对象
    private List<Component> childComponents = new ArrayList<>();
    // 合成对象的名称
    private String name;

    public Composite(String name) {
        this.name = name;
    }

    /**
     * 增加一个子构件对象
     * 
     * @param child
     */
    public void addChild(Component child) {
        childComponents.add(child);
    }

    /**
     * 移除一个子构件对象
     * 
     * @param index
     */
    public void removeChild(int index) {
        childComponents.remove(index);
    }

    // 获取所有子构件对象
    public List<Component> getChild() {
        return childComponents;
    }

    /**
     * 输出结构的名称
     */
    @Override
    public void showStructure(String str) {
        // 首先输出最高级构件
        System.out.println(str + "●" + this.name);
        // 如果含有子构件,则输出
        if (this.childComponents != null) {
            // 子构件向后缩进显示
            str += "   ";
            // 输出当前对象的子构件对象
            for (Component c : childComponents) {
                // 递归输出每个子对象
                c.showStructure(str);
            }
        }

    }

}

叶子对象类:

public class Leaf implements Component {
    // 叶子对象的名称
    private String name;

    public Leaf(String name) {
        this.name = name;
    }

    /**
     * 输出叶子构件的对象,叶子已经是最低级构件,所以只显示叶子名称就行
     */
    @Override
    public void showStructure(String str) {
        str += "   ";
        System.out.println(str + "〉" + name);
    }

}

测试类:

public class Client {
    public static void main(String[] args) {
        //声明最高级构件
        Composite root = new Composite("宠物");
        //子构件
        Composite dog = new Composite("宠物狗");
        Composite cat = new Composite("宠物猫");

        //添加子构件
        root.addChild(dog);
        root.addChild(cat);

        //声明叶子对象
        Leaf leaf1 = new Leaf("柴犬");
        Leaf leaf2 = new Leaf("二哈");

        //添加叶子对象
        dog.addChild(leaf1);
        dog.addChild(leaf2);

        Leaf leaf3 = new Leaf("波斯猫");
        Leaf leaf4 = new Leaf("咖菲猫");
        Leaf leaf5 = new Leaf("机器猫");

        cat.addChild(leaf3);
        cat.addChild(leaf4);
        cat.addChild(leaf5);

        root.showStructure("");

        System.out.println("====================");
        //移除不是动物的猫
        cat.removeChild(2);
        root.showStructure("");

    }
}

运行结果:
这里写图片描述

从类图和代码可以看出树枝构件类Composite都实现了addChild()、removeChild()和getChild()的方法,而叶子构件类则没有。这是安全式合成模式的特点,因为这个特点,客户端不可能调用到叶子构件类的这些方法,因为叶子构件类根本没有这些方法。

透明式合成模式的详解

类图:
这里写图片描述

代码演示,抽象构件类:

public abstract class Component {
    // 输出构件的名称
    public abstract void showStructure(String str);

    /**
     * 增加一个子构件对象
     * 
     * @param child
     */
    public void addChild(Component child) {

        // 叶子构件类没有此功能,若缺省实现,则抛出异常
        throw new UnsupportedOperationException("对象不支持此操作");
    }

    /**
     * 移除一个子构件对象
     * 
     * @param index
     */
    public void removeChild(int index) {

        // 叶子构件类没有此功能,若缺省实现,则抛出异常
        throw new UnsupportedOperationException("对象不支持此操作");
    }

    // 获取所有子构件对象
    public List<Component> getChild() {

        // 叶子构件类没有此功能,若缺省实现,则抛出异常
        throw new UnsupportedOperationException("对象不支持此操作");
    }
}

树枝构件类:

public class Composite extends Component {
    // 用来存储合成对象中的子构件对象
    private List<Component> childComponents = new ArrayList<>();
    // 合成对象的名称
    private String name;

    public Composite(String name) {
        this.name = name;
    }

    /**
     * 增加一个子构件对象
     * 
     * @param child
     */
    @Override
    public void addChild(Component child) {
        childComponents.add(child);
    }

    /**
     * 移除一个子构件对象
     * 
     * @param index
     */
    @Override
    public void removeChild(int index) {
        childComponents.remove(index);
    }

    // 获取所有子构件对象
    @Override
    public List<Component> getChild() {
        return childComponents;
    }

    /**
     * 输出结构的名称
     */
    @Override
    public void showStructure(String str) {
        // 首先输出最高级构件
        System.out.println(str + "●" + this.name);
        // 如果含有子构件,则输出
        if (this.childComponents != null) {
            // 子构件向后缩进显示
            str += "   ";
            // 输出当前对象的子构件对象
            for (Component c : childComponents) {
                // 递归输出每个子对象
                c.showStructure(str);
            }
        }

    }

}

叶子构件类:

public class Leaf extends Component {
    // 叶子对象的名称
    private String name;

    public Leaf(String name) {
        this.name = name;
    }

    /**
     * 输出叶子构件的对象,叶子已经是最低级构件,所以只显示叶子名称就行
     */
    @Override
    public void showStructure(String str) {
        str += "   ";
        System.out.println(str + "〉" + name);
    }

}

测试类:

public class Client {
    public static void main(String[] args) {
        //声明最高级构件
        Component root = new Composite("宠物");
        //子构件
        Component dog = new Composite("宠物狗");
        Component cat = new Composite("宠物猫");

        //添加子构件
        root.addChild(dog);
        root.addChild(cat);

        //声明叶子对象,这时不再区分Composite或Leaf对象了
        Component leaf1 = new Leaf("柴犬");
        Component leaf2 = new Leaf("二哈");

        //添加叶子对象
        dog.addChild(leaf1);
        dog.addChild(leaf2);

        Component leaf3 = new Leaf("波斯猫");
        Component leaf4 = new Leaf("咖菲猫");
        Component leaf5 = new Leaf("机器猫");

        cat.addChild(leaf3);
        cat.addChild(leaf4);
        cat.addChild(leaf5);

        root.showStructure("");

        System.out.println("====================");
        //移除不是动物的猫
        cat.removeChild(2);
        root.showStructure("");

    }
}

运行结果跟安全式的一样:
这里写图片描述

合成模式的安全式和透明式的选择

安全式:从客户端使用上看,安全式就不会发生误操作的可能。

透明式:从客户端使用上看,透明式是不用区分树枝对象和叶子对象。

合成模式的目的是让客户端不区分操作的是树枝对象还是叶子对象,而是统一的方式来操作。还有,对于安全式的实现,区分树枝和叶子对象的情况下,有时需要类型强转,这种体现就不安全了。所以综合考虑还是着重选择透明式合成模式的实现。当然这不是绝对的,还是要看具体需求的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值