一、概念
组合模式关注那些存在叶子构件和容器构件的结构以及它们的组织形式。一般处理具有“容器”特征的对象,它们既可以充当普通对象,有可以作为其它对象的容器,说白了就是像文件夹一样的,可以包含别人但又被别人包含。将这些对象的联系弄成一个树形结构以表示“整体-部分”的结构层次。
二、角色
1.抽象构件Componet
接口或者抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现。比如增加、删除、获取子构件等。
2.叶子构件Leaf
叶子节点对象,没有子节点,对于访问子构件的方法可以通过异常等方式处理。
3.容器构件Composite
容器节点对象,包含子节点(可以是叶子构件或者容器构件),提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括访问、管理子构件的方法,在其业务方法中可以递归调用其子节点的业务方法。
4.客户类Client
通过抽象构件接口访问和控制组合构件中的对象。
三、透明组合模式和安全组合模式
组合模式根据抽象构件类的定义形式,分为两种模式
1.透明组合模式
抽象构件类声明了叶子构件和容器构件的所有方法。但叶子构件和容器构件本质上有区别,叶子构件没有下一层对象,所以添加、删除、访问子对象的方法是没有意义的。编译阶段不出错但运行时调用可能出错。
2.安全组合模式
抽象构件只声明容器构件和叶子构件共同需要的方法,即不声明管理子成员对象的方法,因为叶子构件不需要这些方法。
四、代码举例
大盘子装2个中盘子、1个苹果、2个桃子
每个中盘子装2个小盘子(其中1个小盘子为空,另1个小盘子装1个苹果)、1个苹果、1个桃子
package zuhe; import java.util.ArrayList; public abstract class Componet{ public abstract void eat(); } class Apple extends Componet{ String name; public Apple(String name) { this.name=name; } public void eat() { System.out.println(name); } } class Peach extends Componet{ String name; public Peach(String name) { this.name=name; } public void eat() { System.out.println(name); } } class B_plate extends Componet{ String name; private ArrayList<Componet> list=new ArrayList<Componet> (); public B_plate(String name) { this.name=name; } public void add(Componet componet) { list.add(componet); } public void remove(Componet componet) { list.remove(componet); } public void eat() { System.out.println(".................."+name+".................."); for(Object obj:list) { ((Componet)obj).eat(); } System.out.println(".................."+name+".................."); } } class M_plate extends Componet{ String name; private ArrayList<Componet> list=new ArrayList<Componet> (); public M_plate(String name) { this.name=name; } public void add(Componet componet) { list.add(componet); } public void remove(Componet componet) { list.remove(componet); } public void eat() { System.out.println(".................."+name+".................."); for(Object obj:list) { ((Componet)obj).eat(); } System.out.println(".................."+name+".................."); } } class S_plate extends Componet{ String name; private ArrayList<Componet> list=new ArrayList<Componet> (); public S_plate(String name) { this.name=name; } public void add(Componet componet) { list.add(componet); } public void remove(Componet componet) { list.remove(componet); } public void eat() { System.out.println(".................."+name+".................."); for(Object obj:list) { ((Componet)obj).eat(); } System.out.println(".................."+name+".................."); } }
package zuhe; public class Client { public static void main(String[] args) { B_plate b=new B_plate("大盘子"); M_plate m1=new M_plate("中盘子1"); M_plate m2=new M_plate("中盘子2"); S_plate s11=new S_plate("小盘子11"); S_plate s12=new S_plate("小盘子12"); S_plate s21=new S_plate("小盘子21"); S_plate s22=new S_plate("小盘子22"); s11.add(new Apple("苹果0")); m1.add(s11); m1.add(s12); m1.add(new Apple("苹果2")); m1.add(new Peach("桃子1")); s21.add(new Apple("苹果1")); m2.add(s21); m2.add(s22); m1.add(new Apple("苹果3")); m1.add(new Peach("桃子2")); b.add(m1); b.add(m2); b.eat(); } }
输出:
..................大盘子..................
..................中盘子1..................
..................小盘子11..................
苹果0
..................小盘子11..................
..................小盘子12..................
..................小盘子12..................
苹果2
桃子1
苹果3
桃子2
..................中盘子1..................
..................中盘子2..................
..................小盘子21..................
苹果1
..................小盘子21..................
..................小盘子22..................
..................小盘子22..................
..................中盘子2..................
..................大盘子..................
五、优缺点
优点:清楚地定义分层的复杂对象。客户端调用简单,可以一致的使用组合结构或其中单个对象。方便添加新构件。
缺点:使设计变得抽象,如果业务复杂,代码难写,不是所有的方法都与叶子对象子类有关联。
(书上那些看着又抽象又虚的内容就不记录了)