浅学设计模式之组合模式及在Android中的应用
定义
组合模式允许你将对象组合成树形结构来表现出“整体/部分”层次结构。组合能以一致的方式处理个别对象以及对象组合。
结构图
用户使用Compoment类接口与组合结构中的对象进行交互。如果接受者是一个叶节点,则直接处理请求。如果接受者是Composite,它通常将请求发送给他的子部件,在转发请求之前或者之后可能执行一些辅助操作。
代码示例
component:
public abstract class Component { public int getChildNum(){ throw new UnsupportedOperationException(); }; public Component getChild(int i){ throw new UnsupportedOperationException(); } public String getType(){ throw new UnsupportedOperationException(); }; public String getName(){ throw new UnsupportedOperationException(); }; public void add(Component c){ throw new UnsupportedOperationException(); }; public void remove(Component c){ throw new UnsupportedOperationException(); }; // public abstract void print(); }
leaf:
public class Leaf extends Component { private String strType = "leat"; private String strName = "Leat"; public Leaf(String strName){ this.strName = strName; } public String getType(){ return strType; }; public String getName(){ return strName; }; @Override public void print() { // TODO Auto-generated method stub System.out.println("i am "+getName()); } }
composite:
public class Branches extends Component { private ArrayList list; private String strType = "composite"; private String strName = "Branches"; public Branches(String strName){ list = new ArrayList(); this.strName = strName; } public int getSize(){ return list.size(); }; public int getChildNum(){ return list.size(); }; public Component getChild(int i){ if(i<=list.size()){ return (Component) list.get(i); } else { return null; } } public String getType(){ return strType; }; public String getName(){ return strName; }; public void add(Component c){ list.add(c); }; public void remove(Component c){ list.remove(c); }; @Override public void print() { // TODO Auto-generated method stub Iterator iterator = list.iterator(); while(iterator.hasNext()){ ((Component)iterator.next()).print(); System.out.println("belong to "+getName()); } System.out.println("i am "+getName()); } }
public class Tree extends Component { private ArrayList list; private String strType = "composite"; private String strName = "Tree"; public Tree(String strName){ list = new ArrayList(); this.strName = strName; } public int getSize(){ return list.size(); }; public int getChildNum(){ return list.size(); }; public Component getChild(int i){ if(i<=list.size()){ return (Component) list.get(i); } else { return null; } } public String getType(){ return strType; }; public String getName(){ return strName; }; public void add(Component c){ list.add(c); }; public void remove(Component c){ list.remove(c); }; @Override public void print() { // TODO Auto-generated method stub Iterator iterator = list.iterator(); while(iterator.hasNext()){ ((Component)iterator.next()).print(); } System.out.println("i am "+getName()); } }
client:
public static void main(String[] args) { // TODO Auto-generated method stub Component tree = new Tree("杨树"); Component branches1 = new Branches("branches1"); Component branches2 = new Branches("branches2"); Component branches3 = new Branches("branches3"); Component branches4 = new Branches("branches4"); Component leaf1 = new Leaf("leaf1"); Component leaf2 = new Leaf("leaf2"); Component leaf3 = new Leaf("leaf3"); Component leaf4 = new Leaf("leaf4"); Component leaf5 = new Leaf("leaf5"); Component leaf6 = new Leaf("leaf6"); Component leaf7 = new Leaf("leaf7"); Component leaf8 = new Leaf("leaf8"); tree.add(branches1); tree.add(branches2); tree.add(branches3); tree.add(branches4); branches1.add(leaf1); branches1.add(leaf2); branches2.add(leaf3); branches2.add(leaf4); branches3.add(leaf5); branches3.add(leaf6); branches4.add(leaf7); branches4.add(leaf8); tree.print(); }
测试结果:
i am leaf1 belong to branches1 i am leaf2 belong to branches1 i am branches1 i am leaf3 belong to branches2 i am leaf4 belong to branches2 i am branches2 i am leaf5 belong to branches3 i am leaf6 belong to branches3 i am branches3 i am leaf7 belong to branches4 i am leaf8 belong to branches4 i am branches4 i am 杨树
该代码用树(此树非数据结构中的树)来示范组合模式。代码较简单,但能清晰的体现组合模式的优点。
深入分析
将客户代码与复杂的对象容器结构解耦是组合模式的核心思想,解耦之后,客户代码将与纯粹的抽象接口——而非对象容器的复内部实现结构——发生依赖关系,从而更能应对变化。
组合模式中必须提供对子对象的管理方法,不然无法完成对子对象的添加删除等等操作,也就失去了灵活性和扩展性。但是管理方法是在Component中就声明还是在Composite中声明呢?一种方式是在Component里面声明所有的用来管理子类对象的方法,以达到Component接口的最大化。目的就是为了使客户看来在接口层次上树叶和分支没有区别——透明性。但树叶是不存在子类的,因此声明的一些方法对于树叶来说是不适用的。这样也就带来了一些安全性问题。另一种方式就是只在Composite里面声明所有的用来管理子类对象的方法。这样就避免了上一种方式的安全性问题,但是由于叶子和分支有不同的接口,所以又失去了透明性。《设计模式》一书认为:在这一模式中,相对于安全性,我们比较强调透明性。对于第一种方式中叶子节点内不需要的方法可以使用空处理或者异常报告的方式来解决。
组合模式在具体实现中,可以让父对象中的子对象反向追溯;如果父对象有频繁的遍历需求,可使用缓存技巧来改善效率。
要点
-
Composite模式采用树形结构来实现普遍存在的对象容器,从而将“一对多”的关系转化为“一对一”的关系,使得客户代码可以一致的处理对象和对象容器,无需关心处理的是单个对象,还是组合的对象容器。
将“客户代码与复杂的对象容器结构”解耦是Composite模式的核心思想,解耦之后,客户代码将与纯粹的对象接口——而非对象容器的复杂内部实现结构——发生依赖关系,从而更能“应对变化”。
Composite模式中,是将“Add和Remove的和对象容器相关的方法”定义在“表示抽象对象的Component类”中,还是将其定义在“表示对象容器的Composite类”中,是一个关乎“透明性”和“安全性”的两难问题,需要仔细权衡结构,这又是必须付出的代价。
Composite模式在具体实现中,可以让父对象中的字对象反向追溯:如果父对象有频繁的遍历需求,可使用缓存技巧来改善效率
适用性:
以下情况使用Composite模式:
- 想表示对象的部分-整体层次结构。
- 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
优点:
- 组合模式可以很容易的增加新的构件。
- 使用组合模式可以使客户端变的很容易设计,因为客户端可以对组合和叶节点一视同仁。
缺点:
- 使用组合模式后,控制树枝构件的类型不太容易。
- 用继承的方法来增加新的行为很困难。
在android中的应用
在android中,View类是典型的组合模式。
具体图: