一、引入组合模式
设计一个大学>学院>专业的结构代码,可以做到输出大学、学院、专业的信息。
- 一个大学里面有多个学院
- 一个学院里面有多个专业
思路
我们很容易就想到这种组合的方式,去设计我们的代码。完全没有问题,可以很好的去实现我们的功能。
但是后面如果变动的时候就麻烦了。 假如我们要让大学直接去使用专业呢?
二、组合模式
组合模式(Composite Pattern) 将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户可以使用一致的方法操作单个对象和组合对象。
组合模式有三个角色:
组合部件(Component):它可以是抽象类、接口、类。它里面定义了基本的属性和方法。
合成部件(Composite):还有自己的子节点,比如这里的大学、学院。
叶子(Leaf):在组合中表示子节点对象,比如这里的专业。
代码演示
Component
import lombok.Data;
@Data
public abstract class Component {
protected String name;
protected void add(Component component){
throw new UnsupportedOperationException();
}
protected void remove(Component component){
throw new UnsupportedOperationException();
}
abstract void print();
}
注:
1、比如我们上面的大学里面有学院,那么它就需要添加一个学院(add())和删除一个学院(remove())。但是我们的专业(也就是叶子节点),它不需要这个添加和删除方法,所以我们进行一个默认实现,里面抛出这个异常表示不支持此方法。
2、这里为什么不用接口呢?(JDK8之后允许接口有默认实现),因为接口里面不允许定义非常量的变量。
University
import java.util.ArrayList;
import java.util.List;
public class University extends Component {
private List<Component> lists = new ArrayList<>();
public University(String name){
super();
setName(name);
}
@Override
public void add(Component component) {
lists.add(component);
}
@Override
public void remove(Component component) {
lists.remove(component);
}
@Override
public void print() {
System.out.println("----------"+getName()+"----------");
for (Component c : lists){
c.print();
}
}
}
College
import java.util.ArrayList;
import java.util.List;
public class College extends Component {
private List<Component> lists = new ArrayList<>();
public College(String name){
super();
setName(name);
}
@Override
public void add(Component component) {
lists.add(component);
}
@Override
public void remove(Component component) {
lists.remove(component);
}
@Override
public void print() {
System.out.println("----------"+getName()+"----------");
for (Component c : lists){
c.print();
}
}
}
Major
public class Major extends Component {
public Major(String name){
super();
setName(name);
}
@Override
void print() {
System.out.println(getName());
}
}
测试
public class Main {
public static void main(String[] args) {
// 创建学校
University university = new University("沙雕大学");
// 创建学院
College college_1 = new College("计算机与科学学院");
College college_2 = new College("人文艺术学院");
// 大学与学院关联
university.add(college_1);
university.add(college_2);
// 创建专业
Major major_1 = new Major("软件工程");
Major major_2 = new Major("网络工程");
Major major_3 = new Major("音乐与舞蹈");
Major major_4 = new Major("表演与艺术");
// 学院与专业关联
college_1.add(major_1);
college_1.add(major_2);
college_2.add(major_3);
college_2.add(major_4);
// 测试
// 打印大学
university.print();
// ----------沙雕大学----------
// ----------计算机与科学学院----------
// 软件工程
// 网络工程
// ----------人文艺术学院----------
// 音乐与舞蹈
// 表演与艺术
// 打印学院
college_1.print();
// ----------计算机与科学学院----------
// 软件工程
// 网络工程
// 打印专业
major_1.print();
// 软件工程
}
}
总结
- 客户端只需要面对对象即可,不需要考虑整体部分和叶子节点的问题。
- 具有较强的扩展性。当我们需要更改组合对象时,我们只需要调整内部的层次关系即可。
- 需要遍历组织机构,或者处理的对象具有树形结构时,非常适合使用组合模式。
- 如果节点和叶子有很多差异的话,比如很多属性、或方法不一样,就不适合使用组合模式了。