组合模式

组合模式 Composite Pattern 概述

  1. 什么是组合模式: 部分与整体的一种层次结构型设计模式,设计单个对象与组合对象使用一致的处理方式,然客户以一致的方式处理个别对象与组合对象
  2. 通过实际案例解释组合模式: 例如目录,在目录下面可能还有子目录,在子目录下方可能还有文件,例如学校: 学校下方有各个院校,院校下方有分为各个系,系下面可能还有多个种类,关注点:树形结构,大的级别包含小的级别
  3. 通过目录来说明可能存在的问题: 上级目录中删除或添加子级目录,子集目录中删除或添加文件,文件中可能还有属于文件的目录,不确定哪个是子节点,并且级别不同,添加删除的是当前级别中的子级别,其它级别中的添加删除与当前级别中的类型不同,通过组合设计模式,做到一视同仁,强调的是客户端忽略层次结构的差异,方便对整个层次的控制符合开闭原则,更方便的添加新的父节点,子节点,遍历组织结构,或处理的树形接口,容易添加节点或叶子节点,如果节点与叶子节点差异性较大不适合使用

组合模式示例

案例: 学习院系展示系统,可以展示学校中的学院,学院中的各个系,输出学校中的院校,院校中的各个系,以及学校对学院的增删查,学院对系的曾删查,系对自己的描述

实现思路

  1. 如何做到客户端忽略各个级别? 根据实现功能抽象出公共的抽象父类,各个级别类型共同实现该接口,在客户端调用时只需要创建父类引用
  2. 如何做不同级别中功能的兼容? 在抽象父类中先定义抽象方法,或默认的方法,可以是抛出异常,可以是空方法,然后根据不同级别要实现的功能,对方法进行重写
  3. 不同级别是包含关系,例如学习中包含多个学院,学院中又包含多个学系

代码示例

  1. 根据功能抽象出公共的父类Management,添加,删除,描述等,提供抽象方法,默认方法等,子类学校,院,系继承父类,根据自己的需求选在重写这些方法,由于"学校",“学院”,"系"等都实现了Management父类,在客户端调用时,不需要考虑调级别类型,以相同方式进行处理即可
//根据功能抽象出公共父类
abstract class Management{
    public String nameDesc;


    //提供带参构造对名称,人数进行赋值
    public Management(String nameDesc){
        this.nameDesc = nameDesc;

    }

    //功能方法: 根据级别需求的不同进行重写
    //添加操作
    //提供抛出异常的默认方法,适用于不管什么级别都需要实现的功能
    //但是这个功能对应级别的不同实现的逻辑不同
    public void add(Management management){
        throw new UnsupportedOperationException("操作有误");
    }

    //删除操作
    //提供空的默认方法,适用于有的级别中可能没有这个功能,
    public void delete(String nameDesc){

    }
    //描述操作
    //抽象方法
    abstract void desc();
    //获取总人数
    abstract int getPersonCount();
}
  1. 创建不同级别的实现子类,例如 系—>学院—>院校,注意:级别不同功能不同,例如学院中可以添加删除系,学校中可以添加删除学院,不同级别之间相互的关系,大的包含小的,
    系,假设系是最小节点,不可以添加删除,只可以获取,则不需要重写父类中提供的添加删除方法,调用父类中默认的
    院,注意院中可以包含多个系,将系以集合组合到院中,院中可以添加删除系,重写父类的添加删除方法…
//系
class Series extends Management{
    //系中添加人数属性
    public int personCount;

    public Series(String nameDesc, int personCount){
        super(nameDesc);
        this.personCount = personCount;
    }
    //重写描述方法,获取当前系的名称,人数即可
    @Override
    public void desc() {
        System.out.println(nameDesc+",人数"+personCount);
    }
    //重写获取人数方法,获取当前系的人数
    @Override
    public int getPersonCount() {
        return personCount;
    }
}
//学院
class College extends Management{
    //学院中包含多个系,注入系集合
    public List<Management> seriesList;

