组合模式(Composite)
意图
将对象组合成树形结构已表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性
适用性
1、你想表示对象的部分-整体层次i结构
2、你希望用户忽略组合对象与单个休想的不同,用户将统一地使用组合结构中的所有对象
结构
典型的Composite对象结构
Component
为组合的对象声明接口
适当情况下,实现所有类共有接口的缺省行为
声明一个接口用于访问和管理Component的子组件
在递归结构中定义一个接口,用于访问一个父部件,并在合适的情况下实现
Leaf
在组合中表示叶节点对象,叶节点没有子节点
在组合中定义图元对象的行为
Composite
定义所有子部件的部件行为
存储子部件
在Component接口中实现与子部件有关的操作
Client
通过Component接口操纵组合部件的对象
实现
既然说是像一个树状结构,首先想到的就是公司的部门架构,如下
Component
package composite;
/**
* @Author fitz.bai
* @Date 2018/8/29 20:59
*/
public abstract class Company {
private String name;
public Company() {
}
public Company(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
protected abstract void add(Company company);
protected abstract void remove(Company company);
protected abstract void display(int depth);
}
Composite
package composite;
import java.util.ArrayList;
import java.util.List;
/**
* @Author fitz.bai
* @Date 2018/8/29 21:01
*/
public class ConcreteCompany extends Company {
private List<Company> companyList;
public ConcreteCompany() {
companyList = new ArrayList<>();
}
public ConcreteCompany(String name) {
super(name);
companyList = new ArrayList<>();
}
@Override
protected void add(Company company) {
companyList.add(company);
}
@Override
protected void remove(Company company) {
companyList.remove(company);
}
@Override
protected void display(int depth) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < depth; i++) {
stringBuilder.append("-");
}
System.out.println(stringBuilder.toString() + this.getName());
for (Company c : companyList) {
c.display(depth + 2);
}
}
}
Leaf
package composite;
/**
* @Author fitz.bai
* @Date 2018/8/29 21:06
*/
public class OCDepartment extends Company {
public OCDepartment() {
}
public OCDepartment(String name) {
super(name);
}
@Override
protected void add(Company company) {
}
@Override
protected void remove(Company company) {
}
@Override
protected void display(int depth) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++) {
sb.append("-");
}
System.out.println(new String(sb) + this.getName());
}
}
package composite;
/**
* @Author fitz.bai
* @Date 2018/8/29 21:06
*/
public class TechDepartment extends Company {
public TechDepartment() {
}
public TechDepartment(String name) {
super(name);
}
@Override
protected void add(Company company) {
}
@Override
protected void remove(Company company) {
}
@Override
protected void display(int depth) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++) {
sb.append("-");
}
System.out.println(new String(sb) + this.getName());
}
}
Client
package composite;
/**
* @Author fitz.bai
* @Date 2018/8/29 20:58
*/
public class Client {
public static void main(String[] args) {
Company root = new ConcreteCompany("Fitz总公司");
root.add(new OCDepartment("OC部门"));
root.add(new TechDepartment("技术部门"));
Company shanghai = new ConcreteCompany("Fitz上海分公司");
shanghai.add(new OCDepartment("上海OC部门"));
shanghai.add(new TechDepartment("上海技术部门"));
Company yangpu = new ConcreteCompany("Fitz上海杨浦分公司");
yangpu.add(new OCDepartment("上海杨浦OC部门"));
yangpu.add(new TechDepartment("上海杨浦技术部门"));
root.add(shanghai);
root.add(yangpu);
root.display(0);
}
}
/**
Fitz总公司
--OC部门
--技术部门
--Fitz上海分公司
----上海OC部门
----上海技术部门
--Fitz上海杨浦分公司
----上海杨浦OC部门
----上海杨浦技术部门
*/
安全模式和透明模式
从上面的Compoent看出,我们把用来组合使用的方法都方法哦了抽象类中,不管是叶子对象还是树枝对象都有相同的结构,这种方式叫做透明模式
安全模式就是在抽象组件中之定义一些默认的属性和行为,把树枝接点和叶子结点全部彻底分开,上面的例子,我们可以把Company类中只保留共有的display方法,而在ConcreteCompany中还可以有add和remove方法,具体到部门之后(例如OC department)是叶子结点,无法add和remove,因此只保留display方法,这就是安全模式
优点
1、清楚地表示分层次的复杂对象且增加删除构件更容易。
2、叶子对象也可以被组合容器对象,容器对象又可以添加多个叶子对象,这样不断递归下去,可以形成表达复杂的树形结构。
3、更容易在组合体内加入对象,客户端不必因为加入了新的对象构件而更改原有代码。
缺点
增加新构件时,我们很难对容器中的构件类型进行限制。有时候我们希望一个容器中只能有某些特定类型的对象,例如在某个文件夹中只能包含文本文件,使用组合模式时,不能依赖类型系统来施加这些约束,因为它们都来自于相同的抽象层,在这种情况下,必须通过在运行时进行类型检查来实现,这个实现过程较为复杂。