JAVA架构师之路十:设计模式之组合模式

JAVA架构师之路九:设计模式之享元模式

每个人出生的时候都是原创,可悲的是很多人渐渐都成了盗版。

俗话说:男女搭配,干活不累!这句话讲究的是合适的组合,能使效果更好。代码世界中同样存在这样的模式——组合模式

1. 组合模式

定义

也称为整体部分模式,宗旨是通过将单个对象(叶子节点)和组合对象(树枝节点)用相同的接口进行表示
作用:使客户端对单个对象和组合对象保持一致的方式处理
属于结构型模式

优点

清楚地定义分层次的复杂对象,表示对象的全部或者部分层次
让客户端忽略了层次的差异,方便对整个层次接口进行控制
简化客户端代码
符合开闭原则

缺点

限制类型时会较为复杂
使设计变得更加抽象

2. 透明组合模式

举个例子:大学期间,一共上四年,四年中每年学的课程都不一样。四年中每年的课程组合形成了我们大学的整个课程体系,那么问题来了,我们怎么设计这种组合模式来层级输出大学四年每年的课程呢?

public abstract class CourseComponet {

    public void addChild(CourseComponet componet) {
        throw new UnsupportedOperationException("不支持添加操作");
    }

    public void removeChild(CourseComponet componet) {
        throw new UnsupportedOperationException("不支持删除操作");
    }

    public String getName() {
        throw new UnsupportedOperationException("不支持获取名称操作");
    }

    public double getPrice() {
        throw new UnsupportedOperationException("不支持获取价格操作");
    }

    public void print() {
        throw new UnsupportedOperationException("不支持打印操作");
    }

}
public class Course extends CourseComponet {

    private String name;

    private double price;

    public Course(String name, double price) {
        this.name = name;
        this.price = price;
    }

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

    @Override
    public double getPrice() {
        return this.price;
    }

    @Override
    public void print() {
        System.out.println(name + ":" + price + "元");
    }
}

public class CoursePackage extends CourseComponet {

    private List<CourseComponet> items = new ArrayList<CourseComponet>();

    private String name;

    private Integer level;

    public CoursePackage(String name, Integer level) {
        this.name = name;
        this.level = level;
    }

    @Override
    public void addChild(CourseComponet componet) {
        items.add(componet);
    }

    @Override
    public void removeChild(CourseComponet componet) {
        items.remove(componet);
    }

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

    @Override
    public void print() {
        System.out.println(this.name);
        for (CourseComponet c : items) {
            if (this.level != null) {
                for (int i = 0; i < this.level; i++) {
                    System.out.print("  ");
                }
                for (int i = 0; i < this.level; i++) {
                    if (i == 0) {
                        System.out.print("+");
                    }
                    System.out.print("-");
                }
            }
            c.print();
        }
    }
}
public class Test {

    public static void main(String[] args) {
        System.out.println("=============透明的组合模式==============");

        CourseComponet pd = new Course("程序设计基础", 84);
        CourseComponet wjf = new Course("微积分", 130);
        CourseComponet wl = new Course("物理", 76);

        CourseComponet firstYear = new CoursePackage("第一年课程", 2);
        firstYear.addChild(pd);
        firstYear.addChild(wjf);
        firstYear.addChild(wl);

        CourseComponet gll = new Course("概率论", 34);
        CourseComponet sxzz = new Course("思想政治", 45);
        CourseComponet javaCourse = new Course("Java高级程序设计", 203);

        CourseComponet secondYear = new CoursePackage("第二年课程", 3);
        secondYear.addChild(gll);
        secondYear.addChild(sxzz);
        secondYear.addChild(javaCourse);

        CourseComponet sf = new Course("算法", 302);
        CourseComponet js = new Course("JavaScript", 280);

        CourseComponet thirdYear = new CoursePackage("第三年课程", 4);
        thirdYear.addChild(sf);
        thirdYear.addChild(js);

        CourseComponet sy = new Course("嵌入式实验", 56);
        CourseComponet lw = new Course("毕业论文", 500);
        
        CourseComponet firthYear = new CoursePackage("第四年课程", 5);
        firthYear.addChild(sy);
        firthYear.addChild(lw);
        
        CourseComponet daxue = new CoursePackage("大学课程", 1);
        daxue.addChild(firstYear);
        daxue.addChild(secondYear);
        daxue.addChild(thirdYear);
        daxue.addChild(firthYear);

        daxue.print();

    }
}
=============透明的组合模式==============
大学课程
  +-第一年课程
    +--程序设计基础:84.0元
    +--微积分:130.0元
    +--物理:76.0元
  +-第二年课程
      +---概率论:34.0元
      +---思想政治:45.0元
      +---Java高级程序设计:203.0元
  +-第三年课程
        +----算法:302.0元
        +----JavaScript:280.0元
  +-第四年课程
          +-----嵌入式实验:56.0元
          +-----毕业论文:500.0元

