使用C# (.NET Core) 实现组合设计模式 (Composite Pattern)

就当我们感觉我们的设计已经足够好的时候, 新的需求来了, 我们不仅要支持多种菜单, 还要支持菜单下可以拥有子菜单.

例如我想在DinerMenu下添加一个甜点子菜单(dessert menu). 以我们目前的设计, 貌似无法实现该需求.

使用C# (.NET Core) 实现组合设计模式 (Composite Pattern)

目前我们无法把dessertmenu放到MenuItem的数组里.

我们应该怎么做?

我们需要一种类似树形的结构, 让其可以容纳/适应菜单, 子菜单以及菜单项.

我们还需要维护一种可以在该结构下遍历所有菜单的方法, 要和使用遍历器一样简单.

遍历条目的方法需要更灵活, 例如, 我可能只遍历DinerMenu下的甜点菜单(dessert menu), 或者遍历整个Diner Menu, 包括甜点菜单.

使用C# (.NET Core) 实现组合设计模式 (Composite Pattern)

使用C# (.NET Core) 实现组合设计模式 (Composite Pattern)

组合模式定义

组合模式允许你把对象们组合成树形的结构, 从而来表示整体的层次. 通过组合, 客户可以对单个对象或对象们的组合进行一致的处理.

使用C# (.NET Core) 实现组合设计模式 (Composite Pattern)

先看一下树形的结构, 拥有子元素的元素叫做节点(node), 没有子元素的元素叫做叶子(leaf).

针对我们的需求:

使用C# (.NET Core) 实现组合设计模式 (Composite Pattern)

菜单Menu就是节点, 菜单项MenuItem就是叶子.

 

针对需求我们可以创建出一种树形结构, 它可以把嵌套的菜单或菜单项在相同的结构下进行处理.

组合和单个对象是指什么呢?

如果我们拥有一个树形结构的菜单, 子菜单, 或者子菜单和菜单项一起, 那么就可以说任何一个菜单都是一个组合, 因为它可以包含其它菜单或菜单项.

而单独的对象就是菜单项, 它们不包含其它对象.

使用C# (.NET Core) 实现组合设计模式 (Composite Pattern)

使用C# (.NET Core) 实现组合设计模式 (Composite Pattern)

使用C# (.NET Core) 实现组合设计模式 (Composite Pattern)

使用组合模式, 我们可以把相同的操作作用于组合或者单个对象上. 也就是说, 大多数情况下我们可以忽略对象们的组合与单个对象之间的差别.

该模式的类图:

使用C# (.NET Core) 实现组合设计模式 (Composite Pattern)

客户Client, 使用Component来操作组合中的对象.

Component定义了所有对象的接口, 包括组合节点与叶子. Component接口也可能实现了一些默认的操作, 这里就是add, remove, getChild.

叶子Leaf会继承Component的默认操作, 但是有些操作也许并不适合叶子, 这个过会再说.

叶子Leaf没有子节点.

组合Composite需要为拥有子节点的组件定义行为. 同样还实现了叶子相关的操作, 其中有些操作可能不适合组合, 这种情况下异常可能会发生.

使用组合模式来设计菜单

 首先, 需要创建一个component接口, 它作为菜单和菜单项的共同接口, 这样就可以在菜单或菜单项上调用同样的方法了.

使用C# (.NET Core) 实现组合设计模式 (Composite Pattern)

由于菜单和菜单项必须实现同一个接口, 但是毕竟它们的角色还是不同的, 所以并不是每一个接口里(抽象类里)的默认实现方法对它们都有意义. 针对毫无意义的默认方法, 有时最好的办法是抛出一个运行时异常. 例如(NotSupportedException, C#).

MenuComponent:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpsgzd.html