引入:
在面对对象系统时,我们常常会遇到一类具有“容器”特征的对象——即它们在充当对象的同时也是其他对象的容器。
例如:
public interface IBox
{
void Process();
}
public class SingleBox : IBox
{
public void Process()
{
}
}
Container(容器特征对象):里面可能包括SingleBox对象和其他Container对象
/容器特征的对象
public class ContainerBox : IBox
{
private ArrayList list = null;
public void Add(Ibox box)
{
if (list == null)
{
list = new ArrayList();
}
list.Add(box);
}
public void Remove(Ibox box)
{
if (list == null)
throw new Exception();
list.Remove(box);
}
public void Process()
{
//做自己的处理
}
public ArrayList getBoxes()
{
//...
return new ArrayList();
}
}
这时的调用
//客户代码与对象内部结构耦合,希望只与IBox耦合
public void UseBox()
{
IBox box = Factory.GetBox();
if (box is ContainerBox)//依赖对象内部结构
{
box.Process();
ArrayList list = ((ContainerBox)box).getBoxes();
//...将面临比较复杂的处理
}
else if(box is SingleBox)
{
box.Process();
}
}
组合模式
动机
意图
树形结构:对比上方的例子,其中SingleBox即为树型结构的叶子,ContainerBox为树枝。
结构(与代码相结合)
改进后代码
Ibox
public interface Ibox
{
void Process();
void Add(Ibox box);
void Remove(Ibox box);
}
Singlebox
public class Singlebox : Ibox
{
public void Process()
{
}
public void Add(Ibox box)
{
//抛出异常
throw new XXXXException();
}
public void Remove(Ibox box)
{
//抛出异常
throw new XXXXException();
}
}
Containerbox
public class Containerbox : Ibox
{
private ArrayList list = null;
public void Add(Ibox box)
{
if (list == null)
{
list = new ArrayList();
}
list.Add(box);
}
public void Remove(Ibox box)
{
if (list == null)
throw new Exception();
list.Remove(box);
}
public void Process()
{
//做自己的处理
//添加下方来取代GetBox()
if (list != null)
{
foreach (Ibox box in list)
{
box.Process();
}
}
}
使用
public class Uses
{
//客户代码与对象内部结构耦合,希望只与IBox耦合
public void UseBox()
{
IBox box = Factory.GetBox();
box.Process();
}
}
其中,Containerbox中的Add()和Remove()方法处理有两种
1、像上面例子把Add()和Remove()方法放到接口Ibox中,但Singlebox不实现这两个方法,在具体实现时抛出异常。【违反单一职责原则】
2、将Add()和Remove()方法只放到Cintainerbox类中,这样在使用时需要获取Ibox代表的具体类的类型,就像第一个代码一样。
在具体项目中,使用哪种根据项目需求,第一种安全性更高,第二种透明性更好。
要点