组合模式定义:组合模式允许你将对象组合成树形结构来表现“整体/局部”层次结构,组合能让客户以一致的方式处理个别对象以及对象组合。

当涉及到如:菜单,子菜单之类的问题时,会自然而然的想到使用树形结构

类之间的关系确如上图所示,但是这种设计复用性和扩展性都很低:

1,所有的菜单都有各自的add、remove以及getChild实现,复用性很低

2,类型转换问题,菜单完全不知道其包含的子元素的具体类型,这是个大问题(List<Object>)

针对上述2个问题:

1,抽象出共同的父类,以实现一些基本方法的复用

2,隐藏菜单与菜单项之间的差异,在这点,我们可以借鉴装饰者模式,将菜单和菜单项都当做一个菜单,如此一来,共同的父类也出现了

组合模式基本组成:

组件 - Menu、SpecificMenu

叶子节点 - MenuItem

组件可以包含其他组件以及叶子节点

public abstract class Menu {
public void add(){
throw new UnsupportedOperationException();
} public void remove(){
throw new UnsupportedOperationException();
} public Menu getChild(int i){
throw new UnsupportedOperationException();
} public void print(){
throw new UnsupportedOperationException();
}
}
public class MenuItem extends Menu {
private String name; public MenuItem(String name){
this.name = name;
} public void print(){
System.out.println(name);
}
}
public class SpecificMenu extends Menu {
private String name;
private List<Menu> children = new ArrayList<Menu>(); public SpecificMenu(String name){
this.name = name;
} public void add(Menu menu){
children.add(menu);
} public void remove(Menu menu){
children.remove(menu);
} public Menu getChild(int i){
return children.get(i);
} public void print(){
Iterator<Menu> it = children.iterator();
while(it.hasNext()){
Menu tmp = it.next();
tmp.print();
}
}
}
public class Cilent {
public static void main(String[] args) {
MenuItem mocha = new MenuItem("mocha");
MenuItem espressos = new MenuItem("espressos");
SpecificMenu coffeeMenu = new SpecificMenu("coffeeMenu");
coffeeMenu.add(mocha);
coffeeMenu.add(espressos);
MenuItem rice = new MenuItem("rice");
SpecificMenu restaurantMenu = new SpecificMenu("restaurantMenu");
restaurantMenu.add(coffeeMenu);
restaurantMenu.add(rice);
SpecificMenu allMenu = new SpecificMenu("allMenu");
allMenu.add(restaurantMenu);
allMenu.print();
}
}

测试结果:

mocha
espressos
rice

通常情况下,一个类具有单一的责任才是好的设计,但是这里,Menu既要扮演菜单,又需扮演菜单项

在组合模式中,通过牺牲了单一责任的设计原则,换取了透明性(对于一个节点,调用方无法确定其是组合还是节点,即组合与节点对用户来说是透明的)

为了保持透明性,组合内所有的对象都必须实现相同的接口,否则将必须考虑哪个对象使用哪个接口,这就失去了组合模式的意义

当然实现相同的接口也意味着有些对象包含一些没有意义的方法调用(如MenuItem通过继承依然拥有add、remove以及getChild方法,但是对叶子节点MenuItem来说,操作子节点的方法似乎是没有意义的,但是换个考虑方向,将MenuItem想象成没有子节点的节点,是不是感觉不一样了?)

可以看出这是一个折中的方案(折中方案很常见,比如为提高处理速度以“空间换时间”),由此也证明设计模式并不是完美无缺的,在使用前有必要仔细审视其带来的影响

PS:

1,什么时候使用组合模式:

有一些对象,它们之间具有“整体/部分”之间的关系,并且想用一致的方式对待整体与局部

