1. 意图
将对象组合成树形结构以表示“部分-整体” 的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。
Composite模式的关键是一个抽象类,它既可以代表图元,又开始代表图元的容器。
2.适用性
在以下情况使用Composite模式
你想表示对象的部分-整体层次结构
你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
3.类图
4. 参与着
Component, Leaf, Composite, Client
5. Composite的目的是为了为调用者提供操作的一致性,因此Leaf与Composite都继承自抽象的Component
要注意的是.NET Framework 中的 XMLNode ,TreeNode 提供的容器对象 并不继承自同样的接口,因此不是Composite模式
注意上图的add, remove和getChild()方法,通常这些被认为是声明管理子部件的操作,问题是对于Leaf对象,这些操作并没有意义
此时有两种办法:
1) 将add() remove()等操作定义在Composite中,不定义在Component中, 这种做法被称为 安全性
这种做法的缺点是Leaf 和 Composite有不同的接口,因此调用者必须知道调用的对象是Leaf还是Composite,做一个类型转换
2) 将add() remove() 等操作定义在 Component中, 这种做法被称为 透明性
缺点是add , remove 对象可能会导致一些无意义的操作
通常会更加强调透明性(这正是Comosite模式的主要目的), 当然我们需要用一些技巧来避免透明性带来的缺点。
6. 实例
考虑以下的一个场景,某个大规模集团军的战斗
class Program
{
static void Main(string[] args)
{
}
}
interface ICommand
{
void Attack();
void Add(ICommand command);
void Remove(ICommand command);
string Name { get; set; }
ICommand Owner { get; set; }
List<ICommand> GetChilds();
ICommand GetArmy();
}
class Army : ICommand
{
protected List<ICommand> cmdList = null;
public Army(ICommand owner, string name)
{
this.Name = name;
cmdList = new List<ICommand>();
}
public string Name { get; set; }
public ICommand Owner { get; set; }
public void Attack()
{
Console.WriteLine(Name + " joins the battle");
foreach (ICommand cmd in cmdList)
cmd.Attack();
}
public void Add(ICommand command)
{
command.Owner = this;
cmdList.Add(command);
Console.WriteLine(command.Name + " joins the " + Name);
}
public void Remove(ICommand command)
{
if (cmdList.IndexOf(command) > -1)
cmdList.Remove(command);
Console.WriteLine(command.Name + " leaves the " + Name);
}
public ICommand GetArmy()
{
return this;
}
public List<ICommand> GetChilds()
{
return cmdList;
}
}
class Soldier : ICommand
{
public Soldier(ICommand owner, string name)
{
if (owner == null)
throw new NotSupportedException("soldier must belong to an army");
this.Name = name;
this.Owner = owner;
}
public string Name
{
get;
set;
}
public ICommand Owner
{
get;
set;
}
public void Attack()
{
Console.WriteLine(Name + " joins the battle");
}
public void Add(ICommand command)
{
}
public void Remove(ICommand command)
{
}
public List<ICommand> GetChilds()
{
return null;
}
public ICommand GetArmy()
{
return null;
}
}
上面的代码没有调用者的部分,接下来讨论调用者
如果根据需要去创建不同的对象,然后add, remove ... 是一种方法,但是并不优雅
这个时候可以考虑Builder模式, Builder模式定义对象创建的步骤,使得不同的过程可以有不同的表示,非常适合Composite