组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
结构
组合模式的主要角色分为:
- 抽象组件角色(Component):定义系统各层次对象的共有方法和属性,可以预先定义一些默认行为和属性。
- 叶子角色(Leaf):在组合中表示子节点对象,实现了Component,其下没有分支了。
- 组合角色(Composite):一个组合组件,其下有叶子节点,实现了Component。
优缺点
优点:
- 组合模式屏蔽了对象系统的层次差异性(树节点和叶子节点为不同类型),将客户代码与复杂的容器对象解耦,使得客户端可以忽略层次间的差异,使用一致的行为控制不同层次。
- 在 组合模式可以很方便地增加树枝节点和叶子节点 对象,并对现有类库无侵入,符合开闭原则。
缺点:
- 如果类系统(树形结构)过于庞大,虽然对不同层次都提供一致性操作,但客户端仍需花费时间理清类之间的层次关系。
- 组合模式在具体实现上违背了设计模式 接口隔离原则 或 依赖倒置原则。
代码实现
组合模式分为透明式的组合模式和安全式的组合模式。
透明式组合模式:把所有公共方法都定义在 Component 中,这样做的好处是客户端无需分辨是叶子节点(Leaf)和组合节点(Composite),它们具备完全一致的接口;缺点是叶子节点(Leaf)需要实现一些本来不需要的方法,这就破环了接口隔离原则。
/**
*透明组合模式
*/
package com.yn.design_pattern.composite.universal.transparent;
import java.util.ArrayList;
import java.util.List;
class Client {
public static void main(String[] args) {
// 来一个根节点
Component root = new Composite("root");
// 来一个树枝节点
Component branchA = new Composite("---branchA");
Component branchB = new Composite("------branchB");
// 来一个叶子节点
Component leafA = new Leaf("------leafA");
Component leafB = new Leaf("---------leafB");
Component leafC = new Leaf("---leafC");
root.addChild(branchA);
root.addChild(leafC);
branchA.addChild(leafA);
branchA.addChild(branchB);
branchB.addChild(leafB);
String result = root.operation();
System.out.println(result);
}
// 抽象根节点
static abstract class Component {
protected String name;
public Component(String name) {
this.name = name;
}
public abstract String operation();
public boolean addChild(Component component) {
throw new UnsupportedOperationException("addChild not supported!");
}
public boolean removeChild(Component component) {
throw new UnsupportedOperationException("removeChild not supported!");
}
public Component getChild(int index) {
throw new UnsupportedOperationException("getChild not supported!");
}
}
// 树节点
static class Composite extends Component {
private List<Component> mComponents;
public Composite(String name) {
super(name);
this.mComponents = new ArrayList<>();
}
@Override
public String operation() {
StringBuilder builder = new StringBuilder(this.name);
for (Component component : this.mComponents) {
builder.append("\n");
builder.append(component.operation());
}
return builder.toString();
}
@Override
public boolean addChild(Component component) {
return this.mComponents.add(component);
}
@Override
public boolean removeChild(Component component) {
return this.mComponents.remove(component);
}
@Override
public Component getChild(int index) {
return this.mComponents.get(index);
}
}
//叶子节点
static class Leaf extends Component {
public Leaf(String name) {
super(name);
}
@Override
public String operation() {
return this.name;
}
}
}
安全组合模式:统一行为(Component)只规定系统各个层次的最基础的一致行为,而把组合(树节点)本身的方法(管理子类对象的添加,删除等)放到自身当中。这样做的好处是接口定义职责清晰,符合设计模式 单一职责原则和接口隔离原则;缺点是客户需要区分树枝节点(Composite)和叶子节点(Leaf),这样才能正确处理各个层次的操作,客户端无法依赖抽象(Component),违背了设计模式依赖倒置原则。
安全组合模式相对于透明组合模式需进行修改代码如下:
/**
*安全组合模式
*/
// 抽象根节点
static abstract class Component {
protected String name;
public Component(String name) {
this.name = name;
}
public abstract String operation();
}
class Client {
public static void main(String[] args) {
// 来一个根节点
Composite root = new Composite("root");
// 来一个树枝节点
Composite branchA = new Composite("---branchA");
Composite branchB = new Composite("------branchB");
// 来一个叶子节点
Component leafA = new Leaf("------leafA");
Component leafB = new Leaf("---------leafB");
Component leafC = new Leaf("---leafC");
root.addChild(branchA);
root.addChild(leafC);
branchA.addChild(leafA);
branchA.addChild(branchB);
branchB.addChild(leafB);
String result = root.operation();
System.out.println(result);
}
}
控制台输出结果:
root
---branchA
------leafA
------branchB
---------leafB
---leafC