结构型模式-组合模式

定义: 将对象组合成树形结构以表示整个部分的层次结构。组合模式可以让用户统一对待单个对象和对象的组合

这个定义中有两个关键点:一个是用树形结构来分层,另一个是通过统一对待来简化操作。之所以要使用树形结构,其实就是为了能够在某种层次上进行分类,并且能够通过统一的操作来对待复杂的结构。比如,我们常见的公司统计多个维度的人员的工资信息,如果一个一个统计单人的工资信息会比较费时费力,但如果我们将人员工资信息按照组织结构构建成一棵“树”,那么按照一定的分类标示(比如,部门、岗位),就能快速找到相关人员的工资信息,而不是每次都要查找完所有人的数据后再做筛选。

UML图

在这里插入图片描述

组合模式一般的使用场景有:

  • 处理一个树形结构,比如,公司人员组织架构、订单信息等;
  • 跨越多个层次结构聚合数据,比如,统计文件夹下文件总数;
  • 统一处理一个结构中的多个对象,比如,遍历文件夹下所有 XML 类型文件内容。

原型代码示例

/**
 * @Description 组合节点
 */
public abstract class Component {
    public abstract void operation();
}

public class Node extends Component {

    // 存放子节点列表
    private List<Component> myChildren;

    @Override
    public void operation() {

        if (myChildren.isEmpty()) return;
        myChildren.forEach(Component::operation);
    }
}

public class Leaf extends Component {

    @Override
    public void operation() {

        // TODO 叶子节点的操作
    }
}

示例代码 1

import lombok.AllArgsConstructor;
import lombok.Data;

/**
 * @Description 抽象组件
 */
@Data
@AllArgsConstructor
public abstract class OrganizationComponent {

    private String name;

    private String desc;

    protected void add(OrganizationComponent organizationComponent){
        throw new UnsupportedOperationException();
    }
    protected void remove(OrganizationComponent organizationComponent){
        throw new UnsupportedOperationException();
    }

    public abstract void print();
}

import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import java.util.List;

/**
 * @Description 学校-具体组件
 */
@Slf4j
public class University extends OrganizationComponent {

    /**
     * 学院列表
     */
    private List<OrganizationComponent> colleges;

    public University(String name, String desc) {
        super(name, desc);
        this.colleges = Lists.newArrayList();
    }

    @Override
    protected void add(OrganizationComponent college) {
        log.info("添加学院.........{}", college.getName());
        this.colleges.add(college);
    }

    @Override
    protected void remove(OrganizationComponent college) {
        log.info("移除学院.........{}", college.getName());
        this.colleges.remove(college);
    }

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

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

    @Override
    public void print() {
        log.info("================== "+getName()+" ==========================");
        colleges.forEach(OrganizationComponent::print);
    }

}
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import java.util.List;

/**
 * @Description 学院-具体组件
 */
@Slf4j
public class College extends OrganizationComponent {

    /**
     * 专业列表
     */
    List<OrganizationComponent> departments;

    public College(String name, String desc) {
        super(name, desc);
        this.departments = Lists.newArrayList();
    }

    @Override
    protected void add(OrganizationComponent department) {
        log.info("添加院系.........{}", department.getName());
        departments.add(department);
    }

    @Override
    protected void remove(OrganizationComponent department) {
        log.info("移除院系.........{}", department.getName());
        departments.remove(department);
    }

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

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

    @Override
    public void print() {
        log.info("================== "+getName()+" ==========================");
        departments.forEach(OrganizationComponent::print);
    }
}
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import java.util.List;

/**
 * @Description 院系-具体组件
 */
@Slf4j
public class Department extends OrganizationComponent {

    public Department(String name, String desc) {
        super(name, desc);
    }

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

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

    @Override
    public void print() {
        log.info("================== " + getName() + " ==========================");
    }
}
/**
 * @Description 测试用例
 */
public class Client {

    public static void main(String[] args) {

        OrganizationComponent university = new University("HFUT", "好大学");

        OrganizationComponent college1 = new College("学院1", "学院1描述");
        OrganizationComponent college2 = new College("学院2", "学院2描述");


        OrganizationComponent department1 = new Department("学院1-专业1", "学院1-专业1描述");
        OrganizationComponent department2 = new Department("学院1-专业2", "学院1-专业2描述");
        OrganizationComponent department3 = new Department("学院1-专业3", "学院1-专业3描述");

        OrganizationComponent department4 = new Department("学院2-专业1", "学院2-专业1描述");
        OrganizationComponent department5 = new Department("学院2-专业2", "学院2-专业2描述");
        OrganizationComponent department6 = new Department("学院2-专业3", "学院2-专业3描述");

        university.add(college1);
        university.add(college2);

        college1.add(department1);
        college1.add(department2);
        college1.add(department3);

        college2.add(department4);
        college2.add(department5);
        college2.add(department6);

        university.print();

    }
}

为什么要使用组合模式?

通过上面的原理和使用场景分析,我们还可以总结出使用组合模式的三个主要原因。

第一,希望一组对象按照某种层级结构进行管理,比如,管理文件夹和文件,管理订单下的商品等。树形结构天然有一种层次的划分特性,能够让我们自然地理解多个对象间的结构。

  • 第二,需要按照统一的行为来处理复杂结构中的对象

,比如,创建文件,删除文件,移动文件等。在使用文件时,我们其实并不关心文件夹和文件是如何被组织和存储的,只要我们能够正确操作文件即可,这时组合模式就能够很好地帮助我们组织复杂的结构,同时按照定义的统一行为进行操作。

  • 第三,能够快速扩展对象组合。

比如,订单下的手机商品节点可以自由挂接不同分类的手机(品牌类的,如华为、苹果),并且还可以按照商品的特性(如,价格、图片、商家、功能等)再自由地挂接新的节点组合,而查找时可以从手机开始查找,不断增加节点类型,直到找到合适的手机商品。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值