组合模式

组合模式(Composite),将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

组合模式解析

composite-struct

角色介绍

  • Component:组合中的对象声明接口,在适当情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理 Component 的子部件。

  • Leaf:在组合中表示叶节点对象,叶节点没有子节点。

  • Composite:定义有枝节点行为,用来存储子部件,在 Component 接口中实现与子部件有关的操作,比如增加 Add 和删除 Remove。

组合模式基本代码

  • Component 类
1
/**
2
 * Component
3
 */
4
public abstract class Component {
5
6
    private String name;
7
8
    public Component(String name) {
9
        this.name = name;
10
    }
11
12
    public abstract void add(Component component);
13
14
    public abstract void remove(Component component);
15
16
    public abstract void display();
17
18
    public String getName() {
19
        return name;
20
    }
21
22
    public void setName(String name) {
23
        this.name = name;
24
    }
25
}
  • Composite 类
1
/**
2
 * Composite
3
 */
4
public class Composite extends Component {
5
    /**
6
     * 存放子节点
7
     */
8
    List<Component> childCompoents = new LinkedList<>();
9
10
    public Composite(String name) {
11
        super(name);
12
    }
13
14
    @Override
15
    public void add(Component component) {
16
        this.childCompoents.add(component);
17
    }
18
19
    @Override
20
    public void remove(Component component) {
21
        this.childCompoents.remove(component);
22
    }
23
24
    @Override
25
    public void display() {
26
        System.out.println("========" + this.getName() + "==========");
27
        // 遍历子节点
28
        for (Component c : childCompoents) {
29
            c.display();
30
        }
31
    }
32
}
  • Leaf 类
1
/**
2
 * Leaf
3
 */
4
public class Leaf extends Component {
5
6
    public Leaf(String name) {
7
        super(name);
8
    }
9
10
    @Override
11
    public void add(Component component) {
12
        throw new IllegalStateException("Cannot add to a leaf");
13
    }
14
15
    @Override
16
    public void remove(Component component) {
17
        throw new IllegalStateException("Cannot remove from a leaf");
18
    }
19
20
    @Override
21
    public void display() {
22
        // 只打印叶子节点,叶子节点没有子节点
23
        System.out.println(this.getName());
24
    }
25
}

示例

展示一个学校院系结构,一个学校有多个学院,一个学院有多个专业。

类结构图

composite-code-struct

编码

  • OrganizationComponent 类
1
/**
2
 * OrganizationComponent
3
 */
4
public abstract class OrganizationComponent {
5
6
	private String name;
7
8
	public OrganizationComponent(String name) {
9
		this.name = name;
10
	}
11
12
	protected abstract void add(OrganizationComponent organizationComponent);
13
	
14
	protected abstract void remove(OrganizationComponent organizationComponent);
15
16
	protected abstract void print();
17
18
	public String getName() {
19
		return name;
20
	}
21
22
	public void setName(String name) {
23
		this.name = name;
24
	}
25
	
26
}
  • University 类
1
/**
2
 * University 就是 Composite , 可以管理 College
3
 */
4
public class University extends OrganizationComponent {
5
6
	List<OrganizationComponent> organizationComponents = new LinkedList<>();
7
8
	public University(String name) {
9
		super(name);
10
	}
11
12
	@Override
13
	protected void add(OrganizationComponent organizationComponent) {
14
		organizationComponents.add(organizationComponent);
15
	}
16
17
	@Override
18
	protected void remove(OrganizationComponent organizationComponent) {
19
		organizationComponents.remove(organizationComponent);
20
	}
21
22
	@Override
23
	protected void print() {
24
		System.out.println("--------------" + getName() + "--------------");
25
		// 遍历 organizationComponents
26
		for (OrganizationComponent organizationComponent : organizationComponents) {
27
			organizationComponent.print();
28
		}
29
	}
30
31
}
  • College 类
1
/**
2
 * College 学院
3
 */
4
public class College extends OrganizationComponent {
5
6
	/**
7
	 *  存放节点
8
	 */
9
	List<OrganizationComponent> organizationComponents = new LinkedList<OrganizationComponent>();
10
11
	public College(String name) {
12
		super(name);
13
	}
14
15
	@Override
16
	protected void add(OrganizationComponent organizationComponent) {
17
		//  将来实际业务中,Colleage 的 add 和  University add 不一定完全一样
18
		organizationComponents.add(organizationComponent);
19
	}
20
21
	@Override
22
	protected void remove(OrganizationComponent organizationComponent) {
23
		organizationComponents.remove(organizationComponent);
24
	}
25
26
27
	@Override
28
	protected void print() {
29
		System.out.println("--------------" + getName() + "--------------");
30
		// 遍历 organizationComponents
31
		for (OrganizationComponent organizationComponent : organizationComponents) {
32
			organizationComponent.print();
33
		}
34
	}
35
36
}
  • Department 类
1
/**
2
 * Department
3
 */
4
public class Department extends OrganizationComponent {
5
6
	public Department(String name) {
7
		super(name);
8
	}
9
10
	@Override
11
	protected void add(OrganizationComponent organizationComponent) {
12
		throw new UnsupportedOperationException();
13
	}
14
15
	@Override
16
	protected void remove(OrganizationComponent organizationComponent) {
17
       throw new UnsupportedOperationException();
18
	}
19
20
	@Override
21
	protected void print() {
22
		System.out.println(this.getName());
23
	}
24
}
  • Main 类
1
public class Main {
2
3
	public static void main(String[] args) {
4
		// 学校
5
		OrganizationComponent university = new University("清华大学");
6
		
7
		// 创建学院
8
		OrganizationComponent infoEngineerCollege = new College("信息工程学院");
9
10
		// 创建各个学院下面的专业
11
		infoEngineerCollege.add(new Department("软件工程"));
12
		infoEngineerCollege.add(new Department("网络工程"));
13
		infoEngineerCollege.add(new Department("计算机科学与技术"));
14
		
15
		//将学院加入到学校
16
		university.add(infoEngineerCollege);
17
18
		university.print();
19
	}
20
}

小结

在组合模式中,基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断地递归下去,客户代码中,任何用到基本对象的地方都可以使用组合对象了。用户是不用关心到底是处理一个叶节点还是处理一个组合组件,也就用不着为定义组合而写一些选择判断语句了。组合模式让客户可以一致地使用组合结构和单个对象。

如果你发现需求中是体现部分与整体层次的结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑用组合模式了。