组合模式

概述

叶子节点进行相关的操作。

可以将这颗树理解成一个大的容器,容器里面包含很多的成员对象,这些成员对象即可是容器对象也可以是叶子对象。

但是由于容器对象和叶子对象在功能上面的区别,使得我们在使用的过程中必须要区分容器对象和叶子对象,但是这样就会给客户带来不必要的麻烦,

作为客户而已,它始终希望能够一致的对待容器对象和叶子对象

定义:

又名部分整体模式,是用于把一组相似的对象当作一个单一的对象。

组合模式依据树形结构来组合对象,用来表示部分以及整体层次。

这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。

5.6.2 结构

组合模式主要包含三种角色:

  • 抽象根节点(Component):定义系统各层次对象的共有方法和属性,可以预先定义一些默认行为和属性。
  • 树枝节点(Composite):定义树枝节点的行为,存储子节点,组合树枝节点和叶子节点形成一个树形结构。
  • 叶子节点(Leaf):叶子节点对象,其下再无分支,是系统层次遍历的最小单位。

5.6.3 案例实现

【例】软件菜单

如下图,我们在访问别的一些管理系统时,经常可以看到类似的菜单。

一个菜单可以包含菜单项(菜单项是指不再包含其他内容的菜单条目),也可以包含带有其他菜单项的菜单,

因此使用组合模式描述菜单就很恰当,我们的需求是针对一个菜单,打印出其包含的所有菜单以及菜单项的名称。

要实现该案例,我们先画出类图:

代码实现:

不管是菜单还是菜单项,都应该继承自统一的接口,这里姑且将这个统一的接口称为菜单组件。



MenuComponent.java

package com.itheima.pattern.combination;/*** @version v1.0* @ClassName: MenuComponent* @Description: 菜单组件 : 属于抽象根节点* @Author: dym*/
public abstract class MenuComponent {//菜单组件的名称protected String name;//菜单组件的层级protected int level;//添加子菜单public void add(MenuComponent menuComponent) {throw new UnsupportedOperationException();}//移除子菜单public void remove(MenuComponent menuComponent) {throw new UnsupportedOperationException();}//获取指定的子菜单public MenuComponent getChild(int index) {throw new UnsupportedOperationException();}//获取菜单或者菜单项的名称public String getName() {return name;}//打印菜单名称的方法(包含子菜单和字菜单项)public abstract void print();
}

MenuItem.java

