今天介绍的是结构型设计模式中的第四个模式,也就是组合模式(Composite Pattern)。组合模式也好理解,就拿咱们电脑的文件及文件夹来讲吧,这就是一个较好的组合模式的例子。一个目录下面包含文件及文件夹,文件夹下面也包含文件或文件夹。在这样一层层下来,咱们能够想象。他彷佛像极了那个树状图。而组合模式是依据树型结构来组合对象。用来表示部分—总体层次关系。html
在咱们软件系统开发中,会遇到简单对象与复杂对象一块儿使用的状况,就比如刚刚说的文件目录同样,能够包含文件和文件夹,文件夹下面也能够包含文件和文件夹。可是因为简单对象和复杂对象在功能使用上仍是有必定的区别的,可能会形成客户端调用时较为麻烦。这时候就须要将简单对象和复杂对象统一一致对待。然而组合模式也就是解决这一麻烦的。设计模式
将对象组合成树形结构以表示"部分-总体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具备一致性。安全
看上面案例图,能够发现组合模式通常包含如下部分:ide
抽象构件角色:这是一个抽象角色,它给参加组合的对象定义了公共的接口和行为,在透明式的组合模式中,包含了对全部子对象的管理。可是在安全式的组合模式中,这里不定义管理子对象的方法,而是由树枝构件定义给出。spa
树叶构件:树叶构件意味着没有下级对象,定义了参加组合对象的原始行为。设计
树枝构件:表明有下级对象(树枝或树叶都有可能),给出管理其子类的对象。code
在组合模式中,细分为两种形式。一、透明式组合模式。二、安全式组合模式。这里咱们能够看看何为透明式何为安全式:htm
透明式:对象
抽象构件角色定义公共的接口和行为,这里呢就包括对本对象的操做也包含其子对象的操做的。可是树叶构件对象没有其子类。可是依然继承其功能接口和行为。这里在接口和行为上,不管调用树枝构件仍是树叶构件都是同样的。这就属于透明式了。blog
安全式:
由上面透明式讲的,树叶构件也会包含操做本身和子对象的接口和行为,可是没有其子对象怎么办呢?固然是能够空着不写,但会空。可是万一实现调用了呢?对吧,仍是有必定的安全隐患的。那么安全式也就是说抽象构件包含操做自己对象的接口和行为,那么树叶构件也就包含操做自己对象的接口和行为了。树枝构件则实现操做自身对象的接口和行为的同时,还须要实现操做其子类的对象的接口和行为。
就按开始所讲的文件目录的案例,咱们经过代码一块儿看看,在代码中如何实现组合模式的,这样也能够更方便快捷的了解记忆:
透明式:
namespace Composite_Pattern { /// <summary>
/// 透明式组合模式 /// </summary>
class CompositePattern { } #region 抽象构件角色——抽象文件目录============
public abstract class Files { /// <summary>
/// 增长子对象 /// </summary>
public abstract void Add(Files files = null, string Name = null); /// <summary>
/// 删除子对象 /// </summary>
public abstract void Remove(Files files=null, string Name = null); /// <summary>
/// 操做自己对象 /// </summary>
public abstract void Open(string Name); } #endregion
#region 树叶构件——文件类型========================
/// <summary>
/// TXT文本 /// </summary>
public sealed class BookTxt : Files { public override void Add(Files files=null, string Name = null) { throw new NotImplementedException("不存在添加子类操做"); } public override void Remove(Files files=null, string Name = null) { throw new NotImplementedException("不存在删除子类操做"); } public override void Open(string Name) { Console.WriteLine($"打开一个名为【{Name}】txt文本"); } } #endregion
#region 树枝构件——文件夹类型=================
public class SubFiles : Files { public override void Add(Files files=null, string Name = null) { if (files != null) { Console.WriteLine($"添加一个名为【{Name}】的文件夹"); } else { Console.WriteLine($"添加一个名为【{Name}】的txt文本"); } } public override void Remove(Files files=null, string Name = null) { if (files != null ) { Console.WriteLine($"删除一个名为【{Name}】的文件夹"); } else { Console.WriteLine($"删除一个名为【{Name}】的txt文本"); } } public override void Open(string Name) { Console.WriteLine($"打开当前名为【{Name}】文件夹文件夹"); } } #endregion }
class Program { static void Main(string[] args) { //操做树叶自己文件
Files bookTxt = new BookTxt(); bookTxt.Open("文本文件一"); //新增文件夹
Files subFiles = new SubFiles(); subFiles.Open("文件一"); subFiles.Add(new SubFiles(), "文件二"); //删除文件
subFiles.Remove(Name: "文本文件二"); Console.ReadLine(); } }
安全式:
namespace Composite_Pattern1 { /// <summary>
/// 安全式组合模式 /// </summary>
class CompositePattern { } #region 抽象构件角色——抽象文件目录============
public abstract class Files { /// <summary>
/// 操做自己对象 /// </summary>
public abstract void Open(string Name); } #endregion
#region 树叶构件——文件类型========================
/// <summary>
/// TXT文本 /// </summary>
public sealed class BookTxt : Files { public override void Open(string Name) { Console.WriteLine($"打开一个名为【{Name}】txt文本"); } } #endregion
#region 抽象树枝构件——安全模式,开始定义子类对象操做接口和行为=================
public abstract class SubFiles : Files { public abstract void Add(Files files = null, string Name = null); public abstract void Remove(Files files = null, string Name = null); public override void Open(string Name) { Console.WriteLine($"打开当前名为【{Name}】文件夹"); } } #endregion
#region 具体树枝构件——具体实现类
public class AbSubFiles : SubFiles { public override void Add(Files files = null, string Name = null) { if (files != null) { Console.WriteLine($"添加一个名为【{Name}】的文件夹"); } else { Console.WriteLine($"添加一个名为【{Name}】的txt文本"); } } public override void Remove(Files files = null, string Name = null) { if (files != null) { Console.WriteLine($"删除一个名为【{Name}】的文件夹"); } else { Console.WriteLine($"删除一个名为【{Name}】的txt文本"); } } public override void Open(string Name) { Console.WriteLine($"打开当前名为【{Name}】文件夹"); } } #endregion }
class Program1 { static void Main(string[] args) { //操做树叶自己文件
BookTxt bookTxt = new BookTxt(); bookTxt.Open("文本文件一"); //新增文件夹
AbSubFiles subFiles = new AbSubFiles(); subFiles.Open("文件一"); subFiles.Add(new AbSubFiles(), "文件二"); //删除文件
subFiles.Remove(Name: "文本文件二"); Console.ReadLine(); } }
一、部分——总体的环境。例如树型菜单,文件管理
二、用户但愿对简单对象与复杂对象拥有一致的操做时
一、组合模式使得处理简单对象和复杂对象有一致的操做,无需关心处理的简单对象仍是复杂对象
二、更简单快捷的加入新的节点
一、使得设计复杂,难于理清层次
二、在使用透明式的时候违背了接口分离原则,可是在使用安全式的时候又违背了依赖倒置原则
到这里组合模式就介绍完了。这里须要说起的是在使用透明式组合模式时,树叶构件继承了操做子类的接口和行为,可是它并无子类。在接口分离原则中提到——客户不该被强迫依赖它不使用的方法。因此这里违背了其原则,可是都遵循了依赖倒置原则,依赖于抽象。在实现安全式组合模式时,在客户端调用时依赖于具体实现,也就违背了依赖倒置原则,可是却将树叶操做与树枝构件操做分离,符合接口分离原则。在实现组合模式中不一样形式实现有不一样的问题。这就须要根据咱们实际状况去衡量该如何使用了。
只有经历过地狱般的折磨,才有征服天堂的力量。只有流过血的手指才能弹出世间的绝唱。
欢迎你们扫描下方二维码,和我一块儿踏上设计模式的闯关之路吧!