学习而来,代码是自己敲的。也有些自己的理解在里边,有问题希望大家指出。
组合(Composite Pattern)模式的定义:有时又叫作整体-部分(Part-Whole)模式,它是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系,使用户对单个对象和组合对象具有一致的访问性,属于结构型设计模式。
组合模式一般用来描述整体与部分的关系,它将对象组织到树形结构中,顶层的节点被称为根节点,根节点下面可以包含树枝节点和叶子节点,树枝节点下面又可以包含树枝节点和叶子节点,树形结构图如下。
组合模式示意图由上图可以看出,其实根节点和树枝节点本质上属于同一种数据类型,可以作为容器使用;而叶子节点与树枝节点在语义上不属于用一种类型。但是在组合模式中,会把树枝节点和叶子节点看作属于同一种数据类型(用统一接口定义),让它们具备一致行为。
这样,在组合模式中,整个树形结构中的对象都属于同一种类型,带来的好处就是用户不需要辨别是树枝节点还是叶子节点,可以直接进行操作,给用户的使用带来极大的便利。
- 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码;
- 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”;
- 设计较复杂,客户端需要花更多时间理清类之间的层次关系;
- 不容易限制容器中的构件;
- 不容易用继承的方法来增加构件的新功能;
组合模式的结构不是很复杂,下面对它的结构和实现进行分析。
组合模式包含以下主要角色。
- 抽象构件(Component)角色:它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。(总的抽象类或接口,定义一些通用的方法,比如新增、删除)
- 树叶构件(Leaf)角色:是组合中的叶节点对象,它没有子节点,用于继承或实现抽象构件。
- 树枝构件(Composite)角色 / 中间构件:是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件。它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。
组合模式分为透明式的组合模式和安全式的组合模式。
在该方式中,由于抽象构件声明了所有子类中的全部方法,所以客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。但其缺点是:树叶构件本来没有 Add()、Remove() 及 GetChild() 方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。其结构图如图 1 所示。
图1 透明式的组合模式的结构图
在该方式中,将管理子构件的方法移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,这样就避免了上一种方式的安全性问题,但由于叶子和分支有不同的接口,客户端在调用时要知道树叶对象和树枝对象的存在,所以失去了透明性。其结构图如图 2 所示。
图2 安全式的组合模式的结构图假如要访问集合 c0={leaf1,{leaf2,leaf3}} 中的元素,其对应的树状图如图 3 所示。
代码样例
using DesignPattern.CompositePattern;
using System;
namespace DesignPattern
{
internal class Program
{
static void Main(string[] args)
{
CompositeHelper();
}
#region Pattern - Composite
static void CompositeHelper()
{
Composite _root = new TreeLimb("小三门目录");
Composite art = new TreeLimb("美术");
Composite sports = new TreeLimb("体育");
Composite music = new TreeLimb("音乐");
_root.Add(art);
_root.Add(sports);
_root.Add(music);
Composite painting = new TreeLimb("油画类");
art.Add(painting);
Composite running = new TreeLimb("跑步类");
Composite swimming = new TreeLimb("游泳类");
sports.Add(running);
sports.Add(swimming);
Composite soprano = new TreeLimb("高音类");
Composite opera = new TreeLimb("戏曲类");
Composite bass = new TreeLimb("低音类");
music.Add(soprano);
music.Add(opera);
music.Add(bass);
Composite painting1 = new Leaf("油画精选1");
Composite painting2 = new Leaf("油画精选2");
painting.Add(painting1);
painting.Add(painting2);
Composite opera1 = new TreeLimb("戏曲选集1");
Composite opera2 = new TreeLimb("戏曲选集2");
Composite opera3 = new TreeLimb("戏曲选集3");
opera.Add(opera1);
opera.Add(opera2);
opera.Add(opera3);
opera.Remove(opera2);
Composite swimming1 = new Leaf("花样游泳");
Composite swimming2 = new Leaf("200m游泳");
Composite swimming3 = new Leaf("800m接力游泳");
Composite swimming4 = new Leaf("1600m接力游泳");
swimming.Add(swimming1);
swimming.Add(swimming2);
swimming.Add(swimming3);
swimming.Add(swimming4);
_root.Depth(0);
Console.WriteLine();
Console.WriteLine("文章数:" + _root.ShowCount());
Console.ReadLine();
}
#endregion
}
}
//======================================================================================
using System;
using System.Collections.Generic;
namespace DesignPattern.CompositePattern
{
///
/// 抽象合成类
///
public abstract class Composite
{
///
/// 组件名
///
public string Name;
public Composite(string name)
{
Name = name;
}
///
/// 增加子节点
///
public abstract void Add(Composite composite);
///
/// 删除子节点
///
public abstract void Remove(Composite composite);
///
/// 返回最终子节点数量
///
public abstract int ShowCount();
///
/// 节点展示深度
///
/// - 的数量
public abstract void Depth(int depth);
}
///
/// 枝干节点
///
public class TreeLimb : Composite
{
private List m_Composite = new List();
public TreeLimb(string name) : base(name)
{
Name = name;
}
public override void Add(Composite component)
{
m_Composite.Add(component);
}
public override void Depth(int depth)
{
Console.WriteLine(new string('-', depth * 2) + Name);
foreach (Composite item in m_Composite)
{
item.Depth(depth + 1);
}
}
public override void Remove(Composite component)
{
m_Composite.Remove(component);
}
public override int ShowCount()
{
int count = 0;
foreach (var item in m_Composite)
{
count += item.ShowCount();
}
return count;
}
}
///
/// 子节点
///
public class Leaf : Composite
{
public Leaf(string name) : base(name)
{
Name = name;
}
public override void Add(Composite composite)
{
throw new InvalidOperationException("叶子节点不能添加元素");
}
public override void Depth(int depth)
{
Console.WriteLine(new string('-', depth * 2) + Name);
}
public override void Remove(Composite composite)
{
throw new InvalidOperationException("叶子节点不能删除元素");
}
public override int ShowCount()
{
return 1;
}
}
}
运行结果:
今日分享结束啦,小伙伴们你们get到了么,你们有没有更好的办法呢,可以评论区留言分享,也可以加我QQ:841298494,大家一起进步。
- 博客杂货铺
- GoF23 种设计模式的分类和功能