package com.itheima.pattern.combination;import com.itheima.principles.demo1.SougouInput;/*** @version v1.0* @ClassName: MenuItem* @Description: 菜单项类 : 属于叶子节点* @Author: dym*/
public class MenuItem extends MenuComponent {public MenuItem(String name,int level) {this.name = name;this.level = level;}public void print() {//打印菜单项的名称for(int i = 0; i < level; i++) {System.out.print("--");}System.out.println(name);}
}

Menu.java

package com.itheima.pattern.combination;import java.util.ArrayList;
import java.util.List;/*** @version v1.0* @ClassName: Menu* @Description: 菜单类  : 属于树枝节点* @Author: dym*/
public class Menu extends MenuComponent {//菜单可以有多个子菜单或者子菜单项private List<MenuComponent> menuComponentList = new ArrayList<MenuComponent>();//构造方法public Menu(String name,int level) {this.name = name;this.level = level;}@Overridepublic void add(MenuComponent menuComponent) {menuComponentList.add(menuComponent);}@Overridepublic void remove(MenuComponent menuComponent) {menuComponentList.remove(menuComponent);}@Overridepublic MenuComponent getChild(int index) {return menuComponentList.get(index);}@Overridepublic void print() {//打印菜单名称for(int i = 0; i < level; i++) {System.out.print("--");}System.out.println(name);//打印子菜单或者子菜单项名称for (MenuComponent component : menuComponentList) {component.print();}}
}

Client.java

package com.itheima.pattern.combination;/*** @version v1.0* @ClassName: Client* @Description: TODO(一句话描述该类的功能)* @Author: dym*/
public class Client {public static void main(String[] args) {//创建菜单树MenuComponent menu1 = new Menu("菜单管理",2);menu1.add(new MenuItem("页面访问",3));menu1.add(new MenuItem("展开菜单",3));menu1.add(new MenuItem("编辑菜单",3));menu1.add(new MenuItem("删除菜单",3));menu1.add(new MenuItem("新增菜单",3));MenuComponent menu2 = new Menu("权限管理",2);menu2.add(new MenuItem("页面访问",3));menu2.add(new MenuItem("提交保存",3));MenuComponent menu3 = new Menu("角色管理",2);menu3.add(new MenuItem("页面访问",3));menu3.add(new MenuItem("新增角色",3));menu3.add(new MenuItem("修改角色",3));//创建一级菜单MenuComponent component = new Menu("系统管理",1);//将二级菜单添加到一级菜单中component.add(menu1);component.add(menu2);component.add(menu3);//打印菜单名称(如果有子菜单一块打印)component.print();}
}



这里的MenuComponent定义为抽象类,

因为有一些共有的属性和行为要在该类中实现,Menu和MenuItem类就可以只覆盖自己感兴趣的方法,

而不用搭理不需要或者不感兴趣的方法,

举例来说,

Menu类可以包含子菜单,因此需要覆盖add()、remove()、getChild()方法,

但是MenuItem就不应该有这些方法。

这里给出的默认实现是抛出异常,你也可以根据自己的需要改写默认实现



Menu类已经实现了除了getName方法的其他所有方法,因为Menu类具有添加菜单,移除菜单和获取子菜单的功能。

MenuItem是菜单项,不能再有子菜单,所以添加菜单,移除菜单和获取子菜单的功能并不能实现。



组合模式的分类

在使用组合模式时,根据抽象构件类的定义形式,我们可将组合模式分为透明组合模式和安全组合模式两种形式

  • 透明组合模式

    透明组合模式中,抽象根节点角色中声明了所有用于管理成员对象的方法,比如在示例中 MenuComponent 声明了 addremove 、getChild 方法,这样做的好处是确保所有的构件类都有相同的接口。透明组合模式也是组合模式的标准形式。

    透明组合模式的缺点是不够安全因为叶子对象和容器对象在本质上是有区别的,叶子对象不可能有下一个层次的对象,即不可能包含成员对象,因此为其提供 add()、remove() 等方法是没有意义的,这在编译阶段不会出错,但在运行阶段如果调用这些方法可能会出错(如果没有提供相应的错误处理代码)

  • 安全组合模式

    在安全组合模式中,在抽象构件角色中没有声明任何用于管理成员对象的方法,而是在树枝节点 Menu 类中声明并实现这些方法。安全组合模式的缺点是不够透明,因为叶子构件和容器构件具有不同的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义,因此客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件



优点

  • 组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,它让客户端忽略了层次的差异,方便对整个层次结构进行控制。
  • 客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码。
  • 在组合模式中增加新的树枝节点和叶子节点都很方便,无须对现有类库进行任何修改,符合“开闭原则”。
  • 组合模式为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子节点和树枝节点的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单。

使用场景

组合模式正是应树形结构而生,所以组合模式的使用场景就是出现树形结构的地方。

比如:文件目录显示,多级目录呈现等树形结构数据的操作

组合模式——透明组合模式,安全组合模式相关推荐

  1. 设计模式:结构型模式-桥接、外观、组合、享元模式

    结构型模式 结构型模式描述如何将类或对象按某种布局组成更大的结构.它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者采用组合或聚合来组合对象. 由于组合关系或聚合关系比继承关系耦 ...

  2. 组合模式_设计模式结构性:组合模式(CompositePattern)

    组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象.组合模式依据树形结构来组合对象,用来表示部分以及整体层次.这种类型的设计模式属于结构型模式, ...