    public College(String nameDesc) {
        super(nameDesc);
    }
    //重写院校的获取人数的方法,该方法中是通过
    //遍历组合进来的系,获取每个系中的人数相加
    @Override
    public int getPersonCount() {
        if(null == seriesList || seriesList.size() <= 0)
            return 0;
        return seriesList.stream()
                .map(Management::getPersonCount)
                    .reduce(Integer :: sum).get();
    }
    //重写院校的描述方法,首先获取院校的基本信息进行描述
    //然后遍历院校中组合进来的系,通过系对象调用各自系的desc方法
    @Override
    public void desc() {
       System.out.println(nameDesc+",该院总人数为:"+getPersonCount());
       if(null == seriesList || seriesList.size <= 0)
           return;
       seriesList.stream().forEach(management -> management.desc());

    }
    //重写添加方法,院校中可以添加系
    @Override
    public void add(Management series){
        if(null == seriesList){
            seriesList = new ArrayList<>();
            seriesList.add(series);
        }else {
            seriesList.add(series);
        }
    }
    //删除方法
    @Override
    public void delete(String nameDesc){
        if(null == seriesList || seriesList.size() <= 0)
            return ;
        //获取seriesList中不包含该nameDesc的重新赋值给seriesList
        seriesList = seriesList.stream()
                .filter(s -> !s.nameDesc.equals(nameDesc))
                    .collect(Collectors.toList());
    }
}
//学校
class School extends Management{
    //学校中包含学院
    public List<Management> collegeList;

    public School(String nameDesc) {
        super(nameDesc);
    }

    @Override
    public void desc() {
        //本级别中学校的描述
        System.out.println(nameDesc+",该校总人数为:"+getPersonCount());
        if(null == collegeList)
            return;
        //循遍历学校中包含的College院校,调用College中的描述,而College中的desc()方法内部
        //是遍历系院校中包含的系Series,通过Series调用系的desc()方法
        collegeList.stream().forEach(college -> college.desc());
    }

    @Override
    public int getPersonCount() {
        if(null == collegeList || collegeList.size() <= 0)
            return 0;
        return collegeList.stream()
                .map(Management::getPersonCount)
                .reduce(Integer :: sum).get();
    }

    @Override
    public void add(Management college){
        if (null == collegeList) {
            collegeList = new ArrayList<>();
            collegeList.add(college);
        }else {
            collegeList.add(college);
        }
    }

    @Override
    public void delete(String nameDesc){
        if(null == collegeList || collegeList.size() <= 0)
            return ;
        //删除学校中的系,获取集合中不包含该nameDesc的重新赋值给collegeList
        collegeList = collegeList.stream()
                .filter(c -> !c.nameDesc.equals(nameDesc))
                .collect(Collectors.toList());
    }
}
  1. 调用测试,客户端在添加删除时,并不会根据级别不同调用不同的方法,而是一致的操作
public class Test3 {
    public static void main(String[] args) {
        //通过new Series()可以看出创建的是系
        Management series1 = new Series("通讯工程系",400);
        //调用自己重写的desc方法
        series1.desc();
        //由于系是最小节点,不可以添加和删除,没有重写添加删除方法,实际调用的是父类Management中的
        //series1.delete("通讯工程系");

        //创建"网络安全系"
        Management series2 = new Series("网络安全系", 200);

        //创建"计算机学院"
        Management college = new College("计算机学院");
        //将前面创建的系通过add()方法添加到学院中
        college.add(series1);
        college.add(series2);
        //college.desc();

        //创建"离离原上草学校"
        Management school = new School("离离原上草学校");
        //将学院添加到学校中
        school.add(college);
        //删除学校中的"计算机学院"
        school.delete("计算机学院");
        school.desc();

    }
}

JDK 中组合模式的应用案例

查看集合包下的 Map接口,在接口中有抽象的公共方法,该接口被被AbstractMap抽象类实现,拿接口中的putAll()方法来说, 在Map中定义了putAll()抽象方法, Abstract抽象子类中重写了该方法,但是并不是实际的功能处理,而是抛出了一个异常,再继续向下查找,HashMap继承了,Map接口,并实现了AbstractMap抽象子类,重写了putAll()抽象方法,进行实际处理,在这里HashMap就相当于我们现在各个级别的的具体节点例如学校,院等,继续向下分析,在HashMap中有一个Node内部类,这个Node就可以看为是叶子节点,相当于此处的系,而Map,AbstractMap相当于此处根据功能抽象出的公共父类Management,不同之处在于Map,多抽象出了一个接口

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值