Composite组合模式(结构型模式)
1、概述
在面向对象系统中,经常会遇到一些具有"容器性质"的对象,它们自己在充当容器的同时,也充当其他对象的容器.
2、案例
需要构建一个容器系统,需要满足以下几点要求:
(1)、容器需要能创建和删除子容器
(2)、但是整个系统有最终的容器结构一一取名SingleBox
(3)、容器有自有业务逻辑,能执行指定的操作.
实现如下:
/// <summary>
/// 容器接口
/// </summary>
public interface IBox
{
void Process(); void AddBox(IBox box); void RemoveBox(IBox box);
} /// <summary>
/// 最终节点的容器,这个容器无法进行添加和删除子容器的操作
/// </summary>
public class SingleBox : IBox
{
public void Process()
{ } public void AddBox(IBox box)
{
throw new Exception("SingleBox容器无法添加子容器");
} public void RemoveBox(IBox box)
{
throw new Exception("SingleBox容器无法移除子容器");
}
} /// <summary>
/// 普通容器,可以进行添加和删除子容器的操作
/// </summary>
public class ContainerBox : IBox
{
private List<IBox> _containerBox = new List<IBox>(); public void Process() { } /// <summary>
/// 模拟实现,没有实际意义,表达一种概念,获取当前容器的子容器
/// </summary>
/// <returns></returns>
public List<ContainerBox> GetBox()
{
return _containerBox;
} public void AddBox(IBox box)
{
_containerBox.Add(box);
} public void RemoveBox(IBox box)
{
if (_containerBox.Contains(box))
_containerBox.Remove(box);
}
}
调用代码如下:
/// <summary>
/// 第三方调用系统
/// </summary>
public class ThirdSystem
{
public void Run()
{
IBox box = Factory.GetBox();
if (box is ContainerBox)
{
//如果当前容器是ContainerBox,执行该容器的Process方法
box.Process();
//获取该容器所有的子容器
var list = ((ContainerBox)box).GetBox();
//这里对所有的子容器进行递归操作,确保它们全部执行到类型为SingleBox
}
else if (box is SingleBox)
{
box.Process();
}
}
}
分析客户端调用代码发现,客户端调用代码在获取容器的子容器时,需要递归处理子容器,从而使客户端代码与复杂的容器结构发生了耦合,这样在设计上是不合理,客户端代码不能承担这种复杂度,而是应该交给容器系统去处理这种复杂度.
so,这种设计需要进行重构.
/// <summary>
/// 容器接口
/// </summary>
public interface IBox
{
void Process(); void AddBox(IBox box); void RemoveBox(IBox box);
} /// <summary>
/// 最终节点的容器,这个容器无法进行添加和删除子容器的操作
/// </summary>
public class SingleBox : IBox
{
public void Process()
{ } public void AddBox(IBox box)
{
throw new Exception("SingleBox容器无法添加子容器");
} public void RemoveBox(IBox box)
{
throw new Exception("SingleBox容器无法移除子容器");
}
} /// <summary>
/// 普通容器,可以进行添加和删除子容器的操作
/// </summary>
public class ContainerBox : IBox
{
private List<IBox> _containerBox = new List<IBox>(); //做一些容器该做的事情,比如说容器加载,做完之后卸载等等操作 public void Process()
{
if (_containerBox.Count > )
{
//遍历当前容器的所有子容器,然后执行子容器的操作,接着遍历该子容器的所有子容器
//进行它该进行的操作,循环这个操作,知道执行到SingleBox,因为它没有子容器,所有跳出
//Foreach循环,完成整颗容器树的遍历
foreach(IBox box in _containerBox)
{
box.Process();
}
}
} public void AddBox(IBox box)
{
_containerBox.Add(box);
} public void RemoveBox(IBox box)
{
if (_containerBox.Contains(box))
_containerBox.Remove(box);
}
}
客户端调用代码如下:
/// <summary>
/// 第三方调用系统
/// </summary>
public class ThirdSystem
{
public void Run()
{
IBox box = Factory.GetBox();
if (box is ContainerBox)
{
//Procss会遍历当前容器的所有的子容器,并且执行这些容器的方法
box.Process(); }
else if (box is SingleBox)
{
box.Process();
}
}
}
ok,现在的客户端调用代码与复杂的容器完成了解耦.而且完成了提出的需求.实现了对容器管理的同时,形成了一个树形结构.
but,上面的代码还是存在缺陷,IBox接口承担了两种职责,一种是是维护容器,另一种是处理容器的结构,执行容器的方法,虽然违背了OOP职责单一的原则,但是这种代价可以接受.
3、组合模式的要点
(1)、重构的代码使用了组合模式,组合模式采用树形结构来实现普遍存在的对象容器,将原先暴露给客户端的"一对多"的关系转换为"一对一"的关系,使得客户端代码可以一致地处理容器对象,不需要关心处理的是单个对象还是含有树形结构的容器对象,将递归处理容器的复杂度交给组合模式来承担.
(2)、将客户端调用代码与负责的容器结构解耦是Composite组合模式的核心思想,解耦之后,客户端代码与依赖的是容器抽象,而不是容器的内部实现结构,从而更能应对变化,试想以下,如果不这么做,如果容器对象发生改变,那么客户端就需要承受这种改变.
(3)、Composite模式在具体的实现中.可以让父对象的子对象进行反向追溯,如果父对象有频繁的遍历需求,可以使用缓存来改善效率.
(4)、Asp.Net中的控件大量使用了组合模式,可以参考帮助理解.
Composite组合模式(结构型模式)的更多相关文章
- 设计模式(十二): Flyweight享元模式 -- 结构型模式
说明: 相对于其它模式,Flyweight模式在PHP实现似乎没有太大的意义,因为PHP的生命周期就在一个请求,请求执行完了,php占用的资源都被释放.我们只是为了学习而简单做了介绍. 1. 概述 面 ...
- 代理模式/proxy模式/结构型模式
代理模式proxy 定义 为其他对象提供一种代理,并以控制对这个对象的访问.最简单的理解,买东西都是要去商店的,不会去工厂. java实现三要素 proxy(代理)+subject(接口)+realS ...
- 设计模式(十):Decorator装饰者模式 -- 结构型模式
1. 概述 若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性.如果已经存在的一个类缺少某些方法,或者须要给方法添加更多的功能(魅力),你也许会仅仅继 ...
- 设计模式(十三): Proxy代理模式 -- 结构型模式
设计模式(十一)代理模式Proxy(结构型) 1.概述 因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路 ...
- 设计模式(十一):FACADE外观模式 -- 结构型模式
1. 概述 外观模式,我们通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会降低应用程序的复杂度,并且提高了程序的可维护性.例子1:一个电源总开关可以控制四盏灯.一个风扇 ...
- 设计模式(八):Bridge桥接模式 -- 结构型模式
1. 概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度 ...
- 设计模式学习之路——Facade 外观模式(结构型模式)
动机: 组件的客户和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦合面临很多变化的挑战.如何简化外部客户程序和系统间的交互接口?如何将外部客户程序的演化和内部子系 ...
- 设计模式(九):Composite组合模式 -- 结构型模式
1. 概述 在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面. 例子1:就是多级树形菜单. 例子2:文件和文件夹目录 2.问题 我们可以使用简单的对象组合成复杂的对象,而这个复杂对 ...
- 适配器模式/adapter模式/结构型模式
定义 将类的接口转化为客户端希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作,别名Wrapper(包装器). 适配器模式,最终改变一个已有对象的接口. 使用场景 当有那么个类, ...
随机推荐
- 相似性度量 Aprioir算法
第三章 标称:转换成0,1来算,或者用非对称二元属性 二元:x1,x2的分布取00,01,10,11的二元属性个数,列表,算比例.不对称的二元属性就忽略00的属性个数 序数:转换成排位rif,度量:r ...
- MyBatis(二)最简易的增、删、改、查
这篇是承接上一篇的helloWorld程序.首先将一系列初始化的步骤再做一个工厂类进行包装,代码如下: package com.tinaluo.sun; import java.io.InputStr ...
- 20145232 韩文浩 《Java程序设计》第2周学习总结
教材学习内容总结 这周主要学习了注释的使用,运算符的基本使用,认识了类型,变量与常量,以及一些语句语法.复习了进制转换. 整数 Short整数占用2字节,储存整数范围-32768 ~ 32767(2- ...
- PHP与Python哪个做网站产品好?
虽然python现在比较火,但在传统的LAMP组合里Linux+apache/tomcat+MySql+PHP里是PHP做网站的脚本语言,但现在已经变了:https://baike.baidu.com ...
- Spring的两种代理JDK和CGLIB的区别浅谈
一.原理区别: java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. 而cglib动态代理是利用asm开源包,对代理对象类的class文件 ...
- oj错误之char型超出范围
在oj时遇到一个题 题目本身并不是很难,但在一个数据时出了错,刚开始一直没想通是哪里出了错 下面为源代码 #include <bits/stdc++.h> using namespace ...
- ASP.NET Web API 框架研究 Web Host模式路由及将请求转出到消息处理管道
Web Host 模式下的路由本质上还是通过ASP.NET 路由系统来进行路由的,只是通过继承和组合的方式对ASP.NET路由系统的内部的类进行了一些封装,产生自己专用一套类结构,功能逻辑基本都是一样 ...
- Python自动化开发 - 面向对象(二)
本节内容 1.isinstance(obj,cls)和issubclass(sub,super) 2.反射 3.__setattr__,__delattr__,__getattr__ 一. isins ...
- Python自动化开发 - 常用模块(一)
本节内容 1.模块介绍 2.time&datetime模块 3.random模块 4.os模块 5.sys模块 6.json&pickle模块 7.logging模块 一.模块介绍 模 ...
- Android-Kotlin-印章类
上一篇博客介绍了,Android-Kotlin-枚举enum: 由于枚举 和 印章类 有相似之处,所以两者对比一下: Kotlin的枚举,重点区分的数据本身 Kotlin的印章类,重点区分的是数据类型 ...