组合模式
将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性
组合模式的通用类图
Component是抽象构件角色,定义参加组合对象的共有方法和属性,可以定义一些默认的行为或属性。 Leaf是叶子构件,其下再没有其他的分支,是遍历的最小单位。Composite是树枝构件,作用是组合树枝节点和叶子节点形成一个树形结构。
组合模式的通用源码
-
抽象构件
public abstract class Component { //个体和整体都具有的共享 public void doSomething(){ //编写业务逻辑 } }
-
树枝构件
public class Composite extends Component { //构件容器 private ArrayList<Component> componentArrayList = new ArrayList<Component>(); //增加一个叶子构件或树枝构件 public void add(Component component){ this.componentArrayList.add(component); } //删除一个叶子构件或树枝构件 public void remove(Component component){ this.componentArrayList.remove(component); } //获得分支下的所有叶子构件和树枝构件 public ArrayList<Component> getChildren(){ return this.componentArrayList; } }
-
树叶构件
public class Leaf extends Component { /* * 可以覆写父类方法 * public void doSomething(){ * * } */ }
-
场景类
public class Client { public static void main(String[] args) { //创建一个根节点 Composite root = new Composite(); root.doSomething(); //创建一个树枝构件 Composite branch = new Composite(); //创建一个叶子节点 Leaf leaf = new Leaf(); //建立整体 root.add(branch); branch.add(leaf); } //通过递归遍历树 public static void display(Composite root){ for(Component c:root.getChildren()){ if(c instanceof Leaf){ //叶子节点 c.doSomething(); }else{ //树枝节点 display((Composite)c); } } } }
二、组合模式的优点
-
高层模块调用简单
树形结构中所有的节点都是Component,局部和整体对调用者来说没有任何区别。
-
节点自由增加
三、组合模式的缺点
- 树叶和树枝直接使用了实现类,与依赖倒置原则冲突,限制了接口的影响范围
四、组合模式的使用场景
-
维护和展示部分-整体关系的场景
如树形菜单、文件和文件夹管理等
-
从一个整体能够独立出部分模块或功能的场景
注意:只要是树形结构,就要考虑使用组合模式。只要是体现局部和整体的关系,而且这种关系还比较深时,考虑用组合模式。
五、扩展
-
组合模式的不同实现:透明模式和安全模式
上面的为安全模式,透明模式通用类图如下
透明模式是把用来组合使用的方法放到抽象类中,不管叶子对象还是树枝对象都有相同的结构,通过判断getChildren的返回值确认是叶子节点还是树枝节点,如果处理不当,可能会在运行期出现问题。安全模式,把树枝节点和树叶节点彻底分开,树枝节点单独拥有用来组合的方法。抽象模式的通用源码
- 抽象构件
public abstract class Component { //个体和整体都具有的共享 public void doSomething(){ //编写业务逻辑 } //增加一个叶子构件或树枝构件 public abstract void add(Component component); //删除一个叶子构件或树枝构件 public abstract void remove(Component component); //获得分支下的所有叶子构件和树枝构件 public abstract ArrayList<Component> getChildren(); }
-
树叶节点
public class Leaf extends Component { @Deprecated public void add(Component component) throws UnsupportedOperationException{ //空实现,直接抛弃一个"不支持请求"异常 throw new UnsupportedOperationException(); } @Deprecated public void remove(Component component)throws UnsupportedOperationException{ //空实现 throw new UnsupportedOperationException(); } @Deprecated public ArrayList<Component> getChildren()throws UnsupportedOperationException{ //空实现 throw new UnsupportedOperationException(); } }
-
树结构遍历
public class Client { //通过递归遍历树 public static void display(Component root){ for(Component c:root.getChildren()){ if(c instanceof Leaf){ //叶子节点 c.doSomething(); }else{ //树枝节点 display(c); } } } }
-
组合模式的遍历
上述树的遍历可以实现从上到下的遍历(根节点到叶子节点),从下往上遍历(子节点到父节点)实现方式只要添加两个方法,setParent设置父节点是谁,getParent查找父节点。即可