  3. 【设计模式】组合模式?建议改名叫树形模式!

    什么是组合模式(Composite) 概念 组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象.组合模式依据树形结构来组合对象,用来表示部分以及 ...

  4. 设计模式学习笔记(六) - 组合模式 Composite (树状结构专用模式)

    组合模式 Composite 树状结构专用模式   递归遍历结构

  5. java设计模式之——外观模式、组合模式、装饰模式、享元模式(结构型)

    一.外观模式 定义:为子系统中一组接口提供一致的界面,此模式定义了一个高层接口,该接口使得子系统更加容易使用. 使用场景:一.在软件设计初级阶段,应该有意识的将软件两个层分开,比如经典的三层架构,降低 ...

  6. 透传模式(透明传输SeriaNet)详解

    1.简介 SerialNet模式将本地异步串口通信转换成基于TCP/UDP协议的网络通信.其主要目是将串行通信的简单设备实现在网络上的通信,而这些设备不需要做任何改变,为此,SerialNet模式定义 ...

  7. ANDROID 中设计模式的採用--创建型模式

     所谓模式就是在某一情景下解决某个问题的固定解决方式. 全部的创建型模式都是用作对象的创建或实例化的解决方式. 1 简单工厂模式 创建对象的最简单方法是使用new来创建一个对象,假设仅仅创建一种固 ...

  8. 创建型模式、结构型模式和行为型模式_设计模式之创建型模式

    设计模式GOF23(Group of Four) 设计模式可分为三种类型: 创建型模式:单例模式,工厂模式,抽象工厂模式,建造者模式,原型模式. 结构型模式:适配器模式,桥接模式,装饰模式,组合模式, ...

  9. 图解Java设计模式学习笔记——行为型模式(模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式)

    一.模板方法模式(模板模式)--钩子方法 1.需求-豆浆制作问题 编写制作豆浆的程序,说明如下: 制作豆浆的流程选材-->添加配料-->浸泡-->放到豆浆机打碎. 通过添加不同的配料 ...

最新文章

  1. 安装spket-1.6.23.jar
  2. php fprintf,PHP fprintf() 函数 | 菜鸟教程
  3. nvm卸载node_nvm-node版本管理工具
  4. java 全排列非递归算法_全排列的非递归算法 - osc_ivkc73ze的个人空间 - OSCHINA - 中文开源技术交流社区...
  5. word2vec原理_深入理解Word2Vec底层原理
  6. ubuntu android设备 no permissions
  7. jq checked 设置问题
  8. C/C++中static的用法全局变量与局部变量
  9. mysql驱动profilesql_java连接mysql的驱动配置问题
  10. 查看mysql是否归档的命令_查看oracle数据库是否为归档模式
  11. HttpRequest Get和Post调用其他页面的方法
  12. Golang 主机字节序的判断
  13. 零基础学python图文版-杭州零基础学python图文版
  14. 1040 最大公约数之和
  15. Android7.0中关于popupWindow的bug解决办法
  16. IBM-P55A小型机内存故障
  17. 举个栗子!Tableau 技巧(126):学几个常用的日期函数
  18. 架构设计分布式数据结构与算法面试题(2020最新版)
  19. 13 个优秀的 Vue 开源项目及合集推荐
  20. Oracle表数据转换为XML格式数据

热门文章

  1. Django学习笔记(10)——Book单表的增删改查页面
  2. PTA L2-002 链表去重
  3. 解决 vue路由跳转到新页面底部而不是顶部和后退到首页就不让他继续后退了
  4. 梯度下降算法到logistic回归
  5. Linux下使用curl进行http请求(转)
  6. DIV+CSS 网页布局之:三列布局
  7. XPath element 格式
  8. Android系统之Broadcom GPS 移植
  9. 如何使方法行数达到最优、常量与变量如何优雅的定义?
  10. 29.9. Klish - Kommand Line Interface Shell (the fork of clish project)