一、概述
组合模式就是将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性,所以组合模式也可以叫做部分整体模式,它是一种结构型模式。就是用树状结构来表示部分和整体,使他们具有一致性,一致性的意思就是都实现了相同的接口或者继承了相同的父类。
举个具体的例子,总公司下面有多个部门,比如有研发部、产品部、运营部等部门,但是下属有其他的分公司,每个分公司可能负责不同的业务,也分别都有研发部、产品部以及运营部等部门;甚至在细分点,每个分公司下面还有子公司等等......
下面我们就以公司架构来用代码说明。
二、使用
首先创建一个公司的抽象接口,所有的具体公司和部门都要实现此接口。
public interface Company {
String TAG = "XXX";
//添加子公司
void addCompany(Company company);
//移除子公司
void removeCompany(Company company);
//展示所有子公司
void displayAllCompany(int length);
//公司职能
void function();
}
再来定义具体的公司树枝节点。
/**
* 具体的公司——树枝节点
*/
public class ConcreteCompany implements Company {
//公司列表
private List<Company> companyList = new ArrayList<>();
//公司名称
private String name;
public ConcreteCompany(String name){
this.name = name;
}
@Override
public void addCompany(Company company) {
companyList.add(company);
}
@Override
public void removeCompany(Company company) {
companyList.remove(company);
}
@Override
public void displayAllCompany(int length) {
StringBuilder builder = new StringBuilder();
builder.append("-");
for(int i=0;i<length;i++){
builder.append("-");
}
builder.append(name);
Log.e(TAG, builder.toString());
for(Company company : companyList){
company.displayAllCompany(length + 2);
}
}
@Override
public void function() {
for(Company company : companyList){
company.function();
}
}
}
最后就是定义公司的各个部门叶子节点,就是具体到哪个部门了,比如研发、产品等部门。
/**
* 总经办部门——叶子节点
*/
public class ManagerDepartment implements Company {
private String name;
public ManagerDepartment(String name){
this.name = name;
}
@Override
public void addCompany(Company company) {
}
@Override
public void removeCompany(Company company) {
}
@Override
public void displayAllCompany(int length) {
StringBuilder builder = new StringBuilder();
builder.append("-");
for(int i=0;i<length;i++){
builder.append("-");
}
builder.append(name);
Log.e(TAG, builder.toString());
}
@Override
public void function() {
Log.e(TAG, name + ",负责管理所有部门以及子公司");
}
}
/**
* 财务部门——叶子节点
*/
public class FinanceDepartment implements Company {
private String name;
public FinanceDepartment(String name){
this.name = name;
}
@Override
public void addCompany(Company company) {
}
@Override
public void removeCompany(Company company) {
}
@Override
public void displayAllCompany(int length) {
StringBuilder builder = new StringBuilder();
builder.append("-");
for(int i=0;i<length;i++){
builder.append("-");
}
builder.append(name);
Log.e(TAG, builder.toString());
}
@Override
public void function() {
Log.e(TAG, name + ",负责清算所有员工的工资和福利");
}
}
/**
* 研发部门——叶子节点
*/
public class DevelopmentDepartment implements Company {
private String name;
public DevelopmentDepartment(String name){
this.name = name;
}
@Override
public void addCompany(Company company) {
}
@Override
public void removeCompany(Company company) {
}
@Override
public void displayAllCompany(int length) {
StringBuilder builder = new StringBuilder();
builder.append("-");
for(int i=0;i<length;i++){
builder.append("-");
}
builder.append(name);
Log.e(TAG, builder.toString());
}
@Override
public void function() {
Log.e(TAG, name + ",负责研发游戏");
}
}
/**
* 产品部门——叶子节点
*/
public class ProductDepartment implements Company {
private String name;
public ProductDepartment(String name){
this.name = name;
}
@Override
public void addCompany(Company company) {
}
@Override
public void removeCompany(Company company) {
}
@Override
public void displayAllCompany(int length) {
StringBuilder builder = new StringBuilder();
builder.append("-");
for(int i=0;i<length;i++){
builder.append("-");
}
builder.append(name);
Log.e(TAG, builder.toString());
}
@Override
public void function() {
Log.e(TAG, name + ",负责策划游戏的需求");
}
}
/**
* 运营部门——叶子节点
*/
public class OperationDepartment implements Company {
private String name;
public OperationDepartment(String name){
this.name = name;
}
@Override
public void addCompany(Company company) {
}
@Override
public void removeCompany(Company company) {
}
@Override
public void displayAllCompany(int length) {
StringBuilder builder = new StringBuilder();
builder.append("-");
for(int i=0;i<length;i++){
builder.append("-");
}
builder.append(name);
Log.e(TAG, builder.toString());
}
@Override
public void function() {
Log.e(TAG, name + ",负责运营游戏");
}
}
进行测试,打印输出如下图所示。
//根节点
ConcreteCompany rootCompany = new ConcreteCompany("总公司");
rootCompany.addCompany(new ManagerDepartment("总公司总经办"));
rootCompany.addCompany(new FinanceDepartment("总公司财务部"));
//子节点1
ConcreteCompany concreteCompany1 = new ConcreteCompany("分公司1");
concreteCompany1.addCompany(new DevelopmentDepartment("分公司1研发部"));
concreteCompany1.addCompany(new ProductDepartment("分公司1产品部"));
rootCompany.addCompany(concreteCompany1);
//子节点2
ConcreteCompany concreteCompany2 = new ConcreteCompany("分公司2");
Company2.addCompany(new DevelopmentDepartment("分公司2研发部"));
concreteCompany2.addCompany(new ProductDepartment("分公司2产品部"));
concreteCompany2.addCompany(new OperationDepartment("分公司2运营部"));
rootCompany.addCompany(concreteCompany2);
rootCompany.displayAllCompany(1);
rootCompany.function();
三、总结
组合模式使得客户端可以一致的使用一个组合模式或对单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端的代码;在组合模式种增加新的容器组件和叶子组件都很方便,无需对现有类库进行任何修改,符合开闭原则。但是也可以看到很明显的缺点,在叶子节点中也实现了add()和remove()方法,因为这样叶子节点和其他节点对于外界没有区别,它们具有完全一致的行为接口,但是叶子节点的这2个方法时没有意义的,给客户端带来了不安全性,这种方式就是透明方式。
我们也可以在Company接口中不去定义这2个方法,这样安全性得到了提高,但是与此相对变得不再透明,树叶和树枝将不再具有相同的接口,客户端调用时就需要做相对应的判断。这时只需要将这两个方法移到ConcreteCompany类中去就行,具体的部门类中移除这两个方法,具体操作这里就不再过多说明,可以去尝试写出来。
github地址:github.com/leewell5717…