组合模式
1.需求: 编写程序展示学校的院系要求
要在一个页面中展示出学校的院系组成,一个学校中有多个学院,一个学院中有多个系。
图示:
2.解决方案:
-
将学院看做是学校的子类,系看做学院的子类
-
实际上要求是体现出学校的院系组成,一个学校有多个学院,一个学院有多个系。因此这种方案不能很好实现管理操作。比如对学院,系的添加,删除,遍历等(所以不建议使用继承关系完成该需求)
-
解决问题: 将学校,院和系都看作组织结构,他们之间没有继承关系。而是一种树形结构,可以更好地实现管理操作(组合模式)【相当于上下级组织 而不是父亲儿子的继承关系】
3.组合模式介绍
- 组合模式(Composite Pattern),又称为部分整体模式,它创建了对象组的树形结构,将对象组合成树形结构以表示"整体-部分"的层次关系
- 组合模式属于结构型模式,依据树形结构来组合对象,用来表示 部分和整体的层次关系
- 组合模式让对象对单个对象和组合对象的访问具有一致性,即: 组合能让客户以一致的方式处理个别对象以及组合对象
- 当我们要处理的对象可以生成一棵树型结构(参考二叉树),而我们要对树上的枝和叶子进行操作时,可以考虑使用组合模式。
- 组合模式的角色
- Component: 抽象角色,为要组合的对象实现统一接口
- Leaf: 叶子节点
- Composite:枝节点,实例化Component接口的有关操作
- uml:
代码演示:
package composite;
import java.util.ArrayList;
import java.util.List;
//组合模式
public class Demo {
// 1.Component: 组合中对象声明的抽象类,适当情况下支持所有类的共有行为,用来访问和管理所有子部件
public static abstract class OrganizationComponent {
private String name;// 子部件名
private String des;// 子部件的说明
// 日常get set
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
//默认构造
public OrganizationComponent(String name, String des) {
super();
this.name = name;
this.des = des;
}
/**
* 共有方法: 1.添加 add(默认实现) 2.删除 remove(默认实现)
*/
protected void add(OrganizationComponent organization) {
throw new UnsupportedOperationException("默认实现的添加方法");
}
protected void remove(OrganizationComponent organization) {
throw new UnsupportedOperationException("默认实现的删除方法");
}
// 打印当前的信息 抽象方法
public abstract void print();
}
// 2.Composite: 顶层实体类: 大学
public static class University extends OrganizationComponent {
// 采用List存储信息
List<OrganizationComponent> organizationComponents = new ArrayList<>();
public University(String name, String des) {
super(name, des);
// TODO Auto-generated constructor stub
}
// 重写get方法
@Override
public String getName() {
return super.getName();
}
@Override
public String getDes() {
return super.getDes();
}
// 重写add方法
@Override
protected void add(OrganizationComponent organization) {
// 加入元素
organizationComponents.add(organization);
}
@Override
protected void remove(OrganizationComponent organization) {
// 移除元素
organizationComponents.add(organization);
}
@Override
public void print() {
System.out.println("-----------------"+getName()+"-----------------");
for (OrganizationComponent demo : organizationComponents) {
demo.print();
}
}
}
// 3.Composite: 实体类 : 院系 (和 University的逻辑类似)
public static class College extends OrganizationComponent {
public College(String name, String des) {
super(name, des);
// TODO Auto-generated constructor stub
}
// 重写get方法
@Override
public String getName() {
return super.getName();
}
@Override
public String getDes() {
return super.getDes();
}
// 采用List存储信息
List<OrganizationComponent> organizationComponents = new ArrayList<>();
// 重写add方法
@Override
protected void add(OrganizationComponent organization) {
// 加入元素
organizationComponents.add(organization);
}
@Override
protected void remove(OrganizationComponent organization) {
// 移除元素
organizationComponents.add(organization);
}
@Override
public void print() {
System.out.println("-----------------"+getName()+"-----------------");
for (OrganizationComponent demo : organizationComponents) {
demo.print();
}
}
}
// 4.叶子类 : Department
public static class Department extends OrganizationComponent {
public Department(String name, String des) {
super(name, des);
}
//Department已经属于叶子节点了 无需add和remove
@Override
public String getName() {
return super.getName();
}
@Override
public String getDes() {
return super.getDes();
}
@Override
public void print() {
System.out.println(this.getName());
}
}
//client
public static void main(String[]args) {
//从大到小进行对象的创建
OrganizationComponent university = new University("江西农业大学", "我的大学");
//创建学校
OrganizationComponent college = new College("软件学院", "我的学院");
//创建学院1
OrganizationComponent college2 = new College("经管学院", "隔壁学院");
//学院加专业
college.add(new Department("物联网工程", "我的专业"));
college.add(new Department("软件工程", "其他专业"));
college2.add(new Department("农林经济管理", "其他专业1"));
college2.add(new Department("市场营销", "其他专业2"));
//学校加学院
university.add(college);
university.add(college2);
//打印
university.print();
}
}
组合模式的一些细节
优点:
- 很形象地表示出了树形结构
- 节点增加很方便(扩展性强),无需修改底层抽象方法
缺点
- 使用组合模式的时候,叶子节点和树枝都是实现类,违反了依赖倒转原则(高层模块不能依赖底层模块,应该统一依赖于接口)
- 如果节点和叶子之间有较多差异的话,像是方法和属性很多不一样(即具有较低的抽象性),很难使用组合模式
使用环境
- 在一个系统中可以分离出树形结构,分离叶子对象,枝对象和顶层容器,(类似树形菜单,文件,文件夹的管理)
- 在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以一致地对待它们
参考文章: https://www.jianshu.com/p/c658fecbaa7b