组合模式(Composite Pattern)
- 组合模式分为透明组合模式和安全组合模式
透明组合模式:抽象构件声明了所有子类中的全部方法,客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。
安全组合模式:将管理子构件的方法移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,这样就避免了上一种方式的安全性问题。 - 优点
1、高层模块调用简单。
2、节点自由增加。 - 缺点
1、设计较复杂,客户端需要花更多时间理清类之间的层次关系;
2、不容易限制容器中的构件;
3、不容易用继承的方法来增加构件的新功能; - 组合模式包含以下主要角色
抽象构件角色:为树叶构件和树枝构件声明公共接口。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。
树枝构件角色:实现抽象构件,含有子节点。它的主要作用是存储和管理子节点。
树叶构件角色:实现抽象构件,它没有子节点。 - **例子:**用透明组合模式和安全组合模式分别实现如下树结构,并遍历所有节点
- 透明组合模式:在该方式中,由于抽象构件声明了所有子类中的全部方法,所以客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。但其缺点是:树叶构件本来没有 Add()、Remove() 及 GetChild() 方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题
抽象构件角色
public interface Component {
// 添加节点
void add(Component c);
// 删除节点
void remove(Component c);
// 获取节点
Component getChild(int i);
// 操作
void show();
}
树枝构件角色
public class Branch implements Component {
private String name;
private List<Component> children;
public Branch(String name) {
children = new ArrayList<>();
this.name = name;
}
@Override
public void add(Component c) {
children.add(c);
}
@Override
public void remove(Component c) {
children.remove(c);
}
@Override
public Component getChild(int i) {
return children.get(i);
}
@Override
public void show() {
for (Component child : children) {
child.show();
}
}
@Override
public String toString() {
return "{" + "branch=" + name + ", children=" + children.toString() + "}";
}
}
树叶构件角色
public class Leaf implements Component {
private String name;
public Leaf(String name) {
this.name = name;
}
@Override
public void add(Component c) {
}
@Override
public void remove(Component c) {
}
@Override
public Component getChild(int i) {
return null;
}
@Override
public void show() {
System.out.println(name + ":被访问!");
}
@Override
public String toString() {
return name;
}
}
测试
public class Test {
public static void main(String[] args) {
Component root = new Branch("根节点");
Component branch1 = new Branch("树枝节点1");
Component leaf1 = new Leaf("叶子节点1");
Component leaf2 = new Leaf("叶子节点2");
Component leaf3 = new Leaf("叶子节点3");
root.add(leaf1);
branch1.add(leaf2);
branch1.add(leaf3);
root.add(branch1);
root.operation();
System.out.println("结构:" + root.toString());
}
}
// 运行结果
叶子节点1:被访问!
叶子节点2:被访问!
叶子节点3:被访问!
结构:{branch=根节点, children=[叶子节点1, {branch=树枝节点1, children=[叶子节点2, 叶子节点3]}]}
- 安全组合模式:在该方式中,将管理子构件的方法移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,这样就避免了上一种方式的安全性问题,但由于叶子和分支有不同的接口,客户端在调用时要知道树叶对象和树枝对象的存在,所以失去了透明性
抽象构件角色
public interface Component {
// 操作
void show();
}
树枝构件角色
public class Branch implements Component {
private String name;
private List<Component> children;
public Branch(String name) {
children = new ArrayList<>();
this.name = name;
}
// 添加节点
public void add(Component c) {
children.add(c);
}
// 删除节点
public void remove(Component c) {
children.remove(c);
}
// 获取节点
public Component getChild(int i) {
return children.get(i);
}
@Override
public void show() {
for (Component child : children) {
child.show();
}
}
@Override
public String toString() {
return "{" + "branch=" + name + ", children=" + children.toString() + "}";
}
}
树叶构件角色
public class Leaf implements Component {
private String name;
public Leaf(String name) {
this.name = name;
}
@Override
public void show() {
System.out.println(name + ":被访问!");
}
@Override
public String toString() {
return name;
}
}
测试
public class Test {
public static void main(String[] args) {
Branch root = new Branch("根节点");
Branch branch1 = new Branch("树枝节点1");
Component leaf1 = new Leaf("叶子节点1");
Component leaf2 = new Leaf("叶子节点2");
Component leaf3 = new Leaf("叶子节点3");
root.add(leaf1);
branch1.add(leaf2);
branch1.add(leaf3);
root.add(branch1);
root.operation();
System.out.println("结构:" + root.toString());
}
}
// 运行结果
叶子节点1:被访问!
叶子节点2:被访问!
叶子节点3:被访问!
结构:{branch=根节点, children=[叶子节点1, {branch=树枝节点1, children=[叶子节点2, 叶子节点3]}]}