【概念介绍】
1.定义:组合模式是将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
2.如图所示:
Component是一个抽象类,在其下面定义所有子类用到的事件、方法;它也可作为对象声明的接口,声明接口用于访问和管理其子部件。而Composite和Leaf可以作为具体类,换句话说,也叫做具体对象(部分),作为部分,可以不必全部继承父类所有的方法事件。这个“部分”可以理解为大树的枝干也可以理解为是大树的叶子。当然,大树会有若干枝干,但是叶子却是大树上最小的不可再分的。但是,为了使得客户端判别事件的简便性,于是,定义了统一的接口。在这里大鸟提到了“透明方式和安全方式”:前者是说,让叶节点对于外界没有区别,它们具备完全一致的行为接口,但是也会存在叶节点不具备某些方法功能的现象,所以存在无意义的方法;后者是说,各个分支都具备实现自己功能的方法,没有多余的方法,此时,树叶和树枝不具有相同的接口,客户端调用需要做相应的判断,这样就会增加工作负荷,带来很大的不便。所以说,还是透明方式和组合模式是一家子啊。
【个人理解】
刚一开始看组合模式前面那个例子:小菜给公司设计那个公司管理模式的时候,我给理解偏了,总公司下面既有分公司也有财务部、人力资源部等,我当时想的是总公司和分公司都是一样的啊,都是公司,日常管理都是一样的啊,在这里哪里体现整体和部分的关系了???要是说财务部啦、人力资源部啦这个和总公司可以说是整体、部分的关系…还是学习的时候不仔细,没有看透组合模式,或许是看大话设计这本书看的太久了,竟然有了和小菜同样的经历,但是没有人家那么高大上,人家做梦梦到超模大赛,将二十三个设计模式外加简单工厂模式演绎的淋漓尽致,我就是中午休憩了一下,梦到了组合模式,下午,竟然想通了…
其实,结合透明方式就不难理解啦,需求中体现部分整体层次的结构时,用户忽略组合对象与单个对象的不同,统一的使用组合结构中的所有对象,这个时候组合模式就可以派上用场啦。
【组合模式的好处】
1.组合模式定义了包含基本对象、组合对象的类的层次结构。基本对象可以被组合成更复杂的组合对象,而这个组合对象又被组合,这样不断地递归下去,客户代码中,任何用到基本对象的地方都可以使用组合对象了。
2.用户是不关心到底是处理一个叶节点还是处理一个组合组件,也就用不着为定义组合而写一些判断语句了。
【活学活用】
了解了组合模式还不够,更重要的是能把所学运用到实际当中,拿书中的例子来说:总公司和各个分公司及总公司下面的财务部、人事部门等。各个分公司可以看作是枝节点可以再细分,财务部等就是叶节点不可以再分。运用组合模式的思想:总公司作为整体可以抽象出一个类来,分公司们(具有相同的方法事件)抽象成一个类,财务部们等也可以抽象出一个类来,它们共同继承总公司这个抽象类的属性、事件、方法,先看一下具体的类图:
也许你会奇怪,公司的下属部门可能不具备Company的所有功能或者是执行事件的具体形式不同,但是我们为了减轻客户端不必要的负荷,可以遵照透明方式的原则进行这样的设计,体现了编码的灵活性。
看到这张类图我们可以很轻松的写出代码来,先看下面是先对各个类进行的定义:
//公司类 抽象类(接口) abstract class Company { protected string name; public Company(string name) { this.name = name; } public abstract void Add(Company c); public abstract void Remove(Company c); public abstract void Display(int depth); public abstract void LineOfDuty();//每个部门或公司会执行不同的职责,在这里只是抽象出来了“履行职责”这个方法,接下来就是具体问题具体分析了。 }
//定义各个具体公司类 class ConcreteCompany : Company { private List<Company> children = new List<Company>(); public ConcreteCompany(string name) : base(name) { } public override void Add(Company c) { children .Add (c); } public override void Remove(Company c) { children .Remove (c); } public override void Display(int depth) { Console .WriteLine (new String ('-',depth )+name); foreach (Company component in children) { component.Display(depth + 2); } } public override void LineOfDuty() { foreach (Company component in children) { component.LineOfDuty(); } } }
//定义各个部门类,继承Company类 class HRDepartment : Company { public HRDepartment(string name) : base(name) { } public override void Add(Company c) { } public override void Remove(Company c) { } public override void Display(int depth) { Console.WriteLine(new String('-', depth) + name); } public override void LineOfDuty() { Console .WriteLine ("{0} 员工招聘培训管理",name ); } }
客户端代码如下:
static void Main(string[] args) { ConcreteCompany root = new ConcreteCompany("加菲猫总公司"); root.Add(new HRDepartment("总公司人力资源部")); root.Add(new FinanceDepartment("总公司财务部")); ConcreteCompany comp = new ConcreteCompany("意大利面分公司"); comp.Add(new HRDepartment("分公司人力资源部")); comp.Add(new FinanceDepartment("分公司财务部")); root.Add(comp);
<span style="white-space:pre"> </span> Console.WriteLine("\n结构图:"); root.Display(1); Console.WriteLine("\n职责:"); root.LineOfDuty(); Console.Read(); }【小结】
总感觉每个设计模式都有着相一致的套路,可能是设计模式学的久了,学多了,把概念弄混了吧:完全贯彻面向对象的思想,尽可能多的体现六大设计原则,尽可能的抽象出类来,尽量减少耦合性,无时无刻不再向着OO精神:可维护、可扩展、可复用、灵活性好这方面靠拢。没错啊,编程是一门技术,更是一门艺术。