Java设计模式 —— 组合模式(Composite)
发布日期:2021-05-06 22:42:21 浏览次数:28 分类:技术文章

本文共 6803 字,大约阅读时间需要 22 分钟。

Java设计模式 —— 组合模式(Composite)

定义

Composite,组合模式:将对象组合成树形结构以表示部分整体的关系,Composite使得用户对单个对象和组合对象的使用具有一致性。

特征:

  1. 树形结构,节点如果没有分支,就是叶子节点;如果存在分支,则是树枝节点
  2. 关键在于它定义了一个抽象构建类,它既可表示叶子对象,也可表示容器对象。就是树枝和叶子实现了统一接口,或树枝和叶子之间有继承关系
  3. 根据所实现接口的区别分为两种形式,分别称为安全方式和透明方式。

代码实现

透明方式:树枝、叶子节点都提供子对象的管理方法,诸如:add()、remove()、以及getChild()等

抽象构件角色类

public abstract class Component {       /**     * 输出组建自身的名称     */    public abstract void printStruct(String preStr);    /**     * 聚集管理方法,增加一个子构件对象     * @param child 子构件对象     */    public void addChild(Component child){           /**         * 缺省实现,抛出异常,因为叶子对象没有此功能         * 或者子组件没有实现这个功能         */        throw new UnsupportedOperationException("对象不支持此功能");    }    /**     * 聚集管理方法,删除一个子构件对象     * @param index 子构件对象的下标     */    public void removeChild(int index){           /**         * 缺省实现,抛出异常,因为叶子对象没有此功能         * 或者子组件没有实现这个功能         */        throw new UnsupportedOperationException("对象不支持此功能");    }        /**     * 聚集管理方法,返回所有子构件对象     */    public List
getChild(){ /** * 缺省实现,抛出异常,因为叶子对象没有此功能 * 或者子组件没有实现这个功能 */ throw new UnsupportedOperationException("对象不支持此功能"); }}

树枝构件角色类,此类将implements Conponent改为extends Conponent,其他地方无变化。

