Composite模式定义了单个对象和组合对象的类层次结构。(1)单个对象组合成复杂的组合对象,而多个组合对象又可以被组合成一个新的组合对象。其中,一个组合对象中的某些对象可能包容了其他对象。某些对象则表现单个基本对象,称为叶对象;某些对象代表一组对象,称为枝对象。叶对象可以组合成复杂的枝对象,而枝对象又可以被组合成新的枝对象,可以不断组合下去。
Composite模式使用户对单个对象和组合对象的使用具有一致性。客户可以一致地使用组合结构和单个对象,而不用关心处理的是一个叶节点还是一个组合组件。Composite关键是一个抽象类,这个类既可以代表一个对象,也可以代表一个容器来包含一组对象。(1)那么。Composite关键两个思想:
一、一个Composite对象既可包容Leaf对象,也可以其他包容Composite对象。
二、一个Leaf类和一个Composite共享一个在抽象类中定义的公共接口Component。(2)
在以下情况下考虑使用合成模式:
(1)表示对象的部分和整体层次结构
(2)忽略枝对象和叶对象的不同,用户同意使用组合结构的所有对象。
结构图如下:
合成模式的实现根据公共接口Component的区别分为两种形式,分别称为安全模式和透明模式。
透明模式:
公共接口Component中里面声明所有的用来管理子类对象的方法,包括Add()、Remove(),以及GetChild()方法。这样所有的叶对象和枝对象都有相同的接口,那么客户端可以将叶对象和枝对象同等对待而不用区分。
示例代码如下:
using System.Collections.Generic;
using System.Text;
namespace Composite
... {
/**//// <summary>
/// 透明模式
/// 一个Leaf类和一个Composite共享一个在抽象类中定义的公共接口
/// </summary>
public interface ITransparence
...{
/**//// <summary>
/// 获得学生的总成绩
/// </summary>
/// <returns>返回学生的总成绩</returns>
int GetStudentScores();
/**//// <summary>
/// 获得学生的所有科目名称
/// </summary>
/// <returns>返回学生的所有科目名称</returns>
string GetStudentSubjects();
/**//// <summary>
/// 增加叶节点
/// </summary>
/// <param name="transparence">接口类型对象</param>
/// <returns>操作是否成功</returns>
bool Add(ITransparence transparence);
/**//// <summary>
/// 移除叶节点
/// </summary>
/// <param name="transparence">接口类型对象</param>
/// <returns>操作是否成功</returns>
bool Remove(ITransparence transparence);
/**//// <summary>
/// 获得所有的子节点
/// </summary>
/// <returns></returns>
List<ITransparence> GetChild();
}
/**//// <summary>
/// 学生叶子节点
/// </summary>
public class StudentLeaf : ITransparence
...{
/**//// <summary>
/// 语文
/// </summary>
private string _chinese;
/**//// <summary>
/// 数学
/// </summary>
private string _math;
/**//// <summary>
/// 英语
/// </summary>
private string _english;
/**//// <summary>
/// 语文成绩
/// </summary>
private int _chineseScore;
/**//// <summary>
/// 数学成绩
/// </summary>
private int _mathScore;
/**//// <summary>
/// 英语成绩
/// </summary>
private int _englishScore;
/**//// <summary>
/// 构造函数:语文,数学,英语的中文名称和它的分数
/// </summary>
/// <param name="chinese"></param>
/// <param name="math"></param>
/// <param name="english"></param>
public StudentLeaf(string chinese, string math, string english, int chineseScore, int mathScore, int englishScore)
...{
_chinese = chinese;
_math = math;
_english = english;
_chineseScore = chineseScore;
_mathScore = mathScore;
_englishScore = englishScore;
}
/**//// <summary>
/// 获得某个学生总成绩
/// </summary>
/// <returns></returns>
public int GetStudentScores()
...{
int scores = _chineseScore + _mathScore + _englishScore;
return scores;
}
/**//// <summary>
/// 获得某个学生的所有科目名称
/// </summary>
/// <returns></returns>
public string GetStudentSubjects()
...{
StringBuilder sb = new StringBuilder();
sb.Append("语文:");
sb.Append(_chinese);
sb.Append(" ");
sb.Append("数学:");
sb.Append(_math);
sb.Append(" ");
sb.Append("英语:");
sb.Append(_english);
sb.Append(" ");
return sb.ToString();
}
/**//// <summary>
/// 增加叶节点
/// </summary>
/// <param name="transparence">接口类型对象</param>
/// <returns>操作是否成功</returns>
public bool Add(ITransparence transparence)
...{
//叶子节点不能使用该方法
return false;
}
/**//// <summary>
/// 移除叶节点
/// </summary>
/// <param name="transparence">接口类型对象</param>
/// <returns>操作是否成功</returns>
public bool Remove(ITransparence transparence)
...{
//叶子节点不能使用该方法
return false;
}
/**//// <summary>
/// 获得所有的子节点
/// </summary>
/// <returns></returns>
public List<ITransparence> GetChild()
...{
return null;
}
}
/**//// <summary>
/// 学生合成类
/// </summary>
public class StudentComposite : ITransparence
...{
private List<ITransparence> studentComposite = new List<ITransparence>();
/**//// <summary>
/// 获得某个学生总成绩
/// </summary>
/// <returns></returns>
public int GetStudentScores()
...{
int scores = 0;
foreach(ITransparence transparence in studentComposite)
...{
scores += transparence.GetStudentScores();
}
return scores;
}
/**//// <summary>
/// 获得某个学生的所有科目名称
/// </summary>
/// <returns></returns>
public string GetStudentSubjects()
...{
StringBuilder sb = new StringBuilder();
foreach (ITransparence transparence in studentComposite)
...{
sb.Append(transparence.GetStudentSubjects());
sb.Append(" ");
}
return sb.ToString();
}
/**//// <summary>
/// 增加叶节点
/// </summary>
/// <param name="transparence">接口类型对象</param>
/// <returns>操作是否成功</returns>
public bool Add(ITransparence transparence)
...{
studentComposite.Add(transparence);
return true;
}
/**//// <summary>
/// 移除叶节点
/// </summary>
/// <param name="transparence">接口类型对象</param>
/// <returns>操作是否成功</returns>
public bool Remove(ITransparence transparence)
...{
studentComposite.Remove(transparence);
return true;
}
/**//// <summary>
/// 获得所有的子节点
/// </summary>
/// <returns></returns>
public List<ITransparence> GetChild()
...{
return studentComposite;
}
}
/**//// <summary>
/// 客户类
/// </summary>
public class Client
...{
static void Main(string[] args)
...{
int scores = 0;
string studentSubjectsName = string.Empty;
StudentComposite sudentCompositeRoot = new StudentComposite();
StudentLeaf studentLeafRootOne = new StudentLeaf("11","12","13",70,71,72);
StudentLeaf studentLeafRootTwo = new StudentLeaf("21","22","23",80,81,82);
StudentLeaf studentLeafRootThree= new StudentLeaf("31","32","33",90,91,92);
sudentCompositeRoot.Add(studentLeafRootOne);
sudentCompositeRoot.Add(studentLeafRootTwo);
sudentCompositeRoot.Add(studentLeafRootThree);
StudentComposite sudentCompositeChild = new StudentComposite();
StudentLeaf studentLeafChildOne = new StudentLeaf("41","42","43",60,61,62);
StudentLeaf studentLeafChildTwo = new StudentLeaf("51","52","53",50,51,52);
sudentCompositeChild.Add(studentLeafChildOne);
sudentCompositeChild.Add(studentLeafChildTwo);
sudentCompositeRoot.Add(sudentCompositeChild);
scores = sudentCompositeRoot.GetStudentScores();
Console.WriteLine(" 总成绩:{0} ", scores);
studentSubjectsName = sudentCompositeRoot.GetStudentSubjects();
Console.WriteLine(" 所有科目名称:{0} ", studentSubjectsName);
StudentLeaf studentLeaf = new StudentLeaf("61", "62", "63", 40, 41, 42);
scores = studentLeaf.GetStudentScores();
Console.WriteLine(" 总成绩:{0} ", scores);
studentSubjectsName = studentLeaf.GetStudentSubjects();
Console.WriteLine(" 所有科目名称:{0} ", studentSubjectsName);
}
}
}
安全模式:
公共接口Component中里面不声明所有的用来管理子类对象的方法,而将这些方法(Add()、Remove(),以及GetChild()方法)在Composite类中实现。因为叶对象不包含任何对象,所以叶对象不需要操作叶子对象的方法,故是安全的。在这种情况下,在客户端使用管理子类对象的方法,自然就出错了。
示例代码如下:
using System.Collections.Generic;
using System.Text;
namespace Composite
... {
/**//// <summary>
/// 安全模式
/// 一个Leaf类和一个Composite共享一个在抽象类中定义的公共接口
/// </summary>
public interface ITransparence
...{
/**//// <summary>
/// 获得学生的总成绩
/// </summary>
/// <returns>返回学生的总成绩</returns>
int GetStudentScores();
/**//// <summary>
/// 获得学生的所有科目名称
/// </summary>
/// <returns>返回学生的所有科目名称</returns>
string GetStudentSubjects();
}
/**//// <summary>
/// 学生叶子节点
/// </summary>
public class StudentLeaf : ITransparence
...{
/**//// <summary>
/// 语文
/// </summary>
private string _chinese;
/**//// <summary>
/// 数学
/// </summary>
private string _math;
/**//// <summary>
/// 英语
/// </summary>
private string _english;
/**//// <summary>
/// 语文成绩
/// </summary>
private int _chineseScore;
/**//// <summary>
/// 数学成绩
/// </summary>
private int _mathScore;
/**//// <summary>
/// 英语成绩
/// </summary>
private int _englishScore;
/**//// <summary>
/// 构造函数:语文,数学,英语的中文名称和它的分数
/// </summary>
/// <param name="chinese"></param>
/// <param name="math"></param>
/// <param name="english"></param>
public StudentLeaf(string chinese, string math, string english, int chineseScore, int mathScore, int englishScore)
...{
_chinese = chinese;
_math = math;
_english = english;
_chineseScore = chineseScore;
_mathScore = mathScore;
_englishScore = englishScore;
}
/**//// <summary>
/// 获得某个学生总成绩
/// </summary>
/// <returns></returns>
public int GetStudentScores()
...{
int scores = _chineseScore + _mathScore + _englishScore;
return scores;
}
/**//// <summary>
/// 获得某个学生的所有科目名称
/// </summary>
/// <returns></returns>
public string GetStudentSubjects()
...{
StringBuilder sb = new StringBuilder();
sb.Append("语文:");
sb.Append(_chinese);
sb.Append(" ");
sb.Append("数学:");
sb.Append(_math);
sb.Append(" ");
sb.Append("英语:");
sb.Append(_english);
sb.Append(" ");
return sb.ToString();
}
}
/**//// <summary>
/// 学生合成类
/// </summary>
public class StudentComposite : ITransparence
...{
private List<ITransparence> studentComposite = new List<ITransparence>();
/**//// <summary>
/// 获得某个学生总成绩
/// </summary>
/// <returns></returns>
public int GetStudentScores()
...{
int scores = 0;
foreach(ITransparence transparence in studentComposite)
...{
scores += transparence.GetStudentScores();
}
return scores;
}
/**//// <summary>
/// 获得某个学生的所有科目名称
/// </summary>
/// <returns></returns>
public string GetStudentSubjects()
...{
StringBuilder sb = new StringBuilder();
foreach (ITransparence transparence in studentComposite)
...{
sb.Append(transparence.GetStudentSubjects());
sb.Append(" ");
}
return sb.ToString();
}
/**//// <summary>
/// 增加叶节点
/// </summary>
/// <param name="transparence">接口类型对象</param>
/// <returns>操作是否成功</returns>
public bool Add(ITransparence transparence)
...{
studentComposite.Add(transparence);
return true;
}
/**//// <summary>
/// 移除叶节点
/// </summary>
/// <param name="transparence">接口类型对象</param>
/// <returns>操作是否成功</returns>
public bool Remove(ITransparence transparence)
...{
studentComposite.Remove(transparence);
return true;
}
/**//// <summary>
/// 获得所有的子节点
/// </summary>
/// <returns></returns>
public List<ITransparence> GetChild()
...{
return studentComposite;
}
}
/**//// <summary>
/// 客户类
/// </summary>
public class Client
...{
static void Main(string[] args)
...{
int scores = 0;
string studentSubjectsName = string.Empty;
StudentComposite sudentCompositeRoot = new StudentComposite();
StudentLeaf studentLeafRootOne = new StudentLeaf("11","12","13",70,71,72);
StudentLeaf studentLeafRootTwo = new StudentLeaf("21","22","23",80,81,82);
StudentLeaf studentLeafRootThree= new StudentLeaf("31","32","33",90,91,92);
sudentCompositeRoot.Add(studentLeafRootOne);
sudentCompositeRoot.Add(studentLeafRootTwo);
sudentCompositeRoot.Add(studentLeafRootThree);
StudentComposite sudentCompositeChild = new StudentComposite();
StudentLeaf studentLeafChildOne = new StudentLeaf("41","42","43",60,61,62);
StudentLeaf studentLeafChildTwo = new StudentLeaf("51","52","53",50,51,52);
sudentCompositeChild.Add(studentLeafChildOne);
sudentCompositeChild.Add(studentLeafChildTwo);
sudentCompositeRoot.Add(sudentCompositeChild);
scores = sudentCompositeRoot.GetStudentScores();
Console.WriteLine(" 总成绩:{0} ", scores);
studentSubjectsName = sudentCompositeRoot.GetStudentSubjects();
Console.WriteLine(" 所有科目名称:{0} ", studentSubjectsName);
StudentLeaf studentLeaf = new StudentLeaf("61", "62", "63", 40, 41, 42);
scores = studentLeaf.GetStudentScores();
Console.WriteLine(" 总成绩:{0} ", scores);
studentSubjectsName = studentLeaf.GetStudentSubjects();
Console.WriteLine(" 所有科目名称:{0} ", studentSubjectsName);
}
}
}
参考资料:
(1)《C# 设计模式》《 Desing Patterns in C#》(美)Steven John Metsker 著, 颜炯 译。
(2)设计模式 可复用面向对象软件的基础 Design Patterns Elements of Reusable Object-Oriented Software 》(美)Erich Gamma Richard Helm Ralph Johnson John Vlissides 著,李英军 等译。