Design Patterns之Composite Pattern總結(jié)
本文總結(jié)一下今天學(xué)習(xí)的Composite(組合)模式。內(nèi)容主要基于李建忠WebCast《C#面向?qū)ο笤O(shè)計(jì)模式縱橫談》。
首先,看一下Composite模式的意圖:將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。Composite模式使得用戶對單個(gè)對象和組合對象的使用具有一致性。――GOF 《設(shè)計(jì)模式》
我們看這們個(gè)例子:我們有兩類盒子,設(shè)為A類和B類,A類盒子的內(nèi)部還裝有盒子,而B類盒子內(nèi)部不能裝盒子,A類盒內(nèi)部裝的盒子既可以是A類的也可以是B類的,假設(shè)現(xiàn)在桌子上放有許多盒子(可能是A類或B類盒子),要求計(jì)算桌子上的總盒子數(shù),如果是A類盒子,則需要算上它內(nèi)部的盒子數(shù),比如桌上有1個(gè)A類盒子box1和1個(gè)B類盒子box2,A類盒子內(nèi)有1個(gè)B類盒子box3和1個(gè)A類盒子box4,這個(gè)box4內(nèi)又裝有3個(gè)B類盒子box5,box6,box7,那么總盒子數(shù)就是7。
那現(xiàn)在要怎么做呢?A、B兩類盒子都是盒子,那我們就定義一個(gè)盒子接口,GetBoxCount()方法將返回此盒子內(nèi)的所有盒子數(shù)。
public interface IBox
{
//取得盒子總數(shù)
int GetBoxCount();
}
然后是A類和B類盒子:
/// <summary>
/// 表示B類盒子,內(nèi)部不能再裝盒子,用SingleBox作類名,一會不容易搞混
/// </summary>
public class SingleBox : IBox
{
//取得盒子總數(shù)
public int GetBoxCount()
{
return 1;
}
}
/// <summary>
/// A類盒子,內(nèi)部可再裝盒子,用“盒子容器”作類名
/// </summary>
public class BoxContainer : IBox
{
//private List<SingleBox> boxes;
private List<IBox> boxes;
//添加盒子
public void Add(IBox box)
{
if (boxes == null)
{
//boxes = new List<SingleBox>();
boxes = new List<IBox>();
}
boxes.Add(box);
}
//刪除盒子
public void Remove(IBox box)
{
if ( (boxes == null) || (boxes.Count == 0) )
{
throw new Exception("Sorry,已經(jīng)沒有盒子可Remove了?");
}
boxes.Remove(box);
}
//取得盒子總數(shù)
public int GetBoxCount()
{
int count = 1; //因?yàn)锽oxContainer本身就是一個(gè)盒子,所以初始化為1
if ( (boxes != null) && (boxes.Count > 0) )
{
foreach (IBox box in boxes)
{
count += box.GetBoxCount();
}
}
return count;
}
}
然后就可以在Main()方法中測試了:
public static void Main(string[] args)
{
//新建4個(gè)內(nèi)部不能裝盒子的盒子
IBox box1 = new SingleBox();
IBox box2 = new SingleBox();
IBox box3 = new SingleBox();
IBox box4 = new SingleBox();
//新建 2個(gè)內(nèi)部可以裝盒子的盒子
BoxContainer boxContainer1 = new BoxContainer();
BoxContainer boxContainer2 = new BoxContainer();
//把box2,box3裝入boxContainer2
boxContainer2.Add(box2);
boxContainer2.Add(box3);
//把box4和boxContainer2裝入boxContainer1
boxContainer1.Add(box4);
boxContainer1.Add(boxContainer2);
//求總盒子數(shù)并輸出
int total = box1.GetBoxCount() + boxContainer1.GetBoxCount();
Console.WriteLine("Total:{0}", total);
}
我們可以得到結(jié)果:Total:6
可以看到,雖然A類和B類是不同的盒子,但客戶程序卻可以不去理會盒子內(nèi)部還有沒有裝盒子,裝的是什么盒子,只要簡簡單單地調(diào)用GetBoxCount()方法。這樣的話,客戶程序就可以跟A類盒子(內(nèi)部可以再裝盒子)的內(nèi)部結(jié)構(gòu)解耦。BoxContainer類就是Composite模式中的組合類,它內(nèi)部可以再裝有盒子。
同時(shí)注意到BoxContainer類的私有成員boxes是被聲明為List,而不是注釋中的List,雖然本例中聲明為List也可以,但是當(dāng)B類盒子不只一種時(shí)就不行了,聲明為List也體現(xiàn)了面向?qū)ο蟪绦蛟O(shè)計(jì)中依賴抽象而不是依賴實(shí)現(xiàn)的思想。
上面的Composite模式叫安全的Composite模式(為什么叫安全的?在段尾見答案),因?yàn)閷τ赟ingleBox來說,內(nèi)部不能裝盒子,所以沒有Add和Remove方法,而BoxContainer有,但這種模式卻導(dǎo)致了SingleBox和BoxContainer的接口不一致。還有一種Composite模式叫透明的Composite模式,它把Add和Remove等這些操作子對象的方法定義在IBox接口中,這樣接口就一致了(比如在Main方法中就都可以用IBox來聲明一個(gè)BoxContainer了:IBox boxContainer1 = new BoxContainer();),但是SingleBox里用Add和Remove明顯是不行的,所以,在SingleBox的Add和Remove方法中都拋出一個(gè)異常,而在安全的Composite模式中是沒有這個(gè)問題的,所以才叫安全的Composite模式。在實(shí)際應(yīng)用中選擇哪種Composite模式,要根據(jù)具體情況來看,其實(shí)也就是權(quán)衡安全性和透明性的問題了。
總 結(jié):
1. Composite(組合)模式解耦了客戶程序與復(fù)雜元素內(nèi)部結(jié)構(gòu),從而使客戶程序可以像處理簡單元素一樣來處理復(fù)雜元素。
2. 有安全型的Composite模式和透明型的Composite模式,在它們中做選擇也就是在安全性和透明性中找個(gè)平衡點(diǎn)。
首先,看一下Composite模式的意圖:將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。Composite模式使得用戶對單個(gè)對象和組合對象的使用具有一致性。――GOF 《設(shè)計(jì)模式》
我們看這們個(gè)例子:我們有兩類盒子,設(shè)為A類和B類,A類盒子的內(nèi)部還裝有盒子,而B類盒子內(nèi)部不能裝盒子,A類盒內(nèi)部裝的盒子既可以是A類的也可以是B類的,假設(shè)現(xiàn)在桌子上放有許多盒子(可能是A類或B類盒子),要求計(jì)算桌子上的總盒子數(shù),如果是A類盒子,則需要算上它內(nèi)部的盒子數(shù),比如桌上有1個(gè)A類盒子box1和1個(gè)B類盒子box2,A類盒子內(nèi)有1個(gè)B類盒子box3和1個(gè)A類盒子box4,這個(gè)box4內(nèi)又裝有3個(gè)B類盒子box5,box6,box7,那么總盒子數(shù)就是7。
那現(xiàn)在要怎么做呢?A、B兩類盒子都是盒子,那我們就定義一個(gè)盒子接口,GetBoxCount()方法將返回此盒子內(nèi)的所有盒子數(shù)。
public interface IBox
{
//取得盒子總數(shù)
int GetBoxCount();
}然后是A類和B類盒子:
/// <summary>
/// 表示B類盒子,內(nèi)部不能再裝盒子,用SingleBox作類名,一會不容易搞混
/// </summary>
public class SingleBox : IBox
{
//取得盒子總數(shù)
public int GetBoxCount()
{
return 1;
}
}
/// <summary>
/// A類盒子,內(nèi)部可再裝盒子,用“盒子容器”作類名
/// </summary>
public class BoxContainer : IBox
{
//private List<SingleBox> boxes;
private List<IBox> boxes;
//添加盒子
public void Add(IBox box)
{
if (boxes == null)
{
//boxes = new List<SingleBox>();
boxes = new List<IBox>();
}
boxes.Add(box);
}
//刪除盒子
public void Remove(IBox box)
{
if ( (boxes == null) || (boxes.Count == 0) )
{
throw new Exception("Sorry,已經(jīng)沒有盒子可Remove了?");
}
boxes.Remove(box);
}
//取得盒子總數(shù)
public int GetBoxCount()
{
int count = 1; //因?yàn)锽oxContainer本身就是一個(gè)盒子,所以初始化為1
if ( (boxes != null) && (boxes.Count > 0) )
{
foreach (IBox box in boxes)
{
count += box.GetBoxCount();
}
}
return count;
}
}然后就可以在Main()方法中測試了:
public static void Main(string[] args)
{
//新建4個(gè)內(nèi)部不能裝盒子的盒子
IBox box1 = new SingleBox();
IBox box2 = new SingleBox();
IBox box3 = new SingleBox();
IBox box4 = new SingleBox();
//新建 2個(gè)內(nèi)部可以裝盒子的盒子
BoxContainer boxContainer1 = new BoxContainer();
BoxContainer boxContainer2 = new BoxContainer();
//把box2,box3裝入boxContainer2
boxContainer2.Add(box2);
boxContainer2.Add(box3);
//把box4和boxContainer2裝入boxContainer1
boxContainer1.Add(box4);
boxContainer1.Add(boxContainer2);
//求總盒子數(shù)并輸出
int total = box1.GetBoxCount() + boxContainer1.GetBoxCount();
Console.WriteLine("Total:{0}", total);
}我們可以得到結(jié)果:Total:6
可以看到,雖然A類和B類是不同的盒子,但客戶程序卻可以不去理會盒子內(nèi)部還有沒有裝盒子,裝的是什么盒子,只要簡簡單單地調(diào)用GetBoxCount()方法。這樣的話,客戶程序就可以跟A類盒子(內(nèi)部可以再裝盒子)的內(nèi)部結(jié)構(gòu)解耦。BoxContainer類就是Composite模式中的組合類,它內(nèi)部可以再裝有盒子。
同時(shí)注意到BoxContainer類的私有成員boxes是被聲明為List
上面的Composite模式叫安全的Composite模式(為什么叫安全的?在段尾見答案),因?yàn)閷τ赟ingleBox來說,內(nèi)部不能裝盒子,所以沒有Add和Remove方法,而BoxContainer有,但這種模式卻導(dǎo)致了SingleBox和BoxContainer的接口不一致。還有一種Composite模式叫透明的Composite模式,它把Add和Remove等這些操作子對象的方法定義在IBox接口中,這樣接口就一致了(比如在Main方法中就都可以用IBox來聲明一個(gè)BoxContainer了:IBox boxContainer1 = new BoxContainer();),但是SingleBox里用Add和Remove明顯是不行的,所以,在SingleBox的Add和Remove方法中都拋出一個(gè)異常,而在安全的Composite模式中是沒有這個(gè)問題的,所以才叫安全的Composite模式。在實(shí)際應(yīng)用中選擇哪種Composite模式,要根據(jù)具體情況來看,其實(shí)也就是權(quán)衡安全性和透明性的問題了。
總 結(jié):
1. Composite(組合)模式解耦了客戶程序與復(fù)雜元素內(nèi)部結(jié)構(gòu),從而使客戶程序可以像處理簡單元素一樣來處理復(fù)雜元素。
2. 有安全型的Composite模式和透明型的Composite模式,在它們中做選擇也就是在安全性和透明性中找個(gè)平衡點(diǎn)。


浙公網(wǎng)安備 33010602011771號