定义
组合模式(Composite Pattern)是一种结构性设计模式,它允许你将对象组合成树形结构,以表示"部分-整体"层次结构。这个模式允许客户端统一地对待单个对象和组合对象。
意图
-
将对象组织成树形结构:组合模式允许将对象组织成层次结构,其中单个对象和组合对象都被视为相同类型的组件。
-
客户端统一访问:客户端可以统一地访问单个对象和组合对象,不需要区分它们的具体类型,因为它们都实现了相同的接口。
-
简化客户端代码:组合模式简化了客户端代码,因为客户端不需要处理对象的类型,而只需调用通用的接口方法。
-
支持递归结构:组合模式支持递归结构,因此可以方便地处理深层次的组合对象。
-
增加新类型的组件:组合模式使得增加新类型的组件变得相对容易,因为只需要实现通用的接口。
参与者(角色)
-
组件(Component):这是一个抽象类或接口,它定义了组合对象和单个对象的通用接口。所有具体组件类都必须实现这个接口,它包括方法如显示名称、添加子组件、移除子组件等。
-
叶子(Leaf):这是组合模式中的单个对象,它实现了组件接口。叶子对象没有子组件,通常表示了树结构中的最小单元。
-
组合(Composite):这是组合模式中的组合对象,它实现了组件接口。组合对象可以包含其他组件,包括叶子对象和其他组合对象,形成一个树形结构。
举例
以下是某公司的组织机构实现的组合模式
类图:
这个例子中对应类的角色如下:
-
Component(组件):抽象的接口或类,定义了单个对象和组合对象的通用方法。在示例中,Component
接口定义了 showName()
方法,表示显示对象的名称。
-
Company(公司):具体的组合对象,实现了 Component
接口。Company
类表示公司,可以包含其他组件,包括子公司和部门。它负责管理子组件的添加和删除。
-
SubsidiaryCompany(子公司):具体的组合对象,也实现了 Component
接口。SubsidiaryCompany
类表示子公司,可以包含其他组件,包括部门。它同样负责管理子组件的添加和删除。
-
Department(部门):叶子对象,实现了 Component
接口。Department
类表示部门,它是组织结构的最小单元,没有子组件。
组织抽象接口
public interface Organization {
void showName();
}
公司类
@Slf4j
public class Company implements Organization{
private String name;
private List<Organization> children = new ArrayList<>();
public Company(String name) {
this.name = name;
}
public void add(Organization component) {
children.add(component);
}
public void remove(Organization component) {
children.remove(component);
}
@Override
public void showName() {
log.info("公司名字: " + name);
for (Organization component : children) {
component.showName();
}
}
} }
}
子公司
@Slf4j
public class SubsidiaryCompany implements Organization{
private String name;
private List<Organization> children = new ArrayList<>();
public SubsidiaryCompany(String name) {
this.name = name;
}
public void add(Organization component) {
children.add(component);
}
public void remove(Organization component) {
children.remove(component);
}
@Override
public void showName() {
log.info("子公司: " + name);
for (Organization component : children) {
component.showName();
}
}
}
部门
@Slf4j
public class Department implements Organization{
private String name;
public Department(String name) {
this.name = name;
}
@Override
public void showName() {
log.info("部门名称: " + name);
}
}
测试,组合一个组织机构
public class App {
public static void main(String[] args) {
Company parentCompany = new Company("科技公司");
SubsidiaryCompany subsidiary1 = new SubsidiaryCompany("北京分公司");
Department hrDepartment = new Department("北京Hr部门");
Department devDepartment = new Department("北京研发部门");
subsidiary1.add(hrDepartment);
subsidiary1.add(devDepartment);
SubsidiaryCompany subsidiary2 = new SubsidiaryCompany("广州分公司");
Department finaceDepartment = new Department("广州财务部门");
Department saleDepartment = new Department("广州销售部门");
subsidiary2.add(finaceDepartment);
subsidiary2.add(saleDepartment);
parentCompany.add(subsidiary1);
parentCompany.add(subsidiary2);
parentCompany.showName();
}
}
优点
-
统一接口:组合模式允许客户端统一地对待单个对象和组合对象,因为它们都实现了相同的接口,从而简化了客户端代码。
-
灵活性:组合模式支持递归结构,可以方便地处理深层次的组合对象。你可以轻松地构建具有多层次结构的对象。
-
可扩展性:向组合结构中添加新类型的组件相对容易,因为只需要实现通用的接口即可,不需要修改现有代码。
-
可维护性:组合模式使代码更加清晰,因为它减少了与特定对象类型的耦合,使代码更易于维护和扩展。
缺点
-
复杂性:组合模式可能会引入额外的复杂性,因为它创建了一个对象层次结构。这可能会使代码难以理解和调试。
-
性能开销:递归遍历组合结构可能会导致性能开销,特别是当结构非常深或包含大量组件时。
-
限制操作:组合模式通常不支持在组合对象中添加或删除子对象的操作,因为这些操作可能会破坏整体结构。
-
过度一般化:在某些情况下,组合模式可能会过于一般化,不适用于所有类型的对象组织结构。
组合模式的应用
Hashmap中的组合模式
Map接口对应Component
HashMap对应Composite
Node对应叶子
分享到: