设计模式之装饰者模式的应用场景(Decorator)

问题

装饰者模式的问题,我想从桥接模式引入,对桥接模式不了解的可以参考设计模式之桥接模式。桥接模式解决的问题是我卖的笔记本电脑的组成例如cpu或cache有很多种类型或大小,如果使用继承的方式,会生成非常多的类,难以维护。所以使用桥接模式,将cpu或cache抽象化,在生产电脑时,再将特定类型或大小的组成部分组装到笔记本电脑中。完美!

但是呢,现在又一个问题出现了,客户对电脑要求越来越高,希望可以扩展插入SSD和内存条。嗯,听到这个问题,我觉得很简单呀,在电脑中继续扩展两个组件SSD和cache。这时候发现有一个问题就是原来电脑就有cache的组件了,将cache扩展成list即可,另一种方式就是引入本章的主题——装饰者模式

简介

为什么上面的问题可以用装饰者模式来解决呢?首先,我们从字面上来理解一下,装饰者模式就是给人或物品增加装饰,比如人穿上衣服,化妆或者给房子增加家具等。可以这么理解装饰者模式:

某对象有一个核心功能,现在有一个其衍生对象,扩展了若干功能,但是原对象也有使用场景。在此场景下,可对衍生对象用装饰者模式。

再来上面的问题,为什么我用装饰者模式呢?因为电脑的核心或者必备组件我们之前都已经定义过了,而新增的SSD和cache都是非必须的,添加了的话,电脑性能会更好,没有呢,也可以正常使用电脑,在这种场景下使用装饰者模式,我觉得是相对比较合理的。在考虑使用场景时,可以通过考虑此组件或属性是否可以动态撤销来决定是否使用装饰者模式。

实现

先看Computer(有一些其他设计模式的代码在其中,请忽略)

public class Computer implements Cloneable {

    private String screen;

    private String cpu;

    private String keyboard;

    private String disk;

    /**
     * 主机
     */
    private String engine;

    private String cache;

    /**
     * U盘
     */
    private ArrayList<String> usbFlashDisk;

    public Computer() {
    }

    public Computer(String screen, String cpu, String keyboard, String disk, String engine,
                    String cache) {
        this.screen = screen;
        this.cpu = cpu;
        this.keyboard = keyboard;
        this.disk = disk;
        this.engine = engine;
        this.cache = cache;
    }

    public String getScreen() {
        return screen;
    }

    public void setScreen(String screen) {
        this.screen = screen;
    }

    public String getCpu() {
        return cpu;
    }

    public void setCpu(String cpu) {
        this.cpu = cpu;
    }

    public String getKeyboard() {
        return keyboard;
    }

    public void setKeyboard(String keyboard) {
        this.keyboard = keyboard;
    }

    public String getDisk() {
        return disk;
    }

    public void setDisk(String disk) {
        this.disk = disk;
    }

    public String getEngine() {
        return engine;
    }

    public void setEngine(String engine) {
        this.engine = engine;
    }

    public String getCache() {
        return cache;
    }

    public void setCache(String cache) {
        this.cache = cache;
    }

    public ArrayList<String> getUsbFlashDisk() {
        return usbFlashDisk;
    }

    public void setUsbFlashDisk(ArrayList<String> usbFlashDisk) {
        this.usbFlashDisk = usbFlashDisk;
    }

    @Override
    public String toString() {
        System.out.println("computer is combined by : ---" + getCpu() + "--" + getCache() + "---" + getDisk()
        + "----" + getEngine() + "----" + getKeyboard() + "----" + getScreen());
        return super.toString();
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        Computer computer = (Computer) super.clone();
        ArrayList<String> usbFlashDisk = (ArrayList<String>) getUsbFlashDisk().clone();
        computer.setUsbFlashDisk(usbFlashDisk);
        return computer;
    }
}

装饰者的抽象类(为了可能会出现其他装饰而设计的抽象类):

public abstract class ComputerDecorator {

    protected Computer computer;

    public ComputerDecorator(Computer computer) {
        this.computer = computer;
    }
}

装饰者的实现类:

public class CommonComputerDirector extends ComputerDecorator {

    private List<SSD> ssdList;

    private List<Cache> cacheList;


