设计模式--组合模式

缘起

某日,小明公司最近接到一个办公管理系统的项目,并且在每个城市都有分部。这属于是很常见的OA系统,只要前期将需求分析完善好,中后期开发维护是不难的。

然而,总部公司使用后觉得很OK,想要其他城市的分公司也执行使用。但是现在的问题是,其他分公司的部门和制度没有总公司那么清晰完善。

也许可以一个城市一套代码?但是总公司不乐意了,要求总部、分部等是需要成树状结构的,不可以平行管理。

那么部门Leader想到了一个合适的设计模式–组合模式。

组合模式

组合模式(Composite):将对象组合成树形结构以表示’部门-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

结构图

在这里插入图片描述

Component:作为组合中的对象声明接口,在适当情况下,实现所有类共有接口的默认行为,声明一个接口用于访问和管理Component的子组件

通常使用add和remove增加或删除树枝或树叶的功能

public abstract class Component {
    
    protected String name;

    public Component(String name) {
        this.name = name;
    }
    public abstract void add(Component component);
    public abstract void remove(Component component);
	public abstract void display(int depth);
}
  • Leaf在组合中表示叶节点对象,叶子节点没有子节点,所以add和remove对于Leaf对象来说是没用的,给客户端个提示就行。
public class Leaf extends Component {

    public Leaf(String name) {
        super(name);
    }

    @Override
    public void add(Component component) {
        System.out.println("Cannot add to a leaf");
    }
    @Override
    public void remove(Component component) {
        System.out.println("Cannot remove from a leaf");
    }
    
    // 叶子节点展示职级和名称
    @Override
    public void display(int depth) {
        for (int i = 0; i < depth; i++) {
            System.out.print("-");
        }
        System.out.println(name);
    }
}
  • Composite定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关的操作,比如增加add和删除remove
public class Composite extends Component {

    private List<Component> children = new ArrayList<>();

    public Composite(String name) {
        super(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) {
        for (int i = 0; i < depth; i++) {
            System.out.print("-");
        }
        System.out.println(name);
		// 表层级关系+2
        for (Component item : children) {
            item.display(depth + 2);
        }
    }
}
  • 客户端调用,可以通过Component接口操作组合部件的对象
// 顶级节点
Composite root = new Composite("root");
// 添加两个叶子节点
root.add(new Leaf("Leaf A"));
root.add(new Leaf("Leaf B"));

Composite comp = new Composite("Composite X");
// 加两个叶子节点
comp.add(new Leaf("Leaf A"));
comp.add(new Leaf("Leaf B"));

// 顶级节点加一个枝节点
root.add(comp);

Composite comp2 = new Composite("Composite XY");
// 加两个叶子节点
comp.add(new Leaf("Leaf XYA"));
comp.add(new Leaf("Leaf XYB"));

// 二级节点再加一个枝节点
comp.add(comp2);

// 展示整个架构
root.display(1);

结果

-root
---Leaf A
---Leaf B
---Composite X
-----Leaf A
-----Leaf B
-----Leaf XYA
-----Leaf XYB
-----Composite XY

当发现需求中是体现部分与整体层次的结构时,希望用户可以忽略组合对象与单个对象的不同,统一使用组合结构中的所有对象时,就应该考虑使用组合模式了。

在java开发窗体应用的容器控件Container继承了Component(java自带的),就有add和remove方法,所以它在上面增加控件,如Button、Label、Checkbox等就变成了很自然的事,这就是典型的组合模式的应用。

公司管理系统案例

在这里插入图片描述

公司类:抽象类或接口

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();  // 展示职责
    
}

具体公司类:实现接口、树枝节点

public class ConcreteCompany extends Company {

    protected List<Company> children = new ArrayList<>();
    public ConcreteCompany(String name) {
        super(name);
    }

    @Override
    public void add(Company company) {
        children.add(company);
    }

    @Override
    public void remove(Company company) {
        children.remove(company);
    }

    @Override
    public void display(int depth) {
        for (int i = 0; i < depth; i++) {
            System.out.print("-");
        }
        System.out.println(name);

        for (Company child : children) {
            child.display(depth + 2);
        }
    }

    @Override
    public void lineOfDuty() {
        for (Company child : children) {
            child.lineOfDuty();
        }
    }
}
  • 人力资源部、财务部:叶子节点
// HR
public class HRDept extends Company {
    public HRDept(String name) {
        super(name);
    }

    @Override
    public void add(Company company) {

    }

    @Override
    public void remove(Company company) {

    }

    @Override
    public void display(int depth) {
        for (int i = 0; i < depth; i++) {
            System.out.print("-");
        }
        System.out.println(name);
    }

    @Override
    public void lineOfDuty() {
        System.out.println(name+"员工招聘培训");
    }
}
// 财务部
public class FinanceDept extends Company {

    public FinanceDept(String name) {
        super(name);
    }

    @Override
    public void add(Company company) {

    }

    @Override
    public void remove(Company company) {

    }

    @Override
    public void display(int depth) {
        for (int i = 0; i < depth; i++) {
            System.out.print("-");
        }
        System.out.println(name);
    }

    @Override
    public void lineOfDuty() {
        System.out.println(name + "公司财务收支管理");
    }
}
  • 客户端
// 顶级节点
ConcreteCompany root = new ConcreteCompany("总公司");
root.add(new HRDept("总公司人力资源"));
root.add(new FinanceDept("总公司财务部"));


ConcreteCompany comp = new ConcreteCompany("某分公司");
comp.add(new HRDept("某分公司人力资源"));
comp.add(new FinanceDept("某分公司财务部"));

// 给总公司增加下级部门
root.add(comp);

ConcreteCompany comp2 = new ConcreteCompany("A办事处");
comp2.add(new HRDept("A办事处人力资源"));
comp2.add(new FinanceDept("A办事处财务部"));
comp.add(comp2);

ConcreteCompany comp3 = new ConcreteCompany("B办事处");
comp3.add(new HRDept("B办事处人力资源"));
comp3.add(new FinanceDept("B办事处财务部"));

comp.add(comp3);
System.out.println("结构图");
root.display(1);

System.out.println("职责");
root.lineOfDuty();
结构图
-总公司
---总公司人力资源
---总公司财务部
---某分公司
-----某分公司人力资源
-----某分公司财务部
-----A办事处
-------A办事处人力资源
-------A办事处财务部
-----B办事处
-------B办事处人力资源
-------B办事处财务部
职责
总公司人力资源员工招聘培训
总公司财务部公司财务收支管理
某分公司人力资源员工招聘培训
某分公司财务部公司财务收支管理
A办事处人力资源员工招聘培训
A办事处财务部公司财务收支管理
B办事处人力资源员工招聘培训
B办事处财务部公司财务收支管理
  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值