需求
先整理一个需求,展示一个学校的院系组成,一个学校有多个学院,一个学院又有多个系。如何描述它们之间的关系?一种方案是将学院作为学校的子类,系作为学院的子类,类图描述如下:
类图中存在的问题,系是学院的子类,那么就出现一个问题,学院对系并不能实现很好的管理操作,比如系的添加、删除等等。另一种解决方案是把学校、学院、系都作为组织结构,它们之间没有继承关系,而是一个树状结构,可以更好的实现管理操作,即组合模式。
概述
基本介绍:
1、组合模式是树状结构的专用模式。
2、组合模式也称为部分整体模式,它创建了对象组的树形结构,将对象组合成树状结构来表示整体-部分的层次关系。
3、组合模式依据树形结构来组合对象,用来表示部分以及整体层次。
4、组合模式属于结构型模式。
5、组合模式使得用户对单个对象和组合对象的访问具有一致性,即:组合能让客户以一致的方式处理个别对象以及组合对象。
类图描述
类图简要描述
component (抽象构件:容器):它可以是接口或者抽象类,为叶子构件和子容器构件对象声明接口,在该角色中可以包含所有子类共有的行为的实现和声明。在抽象构件中定义了访问及管理它的子构件的方法,如增加子构件,删除子构件,获取子构件等。
leaf(叶子构件):叶子构件没有子构件。它实现了抽象构件中的定义的行为。
compsite(子容器构件):非叶子构件,用于存储子构件,具体实现component 中子部件的相关操作,比如 增加子构件,删除子构件,获取子构件等。
组合模式可以解决这样的问题,当我们需要处理的对象可以生成一种树形结构,而我们需要对树上的叶子节点和叶子进行操作时,它能够提供一致的方式,而不用考虑它是节点还是叶子。
代码实现
学校打印类图分析
学校打印代码实现
package com.example.pattern.composite;
import lombok.Getter;
import lombok.Setter;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
/**
* 组合模式
*/
@Getter
@Setter
abstract class OrganizationComponent {
private String name; // 名字
private String description; // 描述
public OrganizationComponent(String name, String description) {
this.name = name;
this.description = description;
}
public void add(OrganizationComponent component) { //不使用抽象方法 叶子节点无需实现这个方法
// 默认实现
throw new UnsupportedOperationException("不支持此方法");
}
public void remove(OrganizationComponent component) { //不使用抽象方法 叶子节点无需实现这个方法
// 默认实现
throw new UnsupportedOperationException("不支持此方法");
}
public abstract void print(); // 所以子节点必须实现的打印方法
}
// University 就是 Composite
class University extends OrganizationComponent {
// list中存的是 College 学院
List<OrganizationComponent> componentList = new ArrayList<>();
// 构造器
public University(String name, String description) {
super(name, description);
}
@Override
public void add(OrganizationComponent component) {
componentList.add(component);
}
@Override
public void remove(OrganizationComponent component) {
component.remove(component);
}
@Override
public void print() { // 输出 University中包含的学院
System.out.println("————————— " + getName() + "—————————");
if (!CollectionUtils.isEmpty(componentList)) {
componentList.forEach(OrganizationComponent::print);
}
}
}
public class College extends OrganizationComponent {
// list中存的是 Specialty 专业
List<OrganizationComponent> componentList = new ArrayList<>();
public College(String name, String description) {
super(name, description);
}
@Override
public void add(OrganizationComponent component) {
componentList.add(component);
}
@Override
public void remove(OrganizationComponent component) {
component.remove(component);
}
@Override
public void print() { // 输出 College中包含的专业
System.out.println("————————— " + getName() + " —————————");
if (!CollectionUtils.isEmpty(componentList)) {
componentList.forEach(OrganizationComponent::print);
}
}
}
class Specialty extends OrganizationComponent {
public Specialty(String name, String description) {
super(name, description);
}
@Override
public String getName() {
return super.getName();
}
@Override
public String getDescription() {
return super.getDescription();
}
@Override
public void print() {
System.out.print(getName());
System.out.println(" \t " + getDescription());
}
}
class Client {
public static void main(String[] args) {
// 从大到小创建对象
University university = new University("大学", "这是一个大学");
// 创建学院
College college1 = new College("学院1", "学院1");
College college2 = new College("学院2", "学院2");
// 创建专业
college1.add(new Specialty("专业1", "专业1描述"));
college1.add(new Specialty("专业2", "专业2描述"));
college1.add(new Specialty("专业3", "专业3描述"));
college2.add(new Specialty("专业1", "专业1描述 学院2"));
college2.add(new Specialty("专业2", "专业2描述 学院2"));
// 学院加入到学校中
university.add(college1);
university.add(college2);
// 打印
university.print();
}
}
注意事项和细节
1、简化客户端的操作,客户端只需要面对一致的对象而不用考虑整体部分或者节点部分的问题。
2、具有较强的扩展性,当我们需要改组合对象时,我们只需要调整内部的层次关系,客户端无需做出任何改动。
3、方便创建出复杂的层次结构,客户端不用理会组合里面的组成细节,容易添加节点或者叶子,从而创建出复杂的树形结构。
4、需要遍历组织机构,或者处理的对象具有树形结构时,非常适用组合模式。
5、要求具有较高的抽象性,如果节点和叶子差异性过大,比如方法和属性都不一样,不适合使用组合模式。