1,概念
允许将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。
树节点可以对子节点进行增删改查等操作。
1)举例
linux文件系统。
2,场景
1)需要描述对象的部分和整体之间的等级结构关系,如树形菜单、文件和文件夹管理等等
2)需要客户端忽略个体和组合构件的区别,平等对待所有的构件。
组合模式在java和android源码中也是有不少的应用的,比如List框架,就用到了组合模式原理,实现了增删改查功能,局部和个体的各种操作都可以实现。
3,实现
1)类图
①安全模式
把树枝节点和树叶节点彻底分开,树枝节点单独拥有用来组合的方法,这种方法比较安全。但由于不够透明,所以树叶节点和树枝节点将不具有相同的接口,客户端的调用需要做相应
的判断,带来了不便。
②透明模式
把组合使用的方法放到抽象类中,不管叶子对象还是树枝对象都有相同的结构,这样做的好处就是叶子节点和树枝节点对于外界没有区别,它们具备完全一致的行为接口。但因为Leaf
类本身不具备add()、remove()方法的功能,所以实现它是没有意义的。
2)三种角色
①抽象组件(Component)角色
该角色定义参加组合的对象的共有方法和属性,规范一些默认的行为接口。
②叶子构件(Leaf)角色
该角色是叶子对象,其下没有其他的分支,定义出参加组合的原始对象的行为。
③树枝构件(Composite)角色
该角色代表参加组合的、其下有分支的树枝对象,它的作用是将树枝和叶子组合成一个树形结构,并定义出管理子对象的方法,如add()、remove()等等。
3)demo
①抽象类:Company
/**
* 公司的抽象类,也可以写成接口.
*/
public abstract class Company {
ArrayList<Company> companyArrayList = new ArrayList<>();
String name;//姓名
String sex;//性别
String position;//职位
int salary;//薪水
//获取信息
public abstract String getInfo();
}
②树节点类:ConcreteCompany
/**
* 树节点类,可以对分支节点进行增删改查等操作
*/
public class ConcreteCompany extends Company {
//构造函数,这里创建的是一个树节点,但是也是有支节点的基本属性
public ConcreteCompany(String name, String sex, String posion, int salary) {
this.name = name;
this.sex = sex;
this.position = posion;
this.salary = salary;
}
/**
* 增加:添加应给支节点
* <p>
* 这里看起来是添加Company接口对象,但是你后面用子类的实例化,实际添加的就是子类的实例
*/
public void add(Company company) {
companyArrayList.add(company);
}
/**
* 删除:删除某一个节点数据
* <p>
* 当然你也可多加其他的删除功能,你让删除某一类,或删除全部子节点数据等等
*/
public void remove(Company company) {
companyArrayList.remove(company);
}
/**
* 查询所有子节点的数据
* 返回的是子节点集合对象
*/
public ArrayList<Company> getChild() {
return companyArrayList;
}
//修改这里就不做了,有兴趣可以高一下
/**
* 树节点本身属性数据
*/
@Override
public String getInfo() {
String info = "领导: 名称:" + name + ", 性别:" + sex + ", 职位:" + position + ", 薪水:" + salary;
return info;
}
}
③叶子节点类:Employee
/**
* 叶子节点类
* 被上级的树节点管理
* 这里叶子节点没有什么权力,只能创建自己和看看自己的信息
*/
public class Employee extends Company {
//构造函数,这里创建的是一个叶子节点,并设置基本属性
public Employee(String name, String sex, String posion, int salary) {
this.name = name;
this.sex = sex;
this.position = posion;
this.salary = salary;
}
/**
* 叶子节点本身属性数据
*/
@Override
public String getInfo() {
String info = "下属: 名称:" + name + ", 性别:" + sex + ", 职位:" + position + ", 薪水:" + salary;
return info;
}
}
④组合模式测试类:CompositeDemo
/**
* 组合模式的使用示例
*/
public class CompositeDemo {
public static void main(String[] arg) {
//CEO
ConcreteCompany root = new ConcreteCompany("李文志", "男", "CEO", 100 * 1000);
//部门经理,既是树节点,也是上级的子节点
ConcreteCompany developDep = new ConcreteCompany("卢康", "男", "研发部经理", 10 * 1000);
ConcreteCompany salesDep = new ConcreteCompany("蔡良梁", "男", "销售经理", 11 * 1000);
ConcreteCompany finaceDep = new ConcreteCompany("习伟", "男", "财务经理", 12 * 1000);
//把三个经理添加到公司框架中
root.add(developDep);
root.add(salesDep);
root.add(finaceDep);
//部门员工
Employee e1 = new Employee("A", "男", "研发部", 6000);
Employee e2 = new Employee("B", "男", "研发部", 6000);
Employee e3 = new Employee("C", "男", "研发部", 6000);
Employee e4 = new Employee("D", "男", "销售部", 6000);
Employee e5 = new Employee("E", "男", "销售部", 6000);
Employee e6 = new Employee("F", "男", "销售部", 6000);
Employee e7 = new Employee("G", "男", "财务部", 6000);
Employee e8 = new Employee("H", "男", "财务部", 6000);
//把底层员工添加到特定的区域
developDep.add(e1);//研发部门
developDep.add(e2);
developDep.add(e3);
salesDep.add(e4);//销售部门
salesDep.add(e5);
salesDep.add(e6);
finaceDep.add(e7);//财务部门
finaceDep.add(e8);
//公司的框架已经完成,并添加如数据
//可以进行后续的操作
System.out.println("" + root.getInfo());//查询最大的Boss情况
display(root);//查询整个公司所有人员的情况,所有子节点的数据
}
//遍历打印数据
private static void display(ConcreteCompany root) {
for (Company c : root.getChild()) {
if (c instanceof Employee) {//如果节点类型是子节点
System.out.println(c.getInfo());//查询,打印
} else {//如果节点类型是树节点
System.out.println("\n" + c.getInfo());//查询,打印树节点
display((ConcreteCompany) c);//再递归调用,打印里面的子节点
}
}
}
}
5,Android中的应用
View和ViewGroup就是一种很标准的组合模式:
在Android的视图树中,容器一定是ViewGroup,只有ViewGroup才能包含其他View和ViewGroup。View是没有容器的。者是一种安全的组合模式。
在Android开发中用到组合模式并不很多,组合模式更多的用于界面UI的架构设计上,而这部分让开发者去实现的并不多。
4,优缺点
1)优点
①高层模块调用简单。
一棵树形机构中的所有节点都是Component,局部和整体对调用者来说没有任何区别,即高层模块不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码。
②节点自由增加
使用组合模式后,如果想增加树枝节点、树叶节点,只需找到父节点即可。
2)缺点
①不易控制树枝构件的类型。
②不易使用继承的方法来增加新的行为。
③违反了依赖倒置原则
在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口。