侧边栏壁纸
  • 累计撰写 98 篇文章
  • 累计创建 20 个标签
  • 累计收到 3 条评论

设计模式--组合模式

林贤钦
2020-05-11 / 0 评论 / 9 点赞 / 940 阅读 / 0 字
温馨提示:
本文最后更新于 2020-05-11,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

组合模式(Composite Pattern)

1. 介绍

1.1 模式说明

  1. 组合模式(Composite Pattern),又叫部分整体模式,它创建了对象组的树形结构,将对象组合成树状结构以表示“整体-部分”的层次关系。

  2. 组合模式依据树形结构来组合对象,用来表示部分以及整体层次。

  3. 这种类型的设计模式属于结构型模式。

  4. 组合模式使得用户对单个对象和组合对象的访问具有一致性,即

组合能让客户以一致的方式处理个别对象以及组合对象

1.2 主要作用

它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。

2. 模式原理

2.1 组合模式原理类图

2.2 组合模式包含如下角色:

抽象根节点(Component

定义系统各层次对象的共有方法和属性,可以预先定义一些默认行为和属性;

树枝节点(Composite

定义树枝节点的行为,存储子节点,组合树枝节点和叶子节点形成一个树形结构;

叶子节点(Leaf

叶子节点对象,其下再无分支,是系统层次遍历的最小单位;

2.3 典型的组合模式代码

抽象根节点(Component)

public abstract class Component {
    protected String name;
    public  Component(String name){
        this.name=name;
    }
    public abstract String operation();

    public boolean addChild(Component component){
        throw  new UnsupportedOperationException("addChild not supported!");
    }
    public boolean removeChile(Component component){
        throw  new UnsupportedOperationException("removeChild not supported!");
    }
    public Component getChild(int index) {
        throw new UnsupportedOperationException("getChild not supported!");
    }
}

树枝节点(Composite)

public class Composite extends Component{
    private List<Component> components;
    public Composite(String name){
        super(name);
        this.components=new ArrayList<>();
    }
    @Override
    public String operation() {
        StringBuilder builder = new StringBuilder(this.name);
        for (Component component : this.components) {
            builder.append("\n");
            builder.append(component.operation());
        }
        return builder.toString();
    }

    @Override
    public boolean addChild(Component component) {
        return this.components.add(component);
    }

    @Override
    public boolean removeChile(Component component) {
        return this.components.remove(component);
    }

    @Override
    public Component getChild(int index) {
        return this.components.get(index);
    }
}

叶子节点(Leaf)

public class Leaf  extends Component{

    public Leaf(String name) {
        super(name);
    }
    @Override
    public String operation() {
        return this.name;
    }
}

调用端Client

public class Client {
    public static void main(String[] args) {
        //创建原始对象
        Component component = new ConcreteComponent();
        System.out.println("创建原始对象");
        component.operate();
        //第一次装饰
        component = new ConcreteDecoratorA(component);
        System.out.println("第一次装饰");
        component.operate();
        //第二次装饰
        component = new ConcreteDecoratorB(component);
        //两次装饰后的操作
        System.out.println("第二次装饰");
        component.operate();
    }
}

结果

root
---branchA
------leafA
---branchB
------leafB
------leafC

3. 实例讲解

3.1 实例概况

编写程序展示一个学校院系结构:需求是这样,要在一个页面中展示出学校的院系组成,一个学校有多个学院, 一个学院有多个系

问题分析

  1. 将学院看做是学校的子类,系是学院的子类,这样实际上是站在组织大小来进行分层次的

  2. 实际上我们的要求是 :

在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系, 因此这种方案,不能很好实现的管理的操作,比如对学院、系的添加,删除,遍历等

  1. 解决方案:

把学校、院、系都看做是组织结构,他们之间没有继承的关系,而是一个树形结构,可以更好的实现管理操作。

3.2实例uml类图

3.3代码实现

步骤一:抽象根节点(Component)

public abstract class OrganizationComponent {
    private String name; // 名 字
    private String des; // 说 明

    protected void add(OrganizationComponent organizationComponent) {
        //默认实现
        throw new UnsupportedOperationException();
    }


    protected void remove(OrganizationComponent organizationComponent) {
        //默认实现
        throw new UnsupportedOperationException();
    }

    //构造器
    public OrganizationComponent(String name, String des) {
        super();
        this.name = name;
        this.des = des;
    }


    public String getName() {
        return name;
    }


    public void setName(String name) {
        this.name = name;
    }


    public String getDes() {
        return des;
    }


    public void setDes(String des) {
        this.des = des;
    }

    //方法 print,  做成抽象的,  子类都需要实现
    protected abstract void print();

}

步骤二:树枝节点(Composite)

学校 University、 学院College

public class University extends OrganizationComponent {
    List<OrganizationComponent> organizationComponents = new ArrayList<>();

    // 构造器
    public University(String name, String des) {
        super(name, des);
    }

    // 重 写 add @Override
    protected void add(OrganizationComponent organizationComponent) {
        organizationComponents.add(organizationComponent);
    }

    // 重 写 remove @Override
    protected void remove(OrganizationComponent organizationComponent) {
        organizationComponents.remove(organizationComponent);
    }


    @Override
    public String getName() {
        return super.getName();
    }


    @Override
    public String getDes() {
        return super.getDes();
    }
    // print 方法,就是输出 University  包含的学院
    @Override
    protected void print() {
        System.out.println("--------------" + getName() + "--------------");
        //遍历 organizationComponents
        for (OrganizationComponent organizationComponent : organizationComponents) { organizationComponent.print();
        }
    }
}


public class College extends OrganizationComponent {
    //List 中 存放的 Department
    List<OrganizationComponent> organizationComponents = new ArrayList<>();

    // 构造器
    public College(String name, String des) {
        super(name, des);

    }

    // 重 写 add @Override
    protected void add(OrganizationComponent organizationComponent) {
        //将来实际业务中,Colleage  的  add  和  University add 不一定完全一样
        organizationComponents.add(organizationComponent);
    }

    // 重 写 remove @Override
    protected void remove(OrganizationComponent organizationComponent) {
        organizationComponents.remove(organizationComponent);
    }


    @Override
    public String getName() {
        return super.getName();
    }


    @Override
    public String getDes() {
        return super.getDes();
    }

    // print 方法,就是输出 University  包含的学院
    @Override
    protected void print() {
        System.out.println("--------------" + getName() + "--------------");
        //遍历 organizationComponents
        for (OrganizationComponent organizationComponent : organizationComponents) {
            organizationComponent.print();
        }
    }
}

步骤三:叶子节点(Leaf)

专业computerCollege

public class Department extends OrganizationComponent {
    //没有集合

    public Department(String name, String des) {
        super(name, des);

    }

    //add , remove 就不用写了,因为他是叶子节点

    @Override
    public String getName() {
        return super.getName();
    }

    @Override
    public String getDes() {
        return super.getDes();
    }

    @Override
    protected void print() {
        System.out.println(getName());
    }
}

步骤二:调用端Client

public class Client {
    public static void main(String[] args) {
        //从大到小创建对象 学校
        OrganizationComponent university = new University("清华大学", " 中国顶级大学 ");

        //创建 学院
        OrganizationComponent computerCollege = new College("计算机学院", " 计 算 机 学 院 ");
        OrganizationComponent infoEngineerCollege = new College("信息工程学院", " 信息工程学院 ");

        //创建各个学院下面的系(专业)
        computerCollege.add(new Department("软件工程", " 软件工程不错 "));
        computerCollege.add(new Department("网络工程", " 网络工程不错 "));
        computerCollege.add(new Department("计算机科学与技术", " 计算机科学与技术是老牌的专业 "));

        infoEngineerCollege.add(new Department("通信工程", " 通信工程不好学 "));
        infoEngineerCollege.add(new Department("信息工程", " 信息工程好学 "));

        //将学院加入到学校
        university.add(computerCollege);
        university.add(infoEngineerCollege);
        university.print();
        System.out.println("-----只打印计算机学院-----");
        computerCollege.print();
    }
}

结果

--------------清华大学--------------
--------------计算机学院--------------
软件工程
网络工程
计算机科学与技术
--------------信息工程学院--------------
通信工程
信息工程
-----只打印计算机学院-----
--------------计算机学院--------------
软件工程
网络工程
计算机科学与技术

4. 模式优缺点

优点

  • 可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,使得增加新构件也更容易。

  • 客户端调用简单,客户端可以一致的使用组合结构或其中单个对象。

  • 定义了包含叶子对象和容器对象的类层次结构,叶子对象可以被组合成更复杂的容器对象,而这个容器对象又可以被组合,这样不断递归下去,可以形成复杂的树形结构。

  • 组合模式 屏蔽了对象系统的层次差异性(树节点和叶子节点为不同类型),将客户代码与复杂的容器对象解耦,使得客户端可以忽略层次间的差异,使用一致的行为控制不同层次。

  • 组合模式 可以很方便地增加 树枝节点叶子节点 对象,并对现有类库无侵入,符合 开闭原则

缺点

  • 如果类系统(树形结构)过于庞大,虽然对不同层次都提供一致性操作,但客户端仍需花费时间理清类之间的层次关系;
  • 组合模式 在具体实现上违背了设计模式 接口隔离原则依赖倒置原则

5. 应用场景

  • 系统对象层次具备整体和部分,呈树形结构,且要求具备统一行为

  • 让客户能够忽略不同对象层次的变化,客户端可以针对抽象构件编程,无须关心对象层次结构的细节。

    树形菜单,操作系统目录结构,公司组织架构等

9

评论区