public class Composite extends Component {       /**     * 用来存储组合对象中包含的子组件对象     */    private List
childComponents = new ArrayList
(); /** * 组合对象的名字 */ private String name; /** * 构造方法,传入组合对象的名字 * @param 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
getChild(){ return childComponents; } /** * 输出对象的自身结构 * @param preStr 前缀,主要是按照层级拼接空格,实现向后缩进 */ @Override public void printStruct(String preStr) { // 先把自己输出 System.out.println(preStr + "+" + this.name); //如果还包含有子组件,那么就输出这些子组件对象 if(this.childComponents != null){ //添加两个空格,表示向后缩进两个空格 preStr += " "; //输出当前对象的子对象 for(Component c : childComponents){ //递归输出每个子对象 c.printStruct(preStr); } } }}

树叶构件角色类,此类将implements Conponent改为extends Conponent,其他地方无变化。

public class Leaf extends Component {       /**     * 叶子对象的名字     */    private String name;    /**     * 构造方法,传入叶子对象的名称     * @param name 叶子对象的名字     */    public Leaf(String name){           this.name = name;    }    /**     * 输出叶子对象的结构,叶子对象没有子对象,也就是输出叶子对象的名字     * @param preStr 前缀,主要是按照层级拼接的空格,实现向后缩进     */    @Override    public void printStruct(String preStr) {           // TODO Auto-generated method stub        System.out.println(preStr + "-" + name);    }}

客户端类的主要变化是不再区分Composite对象和Leaf对象。

public class Client {       public static void main(String[]args){           Component root = new Composite("服装");        Component c1 = new Composite("男装");        Component c2 = new Composite("女装");                Component leaf1 = new Leaf("衬衫");        Component leaf2 = new Leaf("夹克");        Component leaf3 = new Leaf("裙子");        Component leaf4 = new Leaf("套装");                root.addChild(c1);        root.addChild(c2);        c1.addChild(leaf1);        c1.addChild(leaf2);        c2.addChild(leaf3);        c2.addChild(leaf4);                root.printStruct("");    }}

可以看出,客户端无需再区分操作的是树枝对象(Composite)还是树叶对象(Leaf)了;对于客户端而言,操作的都是Component对象。

安全方式:树枝都提供子对象的管理方法,叶子节点不提供;也就是抽象类中没有管理方法函数的声明

抽象构件角色类

public interface Component {       /**     * 输出组建自身的名称     */    public void printStruct(String preStr);}

树枝构件角色类

public class Composite implements Component {       /**     * 用来存储组合对象中包含的子组件对象     */    private List
childComponents = new ArrayList
(); /** * 组合对象的名字 */ private String name; /** * 构造方法,传入组合对象的名字 * @param 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
getChild(){ return childComponents; } /** * 输出对象的自身结构 * @param preStr 前缀,主要是按照层级拼接空格,实现向后缩进 */ @Override public void printStruct(String preStr) { // 先把自己输出 System.out.println(preStr + "+" + this.name); //如果还包含有子组件,那么就输出这些子组件对象 if(this.childComponents != null){ //添加两个空格,表示向后缩进两个空格 preStr += " "; //输出当前对象的子对象 for(Component c : childComponents){ //递归输出每个子对象 c.printStruct(preStr); } } }}

树叶构件角色类

public class Leaf implements Component {       /**     * 叶子对象的名字     */    private String name;    /**     * 构造方法,传入叶子对象的名称     * @param name 叶子对象的名字     */    public Leaf(String name){           this.name = name;    }    /**     * 输出叶子对象的结构,叶子对象没有子对象,也就是输出叶子对象的名字     * @param preStr 前缀,主要是按照层级拼接的空格,实现向后缩进     */    @Override    public void printStruct(String preStr) {           // TODO Auto-generated method stub        System.out.println(preStr + "-" + name);    }}

客户端类

public class Client {       public static void main(String[]args){           Composite root = new Composite("服装");        Composite c1 = new Composite("男装");        Composite c2 = new Composite("女装");                Leaf leaf1 = new Leaf("衬衫");        Leaf leaf2 = new Leaf("夹克");        Leaf leaf3 = new Leaf("裙子");        Leaf leaf4 = new Leaf("套装");                root.addChild(c1);        root.addChild(c2);        c1.addChild(leaf1);        c1.addChild(leaf2);        c2.addChild(leaf3);        c2.addChild(leaf4);                root.printStruct("");    }}

可以看出,树枝构件类(Composite)给出了addChild()、removeChild()以及getChild()等方法的声明和实现,而树叶构件类则没有给出这些方法的声明或实现。这样的做法是安全的做法,由于这个特点,客户端应用程序不可能错误地调用树叶构件的聚集方法,因为树叶构件没有这些方法,调用会导致编译错误。

安全式合成模式的缺点是不够透明,因为树叶类和树枝类将具有不同的接口。

组合模式使用问题

优点: 1、高层模块调用简单。 2、节点自由增加。3、客户端可以一致的使用组合结构或其中单个对象。就像Linux一切皆文件。

缺点:

1、在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
2、使设计变得更加抽象,对象的业务规则如果很复杂,则实现组合模式具有很大挑战性,而且不是所有的方法都与叶子对象子类都有关联,会有冗余代码

Android中组合模式

Android源码中,ViewGroup 和 View 就是典型的组合模式。

View相当与叶子节点,里面没有添加删除View等操作。

ViewGroup实际上是View的子类,同时ViewGroup中实现了添加删除View等操作,因此可以作为容器存放view。
实际上ViewGroup中添加了删除View是实现了ViewManager接口中的方法。

感谢

segmentfault:

菜鸟教程:
百度百科:
博客园:
CSDN 郭霖:

上一篇:Java设计模式 —— 享元模式(Flyweight)
下一篇:Java设计模式 —— 桥接模式(Bridge)

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2025年03月22日 04时03分49秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

【最短路】P4408 [NOI2003]逃学的小孩 2019-03-03
2020电工(初级)考试及电工(初级)考试软件 2019-03-03
2020N1叉车司机模拟考试题库及N1叉车司机复审模拟考试 2019-03-03
2020年制冷与空调设备运行操作答案解析及制冷与空调设备运行操作考试总结 2019-03-03
2020年保育员(初级)考试资料及保育员(初级)新版试题 2019-03-03
2020年茶艺师(高级)考试内容及茶艺师(高级)考试申请表 2019-03-03
2021年重氮化工艺考试题库及重氮化工艺考试报名 2019-03-03
2021年车工(高级)考试总结及车工(高级)试题及答案 2019-03-03
2021年压力焊证考试及压力焊实操考试视频 2019-03-03
2021年低压电工考试及低压电工考试申请表 2019-03-03
2021年低压电工考试及低压电工考试申请表 2019-03-03
2021年A特种设备相关管理(电梯)考试APP及A特种设备相关管理(电梯)复审考试 2019-03-03
2021年N1叉车司机考试题及N1叉车司机复审模拟考试 2019-03-03
2021年危险化学品经营单位主要负责人考试APP及危险化学品经营单位主要负责人多少钱 2019-03-03
2021年T电梯修理考试技巧及T电梯修理模拟考试软件 2019-03-03
2021年电工(初级)考试及电工(初级)证考试 2019-03-03
大数据学习之Spark——00Spark项目的pom.xml文件 2019-03-03
从 MFC 移植程序到 wxWidgets 界面库 ——《定时执行专家 5.0》的界面实现 2019-03-03
CodeBlocks开发wxWidgets环境配置详细 2019-03-03
天涯人脉通讯录 - 设计草图 2019-03-03