树形结构在软件中十分常见,如操作系统中的文件结构,文件夹包含文件和子文件夹,而子文件夹又包含文件和子子文件夹,像这样的结构称为树形结构。在树形结构中,文件夹或子文件夹称为容器(Container);而不同类型的文件称为叶子(Leaf)。在树形结构中,由于容器对象和叶子对象在功能上的区别,导致必须有区别地对待容器对象和叶子对象,这将使程序变得复杂。而实际开发中,我们更希望一致地处理它们,由此引出了组合模式。通过组合模式,可以让叶子对象和容器对象的使用具有一致性
组合模式(Composite Pattern):将多个对象组合成树形结构,以表示“整体-部分”的层次关系。组合模式对单个对象(叶子对象)和组合对象(容器对象)的使用具有一致性。组合模式又称为“整体-部分”(Part-Whole)模式。是一种对象结构型模式
组合模式结构包含3个角色
抽象构件(Component):是接口或抽象类,定义了子类共有的行为
叶子构件(Leaf):表示叶子节点对象,没有子节点。实现了抽象构件中定义的行为
容器构件(Composite):表示容器节点对象,包含子节点,其子节点既可以是叶子节点,也可以是容器节点。实现了抽象构件中的行为
组合模式通过定义一个抽象构件类,来达到统一处理的效果。因为抽象构件类既可以是叶子,又可以是容器,客户端针对抽象构件类进行编程,所以无须关心它是叶子还是容器。容器对象和抽象构件类形成一个聚合关联关系,容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合,形成树形结构
组合模式中,根据抽象构件中有没有声明用于管理成员对象的方法,分为透明组合模式和安全组合模式。透明组合模式是组合模式的标椎形式
下面代码演示组合模式
透明组合模式(标准组合模式)
定义抽象构件类
package com.design.structural.composite.transparent;
/**
* 抽象构件
*/
public abstract class Component {
public abstract void add(Component component);
public abstract void remove(Component component);
public abstract void operation();
}
定义叶子构件
package com.design.structural.composite.transparent;
/**
* 叶子构件
*/
public class Leaf extends Component{
private String name;
public Leaf(String name){
this.name = name;
}
@Override
public void add(Component component) {
throw new UnsupportedOperationException();
}
@Override
public void remove(Component component) {
throw new UnsupportedOperationException();
}
@Override
public void operation() {
System.out.println(name);
}
}
定义容器构件类
package com.design.structural.composite.transparent;
import java.util.ArrayList;
import java.util.List;
/**
* 容器构件
*/
public class Composite extends Component{
private List<Component> list = new ArrayList<Component>();
private String name;
private Integer level;
public Composite(String name, Integer level){
this.name = name;
this.level = level;
}
@Override
public void add(Component component) {
list.add(component);
}
@Override
public void remove(Component component) {
list.remove(component);
}
@Override
public void operation() {
System.out.println(this.name);
for (Component component : list){
//容器构件级别判断
if (level != null){
for (int i=0; i<level; i++){
System.out.print(" ");
}
}
component.operation();
}
}
}
透明组合模式(标椎组合模式)类图如下
通过类图可以看出:透明组合模式在抽象构件 Component 中声明了所有用于管理成员对象的方法,包括 add(Component component)、remove(Component component),这样做确保了所有构件类都有相同的接口
测试调用
package com.design.structural.composite.transparent;
/**
* 组合模式(透明)
*/
public class TestMain {
public static void main(String[] args) {
Component leaf1 = new Leaf("叶子1");
Component leaf2 = new Leaf("叶子2");
Component leaf3 = new Leaf("叶子3");
Component leaf4 = new Leaf("叶子4");
Component leaf5 = new Leaf("叶子5");
Component leaf6 = new Leaf("叶子6");
Component composite1 = new Composite("容器构件1", 2);
Component composite2 = new Composite("容器构件2", 2);
composite1.add(leaf1);
composite1.add(leaf2);
composite2.add(leaf3);
composite2.add(leaf4);
composite2.add(leaf5);
Component composite = new Composite("总容器构件", 1);
composite.add(composite1);
composite.add(composite2);
composite.add(leaf6);
composite.operation();
}
}
效果如下图
安全组合模式
定义抽象构件类
package com.design.structural.composite.security;
/**
* 抽象构件
*/
public abstract class Component {
public abstract void operation();
}
定义叶子构件类
package com.design.structural.composite.security;
/**
* 叶子构件
*/
public class Leaf extends Component{
private String name;
public Leaf(String name){
this.name = name;
}
@Override
public void operation() {
System.out.println(this.name);
}
}
定义容器构件类
package com.design.structural.composite.security;
import java.util.ArrayList;
import java.util.List;
/**
* 容器构件
*/
public class Composite extends Component{
private List<Component> list = new ArrayList<Component>();
private String name;
private Integer level;
public Composite(String name, Integer level) {
this.name = name;
this.level = level;
}
public void add(Component component){
list.add(component);
}
public void remove(Component component){
list.remove(component);
}
@Override
public void operation() {
System.out.println(this.name);
for (Component component : list){
if (level != null){
for (int i=0; i<level; i++){
System.out.print(" ");
}
}
component.operation();
}
}
}
安全组合模式类图如下
通过类图可以看出:安全组合模式在抽象构件 Component 中没有声明任何用于管理成员对象的方法,而是在 Composite 类中声明并实现了这些方法。因此叶子对象不能操作管理成员对象的方法,保证了安全
测试调用
package com.design.structural.composite.security;
/**
* 组合模式(安全)
*/
public class TestMain {
public static void main(String[] args) {
Leaf leaf1 = new Leaf("叶子1");
Leaf leaf2 = new Leaf("叶子2");
Leaf leaf3 = new Leaf("叶子3");
Leaf leaf4 = new Leaf("叶子4");
Leaf leaf5 = new Leaf("叶子5");
Leaf leaf6 = new Leaf("叶子6");
Composite composite1 = new Composite("容器构件1", 2);
Composite composite2 = new Composite("容器构件2", 2);
composite1.add(leaf1);
composite1.add(leaf2);
composite2.add(leaf3);
composite2.add(leaf4);
composite2.add(leaf5);
Composite composite = new Composite("总容器构件", 1);
composite.add(leaf6);
composite.add(composite1);
composite.add(composite2);
composite.operation();
}
}
效果如下
组合模式总结
优点:清楚地定义分层次的复杂对象,表示对象的全部或部分层次,使得客户端忽略了层次的差异,易于对整个层次结构进行控制;简化客户端代码;符合开闭原则;可以形成复杂的树形结构,且对树形结构的控制非常简单
缺点:对类型进行限制时,会比较复杂;设计变得更加抽象
适用场景:希望客户端可以忽略组合对象和单个对象差异时;系统中需要处理一个树形结构