Gof定义

将对象组合成树形结构以表示“部分--整体”的层次结构。Composite使得用户对单个对象和组合对象使用具有一致性。

在面向对象系统中,我们经常会遇到一类具有”容器“特征的对象---即他们在充当对象的同时,又是其他对象的容器。比如在一些管理系统中就会出现总公司下面有很多的分公司,分公司下面有很多的部门,每个部门下又有很多的员工,像分公司和部门就是既充当了“对象”的角色也充当了“容器”的角色;还有我们可能玩过的“俄罗斯套娃”也是这种结构,一个大娃娃里面装个小娃娃,小的里面又有个小的直到最小的一个,中间的娃娃就是既充当了“对象”也充当了“容器”。先看下面这个例子:

interface IBox
{void Process();
}
/// <summary>
/// 相当于树的叶子节点,没有子对象了
/// </summary>
public class SingleBox : IBox
{public void Process(){ }
}
/// <summary>
/// 容器
/// </summary>
public class ContainerBox : IBox
{List<IBox> list = new List<IBox>();public void Process() { }public List<IBox> GetBoxes(){return list;}
}
/// <summary>
/// 客户代码
/// </summary>
public class App
{static void Mina(){///此处从工厂方法中得到盒子的对象,但我们不知道是SingleBox还是ContainerBox///所以要做判断IBox box = Factory.Create();if (box is ContainerBox){box.Process();List<IBox> list = ((ContainerBox)box).GetBoxes();}else if(box is SingleBox){box.Process();}}
}

动机

上面代码的问题的根据在于:客户代码过多地依赖对象容器复杂的内部实现结构,对象容器内部实现结构(而非抽象接口)的变化将引起客户代码的频繁变化,带来了代码的维护性、扩展性等弊端。

如何将“客户代码与复杂的对象容器结构”解耦?让对象容器自己来实现自身的复杂结构,从而使得客户代码就像处理简单对象一样来处理复杂的对象容器?

这就要使用Composite模式了,先看下Composite模式的结构图

Component:定义了Leaf和Composite的一些共有特性。

Composite:有容器特征的类型。

Leaf:叶节点,即一个单独的个体,下面没有子节点。

依据上面的结构图完成代码实现:

public abstract class Component
{protected string _name;public Component(string name){_name = name;}public abstract void Operation();public abstract void Add(Component component);public abstract void Remove(Component component);
}public class Leaf : Component
{public Leaf(string name) : base(name) { }public override void Add(Component component){throw new NotSupportedException();}public override void Remove(Component component){throw new NotSupportedException();}public override void Operation(){ //...do something}
}public class Composite : Component
{public Composite(string name):base(name){}List<Component> list = new List<Component>();/// <summary>/// 添加/// </summary>/// <param name="conponent"></param>public override void Add(Component component){if (list != null){list = new List<Component>();}list.Add(component);}/// <summary>/// 删除/// </summary>/// <param name="component"></param>public override void Remove(Component component){if (list == null){throw new NullReferenceException();}list.Remove(component);}public override void Operation(){if (list != null){foreach (Component c in list){c.Operation();}}}
}

Leaf类为叶子节点类,它的实例是没有子节点的,但是在抽象类中的方法Add和Remove方法必须要实现,按理说这样的实现是没有意义的,所以在此处抛出了NotSupportedException 异常,在客户端调用捕获到再做相应的处理,这种模式称之为“透明足组合模式”,这样做的好处是叶子(Leaf)和容器(Composite)对于外界没有分别,它们具有一致的接口行为。还有一种情况叫“安全组合模式”,在抽象类(Component)中不定义Add Remove方法,而是在容器的实现类中去定义,这样就各司其职了,看下面结构图

代码实现

public abstract class Component
{protected string _name;public Component(string name){_name = name;}public abstract void Operation();
}public class Leaf : Component
{public Leaf(string name) : base(name) { }public override void Operation(){//...do something}
}public class Composite : Component
{public Composite(string name) : base(name) { }List<Component> list = new List<Component>();/// <summary>/// 添加/// </summary>/// <param name="conponent"></param>public void Add(Component component){if (list != null){list = new List<Component>();}list.Add(component);}/// <summary>/// 删除/// </summary>/// <param name="component"></param>public void Remove(Component component){if (list == null){throw new NullReferenceException();}list.Remove(component);}public override void Operation(){if (list != null){foreach (Component c in list){c.Operation();}}}
}

使用“安全组合模式”Leaf和Composite就不具有相同的接口,所以在客户端调用的时候还是要去判断是什么类型,比较麻烦。所以说选择哪种还要看具体的需求。

Composite模式的几个要点

Composite模式采用树形结构来实现普遍存在的对象容器,从而将“一对多”的关系转化为“一对一”的关系,使得客户代码可以一致地处理对象和对象容器,无需关心处理的是单个的对象还是组合的对象容器。

将“客户代码与复杂的对象容器结构”解耦是Composite模式的核心思>想,解耦之后,客户代码将与纯粹的抽象接口——而非对象容器的复内部实现结构——发生依赖关系,从而更能“应对变化”。

Composite模式中,是将“Add和Remove等和对象容器相关的方法”定义在“表示抽象对象的Component类”中,还是将其定义在“表示对象容器的Composite类”中,是一个关乎“透明性”和“安全性”的两难问题,需要仔细权衡。这里有可能违背面向对象的“单一职责原则”,但是对于这种特殊结构,这又是必须付出的代价。ASP.NET控件的实现在这方面为我们提供了一个很好的示范。

Composite模式在具体实现中,可以让父对象中的子对象反向追溯; 如果父对象有频繁的遍历需求,可使用缓存技巧来改善效率。

转载于:https://www.cnblogs.com/oec2003/archive/2009/12/02/1615773.html

设计模式笔记(9)---组合模式(结构型)相关推荐

  1. 设计模式深入学习---Component组合模式(结构型模式)

    Component组合模式是一个非常好用而且经常可以在大型项目中看到的设计模式.    首先我们来简单过一下什么是Component组合模式以及用该模式的情况和好处.Component组合模式就是将对 ...

  2. 设计模式笔记(7)---适配器模式(结构型)

    Gof定义 将一个类的接口转换成客户所希望的另一个接口.适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 动机 在软件系统中,由于应用环境的变化,常常要将"一些现存的对象 ...

  3. 设计模式笔记(10)---装饰模式(结构型)

    Gof定义 动态地给一个对象增加一些额外的职责.就增加功能而言,Decorator模式比生成子类更为灵活. 首先来看一个小例子,假如我们需要给游戏开发一种坦克,除了各种不同型号的坦克外,还希望在不同的 ...

  4. .NET设计模式(15):结构型模式专题总结

    .NET设计模式(15):结构型模式专题总结 --探索设计模式系列之十五 Terrylee,2006年5月 摘要:结构型模式,顾名思义讨论的是类和对象的结构,它采用继承机制来组合接口或实现(类结构型模 ...

  5. 23种设计模式:(二)结构型模式

    根据北京尚学堂的视频所学习 结构型模式: 核心作用:是从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题. 分类: 适配器模式.代理模式.桥接模式. 装饰模式.组合模式.外观模式. ...

  6. 23种设计模式(第三章结构型模式7种)

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

  7. 设计模式初识(三)结构型模式(Structural Pattern)

    为什么要使用结构型模式 结构型模式关注点在于"如何组合对象/类",更关注类之间的组合关系: 类结构型模式关心类的组合,由多个类可以组合成一个更大的(继承): 对象结构型模式关心类与 ...

  8. 【设计模式_青春版】结构型|外观模式

    文章目录 外观模式(结构型) 外观模式又名门面模式 结构 外观模式案例 代码实现 优缺点 优点 缺点 使用场景 在tomcat中的 外观模式(结构型) 外观模式又名门面模式 是一种通过为多个复杂的子系 ...

  9. 设计模式之美总结(结构型篇)

    title: 设计模式之美总结(结构型篇) date: 2022-12-21 09:59:11 tags: 设计模式 categories: 设计模式 cover: https://cover.png ...

最新文章

  1. 计算机金融交叉学科考研,22考研:交叉学科可能成为新选择!它有哪些优势?
  2. Javadoc代码追踪记录
  3. mysql字段掩码_在必须输入字母A~Z或数字0~9数据库中设计表时,如果将字段的输入掩码设置为“LLLL”,则该字段能够接受的输入是()_学小易找答案...
  4. 系统维护For流星无语
  5. Docker Java+Tomcat 环境搭建
  6. JavaFX自定义控件– Nest Thermostat第2部分
  7. OGR示例:写shp,求面与面的交和差操作
  8. [转载] java面试100问+参考答案
  9. 13-Mybatis 注解开发
  10. 氮化镓充电器哪家好_氮化镓充电器又添一员猛将
  11. shell编程的for和while循环
  12. AsyncTask的理解和使用
  13. ir2104s的自举电容_一文看懂ir2110自举电容的选择 - 全文
  14. google chrome浏览器崩溃修复
  15. esp8266 python 74hc595_十九 ,ESP32 74HC595 的使用
  16. 密码学(三、非对称加密)
  17. java-php-python-ssm演唱会购票系统计算机毕业设计
  18. 虚拟机dns服务器不可以,windows虚拟机中DNS服务配置
  19. 阿里云大数据ACP专业认证实验之05-MaxCompute内置函数(上)
  20. 20多岁,你迷茫又着急。你想要房子你想要汽车,你想要旅行你想要享受生活。 你那么年轻却窥觑整个世界

热门文章

  1. python 浮点数未解之谜
  2. 解决:sql中将日期字符串当做日期类型处理
  3. SpringBoot集成AOP管理日志
  4. 算法工程师落地_模型的更新升级能力
  5. pip、conda 换国内源,大大提高下载速度
  6. 终端(terminal)、tty、shell、控制台(console)、bash之间的区别与联系
  7. MindSpore技术理解(下)
  8. CUDA C 纹理提取Texture Fetching
  9. Docker_Swarm集群系统
  10. 怎么查找执行比较慢的sql语句