    public CommonComputerDirector(Computer computer) {
        super(computer);
        cacheList = new ArrayList<>();
        ssdList = new ArrayList<>();
    }

    public void addSsd(SSD ssd) {
        ssdList.add(ssd);
    }

    public void addCache(Cache cache) {
        cacheList.add(cache);
    }

    public void play() {
        System.out.println("play with computer with extra devices: ssd size: " + ssdList.size() +
                "  cache size: " + cacheList.size());
    }

}

执行代码:

    public static void main(String[] args) {
        Computer computer = new Computer("base screen", "base cpu", "base keyboard",
                "base disk", "base engine", "base cache");
        computer.toString();

        CommonComputerDirector commonComputerDirector = new CommonComputerDirector(computer);
        commonComputerDirector.addCache(new EightCache());
        commonComputerDirector.addSsd(new SSD());
        commonComputerDirector.play();
    }

执行结果:

computer is combined by : ---base cpu--base cache---base disk----base engine----base keyboard----base screen
play with computer with extra devices: ssd size: 1  cache size: 1

从结果即可看到,我们通过装饰者模式添加了额外的ssd和cache,可能你会在看代码或者自己写代码的过程中想到这个其实是可以用建造者模式来实现。解释一下:因为我这次装饰者模式添加的都是配件,而这些组件确实都是可以用建造者模式来实现,但是呢,装饰者模式不仅仅可以添加配件,还可以在添加配件之后,衍生出一些能力出来,这是建造者模式无法做到的。例如,我添加ssd和cache之后,就可以带的动更大的游戏,例如使命召唤。我就可以在装饰者中添加playGame的能力。

总结

应用场景:对已拥有必备组件的对象进行扩展高阶组件或属性。

优点:

  1. 无需修改现有对象,也无需创建对象的子类,即可扩展对象的功能。
  2. 可以多扩展功能进行动态添加或删除
  3. 可以扩展不同的装饰者来解决扩展不同功能的问题

缺点:多层装饰会比较复杂,无法控制装饰的顺序

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java常用的设计模式包括: 1. 单例模式(Singleton Pattern):用于确保一个类只有一个实例,并提供全局访问点。 应用场景:多线程环境下的资源共享、数据库连接池等。 2. 工厂模式(Factory Pattern):通过一个工厂类来创建对象,将对象的创建和使用分离。 应用场景:对象的创建比较复杂,需要隐藏具体实现逻辑的时候。 3. 抽象工厂模式(Abstract Factory Pattern):提供一个接口用于创建相关或依赖对象的家族,而不需要明确指定具体类。 应用场景:需要创建一系列相互关联或依赖的对象时。 4. 建造者模式(Builder Pattern):通过一个指导者来按照一定的步骤创建复杂对象,将对象的构造和表示分离。 应用场景:需要创建一个包含多个组成部分的复杂对象,并且需要控制创建过程的时候。 5. 原型模式(Prototype Pattern):通过复制现有对象来创建新对象,避免了直接使用new关键字创建对象。 应用场景:需要创建大量相似对象,并且创建过程比较耗时或复杂的时候。 6. 适配器模式(Adapter Pattern):将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。 应用场景:需要使用一个已有的类,但其接口与需要的接口不一致时。 7. 装饰器模式(Decorator Pattern):动态地将责任附加到对象上,在保持功能完整性的同时,灵活地给对象添加新的行为。 应用场景:需要动态地给一个对象添加功能,或者为一个对象添加多个不同的功能。 8. 观察者模式(Observer Pattern):定义一种一对多的依赖关系,当一个对象状态发生改变时,所有依赖它的对象都会收到通知并自动更新。 应用场景:当一个对象的改变需要同时改变其他对象的时候。 9. 策略模式(Strategy Pattern):定义一系列算法,并将每个算法封装起来,使它们可以互相替换,使得算法可以独立于使用它的客户而变化。 应用场景:需要在多个算法中选择一种合适的算法时。 10. 模板方法模式(Template Method Pattern):定义一个操作中的算法骨架,将一些步骤延迟到子类中实现。 应用场景:当算法有固定的骨架,但其中的某些步骤可以有多种实现方式时。 以上是Java常用的设计模式及其应用场景,根据具体情况选择合适的设计模式可以提高代码的可维护性、扩展性和复用性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值