来源:http://blog.csdn.net/shift_wwx/article/details/79174239
一、定义
组合模式,也称作部分整体模式。是结构型设计模式之一。组合模式画成图就是数据结构中的树结构,有一个根节点,然后有很多分支。将最顶部的根节点叫做根结构件,将有分支的节点叫做枝干构件,将没有分支的末端节点叫做叶子构件。
组合模式又有透明组合模式、安全组合模式之分。
使用场景:
- 想表示对象的部分-整体层次结构时。
- 希望用户忽略单个对象和组合对象的不同,对对象使用具有统一性时。
- 从一个整体中能够独立出部分模块或功能时。
二、透明组合模式
对于透明组合模式,无论是枝干构件还是叶子构件,都有相同的固定接口。
- Component:抽象节点,为组合中的对象声明接口,适当的时候实现所有类的公有接口方法的默认行为。
- Composite:定义所有枝干节点的行为,存储子节点,实现相关操作。
- Leaf:叶子节点,没有子节点,实现相关对象的行为。
来看下示例:
/**抽象节点*/
public abstract class Component {
protected String mName;
public Component(String name) {
this.mName = name;
}
public abstract void operate();
public abstract void add(Component child);
public abstract void remove(Component child);
public abstract Component get(int index);
}
/**树干节点*/
public class Composite extends Component {
private List<Component> components = new ArrayList<>();
public Composite(String name) {
super(name);
}
@Override
public void operate() {
System.out.println(name);
if (null!=components){
for (Component c:components) {
c.operate();
}
}
}
public void add(Component child){
components.add(child);
}
public void remove(Component child){
components.remove(child);
}
public Component get(int index){
return components.get(index);
}
}
/**叶子节点*/
public class Leaf extends Component {
public Leaf(String name) {
super(name);
}
@Override
public void operate() {
System.out.println(name);
}
@Override
public void add(Component child) {
throw new UnsupportedOperationException("叶子节点没有子节点");
}
@Override
public void remove(Component child) {
throw new UnsupportedOperationException("叶子节点没有子节点");
}
@Override
public Component get(int index) {
throw new UnsupportedOperationException("叶子节点没有子节点");
}
}
当然,在抽象节点中的add、remove、get可以默认实现,这样如果叶子节点不需要重写可以直接继承。
客户端代码:
public class CLient {
public static void main(String[] args) {
Component root = new Composite("root");
Component branch1 = new Composite("branch1");
Component branch2 = new Composite("branch2");
Component branch3 = new Composite("branch3");
Component leaf1 = new Leaf("leaf1");
Component leaf2 = new Leaf("leaf2");
Component leaf3 = new Leaf("leaf3");
branch1.add(leaf1);
branch3.add(leaf2);
branch3.add(leaf3);
root.add(branch1);
root.add(branch2);
root.add(branch3);
root.operate();
}
}
结果如下:
三、安全组合模式
来看下实例:
/**抽象节点*/
public abstract class Component {
protected String mName;
public Component(String name) {
this.mName = name;
}
public abstract void operate();
}
/**树干节点*/
public class Composite extends Component {
private List<Component> components = new ArrayList<>();
public Composite(String name) {
super(name);
}
@Override
public void operate() {
System.out.println(name);
if (null!=components){
for (Component c:components) {
c.operate();
}
}
}
public void add(Component child){
components.add(child);
}
public void remove(Component child){
components.remove(child);
}
public Component get(int index){
return components.get(index);
}
}
/**叶子节点*/
public class Leaf extends Component {
public Leaf(String name) {
super(name);
}
@Override
public void operate() {
System.out.println(name);
}
}
客户端调用跟上面的透明组合模式相同。
对于安全模式,会将抽象节点(component)中只有枝干构件才会有的方法(如这里的add、remove、get)放到枝干节点(composite)中实现。客户端应用程序不可能错误地调用叶子构件的聚集方法,因为叶子构件没有这些方法,调用会导致编译错误。
四、两种实现方法的选择
这里所说的安全性合成模式是指:从客户端使用合成模式上看是否更安全,如果是安全的,那么就不会有发生误操作的可能,能访问的方法都是被支持的。这里所说的透明性合成模式是指:从客户端使用合成模式上,是否需要区分到底是“树枝对象”还是“树叶对象”。如果是透明的,那就不用区分,对于客户而言,都是Compoent对象,具体的类型对于客户端而言是透明的,是无须关心的。
对于合成模式而言,在安全性和透明性上,会更看重透明性,毕竟合成模式的目的是让客户端不再区分操作的是树枝对象还是树叶对象,而是以一个统一的方式来操作。
而且对于安全性的实现,需要区分是树枝对象还是树叶对象。有时候,需要将对象进行类型转换,却发现类型信息丢失了,只好强行转换,这种类型转换必然是不够安全的。
因此在使用合成模式的时候,建议多采用透明性的实现方式。
五、Android中使用的组合模式
Android中常用的就是这个结构,有了View这个抽象节点,会有很多继承自View的叶子节点,例如,TextView。还有以后自定义的View都可以继承自View。枝干节点为ViewGroup,相当于一个容器,会存放很多叶子节点View。
六、优缺点
优点
- 可以清楚定义分层次的复杂对象,表示全部或部分层次,让高层忽略层次的差异,方便对整个层次结构进行控制。
- 高层模块可以一致的使用一个组合结构或其中的单个对象,不必挂心处理的是单个对象还是整个组合结构,简化了高层模块的代码。
- 增加新的枝干和叶子构件都很方便,无需对现有类进行任何修改,就像增加一个自定义View一样。
- 将对象之间的关系形成树形结构,便于控制。
缺点
设计变得更加抽象,因此很难限制组合中的组件,因为他们都来自相同的抽象层。所以必须在运行时进行类型检查才能实现。
更多的设计模式看:Android中设计模式