【引入】
总公司和各个分公司在职务功能都类似,但是子公司包含于总公司之中,如下图的结构:
将对象组合成树形结构以表示“ 部分-整体”的层次结构,这种模式结构称为组合模式。
一、组合模式
组合模式(Composite) 将对象组合成树形结构以表示“部分——整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
分类:
透明组合模式(一致组合模式)Component中声明了所有用来管理对象的方法,其中包括add()、remove()。叶节点和枝节点对外界没有区别,具备完全一致的行为接口。但是也要清楚,leaf拥有add()、remove()是没有意义的。
【代码实现】
Component类
public abstract class Component {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public abstract void add(Component component);
public abstract void remove(Component component);
public abstract void display(int depth);
}
Leaf类
public class Leaf extends Component {
public Leaf(String name) {
setName(name);
}
@Override
public void add(Component component) {
System.out.println("叶子不能增加节点");
}
@Override
public void remove(Component component) {
System.out.println("叶子不能删除节点");
}
@Override
public void display(int depth) {
StringBuffer branch=new StringBuffer("");
for(int i=0;i<depth;i++)
branch.append("-");
System.out.println("叶子节点:"+branch+getName());
}
}
Composite类
public class Composite extends Component{
private List<Component> children=new ArrayList<Component>();
public Composite(String name){
setName(name);
}
@Override
public void add(Component component) {
children.add(component);
}
@Override
public void remove(Component component) {
children.remove(component);
}
@Override
public void display(int depth) {
StringBuffer branch=new StringBuffer("");
for(int i=0;i<depth;i++)
branch.append("-");
System.out.println("树枝节点:"+branch+getName());
for(Component component:children){
component.display(depth+1);
}
}
}
安全组合模式 只是规定了系统各个层次的最基础的一致性行为,而把组合(树节点)本身的方法(如树枝节点管理子类的addChild等方法)放到自身当中。
【代码实现】
Component类
public abstract class Component {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public abstract void display(int depth);
}
Leaf类
public class Leaf extends Component {
public Leaf(String name) {
setName(name);
}
@Override
public void display(int depth) {
StringBuffer branch=new StringBuffer("");
for(int i=0;i<depth;i++)
branch.append("-");
System.out.println("叶子节点:"+branch+getName());
}
}
Composite类
public class Composite extends Component {
private List<Component> children = new ArrayList<Component>();
public Composite(String name) {
setName(name);
}
public void add(Component component) {
children.add(component);
}
public void remove(Component component) {
children.remove(component);
}
@Override
public void display(int depth) {
StringBuffer branch = new StringBuffer("");
for (int i = 0; i < depth; i++)
branch.append("-");
System.out.println("树枝节点:" + branch + getName());
for (Component component : children) {
component.display(depth + 1);
}
}
}
测试类
public class Demo {
public static void main(String[] args) {
Composite root=new Composite("root");
root.add(new Leaf("leaf A"));
root.add(new Leaf("leaf B"));
Composite composite1=new Composite("Composite1");
root.add(composite1);
composite1.add(new Leaf("leaf 1A"));
composite1.add(new Leaf("leaf 1B"));
root.add(new Leaf("leaf C"));
root.display(1);
}
}
透明组合模式对比安全组合模式:
透明模式的特点就是将组合对象所有的公共方法都定义在了抽象组件内,这样做的好处是客户端无需分辨当前对象是属于树枝节点还是叶子节点,因为它们具备了完全一致的接口,不过缺点就是叶子节点得到到了一些不属于它的方法,比如上面的addChild方法,这违背了接口隔离性原则。和透明方式不一样的是,完全组合模式叶子节点不具备addChild功能,所以无法调用,而上面的示例中时可以被调用,但是调用之后显示不支持,这就是这两种写法最大的区别。
组合适用场景:
- 需求中体现部分与整体层次的结构的时候;
- 希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时。
优点:
- 组合模式定义了包含(人力资源部和财务部这些)基本对象和(分公司、办事处等)组合对象的类层次结构。基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断地递归下去,客户代码中,任何用到基本对象的地方都可以使用组合对象了;
- 组合模式让客户可以一致的使用组合结构和单个对象。
二、应用举例
Company类
public abstract class Company {
protected String name;
public Company(String name){
this.name = name;
}
public abstract void add(Company company);//增加
public abstract void remove(Company company);//移除
public abstract void display(int depth);//显示
public abstract void lineofDuty();//履行职责
}
ConcreteCompany具体公司类
public class ConcreteCompany extends Company {
private List<Company> childrenCompany = new ArrayList<Company>();
public ConcreteCompany(String name) {
super(name);
}
@Override
public void add(Company company) {
childrenCompany.add(company);
}
@Override
public void display(int depth) {
System.out.println("第 " + depth + " 层的机构名为: " + name);
for (Company c : childrenCompany) {
c.display(depth + 1);
}
}
@Override
public void lineofDuty() {
for (Company c : childrenCompany) {
c.lineofDuty();
}
}
@Override
public void remove(Company company) {
childrenCompany.remove(company);
}
}
/**
* 财务部
*/
public class FinanceDepartment extends Company {
public FinanceDepartment(String name) {
super(name);
}
@Override
public void add(Company company) {
}
@Override
public void display(int depth) {
System.out.println("第 " + depth + " 层的机构名为: " + name);
}
@Override
public void lineofDuty() {
System.out.println(name + " 负责公司财务收支管理");
}
@Override
public void remove(Company company) {
}
}
/**
* 人力资源部
*/
public class HRDepartment extends Company {
public HRDepartment(String name) {
super(name);
}
@Override
public void add(Company company) {
}
@Override
public void display(int depth) {
System.out.println("第 " + depth + " 层的机构名为: " + name);
}
@Override
public void lineofDuty() {
System.out.println(name + " 负责员工招聘管理培训");
}
@Override
public void remove(Company company) {
}
}
客户端类
public class Client {
public static void main(String[] args) {
//一个总公司
ConcreteCompany root = new ConcreteCompany("北京总公司");
root.add(new HRDepartment("总公司人力资源部"));
root.add(new FinanceDepartment("总公司财务部"));
//三个子公司
ConcreteCompany com1 = new ConcreteCompany("广州分公司");
com1.add(new HRDepartment("广州分公司人力资源部"));
com1.add(new FinanceDepartment("广州分公司财务部"));
root.add(com1);
ConcreteCompany com2 = new ConcreteCompany("杭州分公司");
com2.add(new HRDepartment("杭州分公司人力资源部"));
com2.add(new FinanceDepartment("杭州分公司财务部"));
root.add(com2);
ConcreteCompany com3 = new ConcreteCompany("深圳分公司");
com3.add(new HRDepartment("深圳分公司人力资源部"));
com3.add(new FinanceDepartment("深圳分公司财务部"));
root.add(com3);
System.out.println("-------公司结构图--------");
root.display(1);
System.out.println("----------各部门职责----------");
root.lineofDuty();
}
}
【结果 】
三、组合模式在JDK和mybatis源码中的体现
1、JDK中:
- Container类,从方法add()可以看出,它添加的是它的父类,符合组合模式的设计
- HashMap中有一个putAll方法,参数是一个Map,也是一种组合模式的体现。
- ArrayList中的addAll方法也相同
2、Mybatis:
接口下有多级标签,符合组合模式设计。
如果文章对你有用,三连支持一下吧!!!