在这里插入图片描述
首先定义一个课程组合抽象类,这个类中定义了所有方法,另外定义一个课程类继承这个抽象类,课程有的方法就是定义名字和书本价格,打印名字和价格,所以要重写父类的这三个方法,在定义一个课程包,也继承课程组合抽象类,课程包是什么?是存储课程的集合,和这个包的名字,还有这个包所在的级别。那么自然的他就有添加课程,删除课程,打印课程名字,获取课程包名字的方法,这些方法就需要重写。那么整个大学四年的课程,就可以分类装进对应的包中,最后把包装进大学四年课程这个包中,组成一棵树形结构打印。这就是组合模式
但是这种写法存在问题,由于课程类没有重写添加和删除接口,那边课程再调用方法的时候是报错的,这是不安全的写法。

CourseComponet wjf = new Course("微积分", 130);
CourseComponet wl = new Course("物理", 76);
wl.addChild(wjf);

在这里插入图片描述

3. 安全组合模式

举个例子:典型的磁盘目录结构

public abstract class Direcotry {

    protected String name;

    public Direcotry(String name) {
        this.name = name;
    }

    public abstract void show();
}
public class Folder extends Direcotry {

    private List<Direcotry> dirs;

    private Integer level;

    public Folder(String name, Integer level) {
        super(name);
        this.level = level;
        this.dirs = new ArrayList<Direcotry>();

    }

    @Override
    public void show() {
        System.out.println(this.name);
        for (Direcotry c : dirs) {
            if (this.level != null) {
                for (int i = 0; i < this.level; i++) {
                    System.out.print("  ");
                }
                for (int i = 0; i < this.level; i++) {
                    if (i == 0) {
                        System.out.print("+");
                    }
                    System.out.print("-");
                }
            }
            c.show();
        }
    }

    public boolean add(Direcotry dir) {
        return this.dirs.add(dir);
    }

    public boolean remove(Direcotry dir) {
        return this.dirs.remove(dir);
    }

    public Direcotry get(int index) {
        return this.dirs.get(index);
    }
}
public class File extends Direcotry {

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

    @Override
    public void show() {
        System.out.println(this.name);
    }
}
public class Test {

    public static void main(String[] args) {
        System.out.println("=============安全的组合模式==============");

        File qq = new File("QQ.exe");
        File wx = new File("WX.exe");

        Folder office = new Folder("办公软件", 2);
        File word = new File("word.exe");
        File ppt = new File("ppt.exe");
        office.add(word);
        office.add(ppt);

        Folder dir = new Folder("D盘:", 1);
        dir.add(qq);
        dir.add(wx);
        dir.add(office);
        dir.show();
    }
}
=============安全的组合模式==============
D盘:
  +-QQ.exe
  +-WX.exe
  +-办公软件
    +--word.exe
    +--ppt.exe

如果这时候,我想查看目录中有什么文件?这时候只需要扩展Folder方法就行。

public void list() {
        for (Direcotry dir : dirs) {
            System.out.println(dir.name);
        }
    }

这时候,File是没有list()方法的,这就是安全模式。

感谢您阅读本文,如果您觉得文章写的对您有用的话,请您点击上面的“关注”,点个赞,这样您就可以持续收到《JAVA架构师之路》的最新文章了。文章内容属于自己的一点点心得,难免有不对的地方,欢迎在下方评论区探讨,你们的关注是我创作优质文章的动力。

JAVA架构师之路十一:设计模式之适配器模式

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值