组合模式(Composite Pattern)的更多相关文章

  1. 浅谈设计模式--组合模式(Composite Pattern)

    组合模式(Composite Pattern) 组合模式,有时候又叫部分-整体结构(part-whole hierarchy),使得用户对单个对象和对一组对象的使用具有一致性.简单来说,就是可以像使用 ...

  2. 二十四种设计模式:组合模式(Composite Pattern)

    组合模式(Composite Pattern) 介绍将对象组合成树形结构以表示"部分-整体"的层次结构.它使得客户对单个对象和复合对象的使用具有一致性.示例有一个Message实体 ...

  3. 乐在其中设计模式(C#) - 组合模式(Composite Pattern)

    原文:乐在其中设计模式(C#) - 组合模式(Composite Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 组合模式(Composite Pattern) 作者:weba ...

  4. 【设计模式】组合模式 Composite Pattern

    树形结构是软件行业很常见的一种结构,几乎随处可见,  比如: HTML 页面中的DOM,产品的分类,通常一些应用或网站的菜单,Windows Form 中的控件继承关系,Android中的View继承 ...

  5. 设计模式 - 组合模式(composite pattern) 迭代器(iterator) 具体解释

    组合模式(composite pattern) 迭代器(iterator) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考组合模式(composit ...

  6. 设计模式系列之组合模式(Composite Pattern)——树形结构的处理

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  7. 组合模式Composite Pattern(转)

    什么是组合模式呢?简单来说组合模式就是将对象合成树形结构以表示“部分整体”的层次结构,组合模式使用户对单个对象和组合对象使用具有一致性. 组合模式(Composite Pattern)有时候又叫部分- ...

  8. python 设计模式之组合模式Composite Pattern

    #引入一 文件夹对我们来说很熟悉,文件夹里面可以包含文件夹,也可以包含文件. 那么文件夹是个容器,文件夹里面的文件夹也是个容器,文件夹里面的文件是对象. 这是一个树形结构 咱们生活工作中常用的一种结构 ...

  9. C#设计模式——组合模式(Composite Pattern)

    一.概述 在软件开发中,我们往往会遇上类似树形结构的对象体系.即某一对象既可能在树形结构中作为叶节点存在,也可能作为分支节点存在.比如在文件系统中,文件是作为叶节点存在,而文件夹就是分支节点.在设计这 ...

  10. 设计模式 -- 组合模式 (Composite Pattern)

    定义: 对象组合成部分整体结构,单个对象和组合对象具有一致性. 看了下大概结构就是集团总公司和子公司那种层级结构. 角色介绍: Component :抽象根节点:其实相当去总公司,抽象子类共有的方法: ...

随机推荐

  1. USACO3.25Magic Squares(bfs)

    /* ID: shangca2 LANG: C++ TASK: msquare */ #include <iostream> #include<cstdio> #include ...

  2. NuGet -- 如何创建及发布自己的程序包

    STEP 1:在NuGet上注册并获取API Key    首先,你需要在NuGet(https://www.nuget.org/)上注册一个新的账号,然后在My Account页面,获取一个API ...

  3. 基于DDD的现代ASP.NET开发框架--ABP系列之2、ABP入门教程

    基于DDD的现代ASP.NET开发框架--ABP系列之2.ABP入门教程 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boi ...

  4. WCF 第五章 会话级别的实例

    会话在分布式应用程序中广泛用于维护每个用户的状态.在站点或者基于站点的应用中,将每个用户的状态存储于会话中很常见.这这些情况中,用户和会话间有一个1:1比例.WCF以一个类似的概念支持服务.使用Ins ...

  5. NEsper事件处理 z

    http://esper.codehaus.org/nesper/documentation/documentation.html 环境配置 NEsper库下载:下载网址 Vs2010环境集成 在项目 ...

  6. android手机屏幕分辨率 及 sp dip(dp) px 区别 及高中低分辨率时处理

    分辨率,是指单位长度内包含的像素点的数量,它的单位通常为像素/英寸(ppi).以分辨率为1024×768的屏幕来说,即每一条水平线上包含有1024个像素点,共有768条线,即扫描列数为1024列,行数 ...

  7. POJ 1847 Tram dij

    分析:d[i]表示到i点,最少的操作数 #include<cstdio> #include<cstring> #include<queue> #include< ...

  8. Mac Vim 如何设置高亮

    首先进入如下目录 cd /usr/share/vim 然后打开vimrc sudo vim vimrc 在vimrc中的“set backspace=2”这行下插入如下代码: set ai " ...

  9. HDU-3622 Bomb Game 2sat

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3622 题意:一个平面上有很多的炸弹,每个炸弹的爆炸范围是一样的,求最大的爆炸范围使得炸弹之间不相互影响 ...

  10. 源码生成deb包

    方法一 源码包要求是使用 automake 进行编译管理的. 安装路径不能指定为 /usr/local 下的目录,否则生成 deb 包期间报错. 制作的工具是 dh-make ,如果没有安装,要先安装 ...