8. 装饰者模式(Decorator Pattern)

定义

  • 在不改变原有对象的基础之上,将功能附加到对象上
  • 提供了不继承更有弹性的替代方案(扩展原有对象功能)

类型

  • 结构型

使用场景

  • 扩展一个类的功能或给一个类添加附加职责
  • 动态的给一个对象添加功能,这功能可以再动态的撤销

优点

  • 继承的有力补充,比继承灵活,不改变原有对象的情况下给一个对象扩展功能
  • 通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同的效果
  • 符合开闭原则

缺点

  • 会出现更多的代码,更多的类,增加程序复杂性
  • 动态装饰时,多层装饰时会更复杂

相关设计模式

  • 装饰者模式和代理模式

装饰者模式关注一个对象动态的添加方法,代理模式在于控制对对象的访问,代理模式的代理类,可以对他的客户隐藏一个对线的具体信息,通常在使用代理模式时,在代理类中创建一个对象的实例,而使用装饰者模式时,通常会把原始对象做一个参数,传递给装饰者的构造器。

  • 装饰者模式和适配器模式

两者都可以叫做包装模式,装饰者和被装饰者可以实现相同的接口,或者装饰者是被装饰者的子类。在适配器中,适配器和被适配的类具有不同的接口,有可能部分接口是重合的。

代码示例

首先我们假设一个场景。我们早上吃早饭。买个煎饼果子,可以加蛋加烤肠。并计算价格。按一般方法我们是这么写的

  1. 创建一个煎饼果子对象
public class Battercake {
    protected String getDesc(){
        return "煎饼果子";
    }

    protected int cost(){
        return 8;
    }
}

  1. 创建一个加蛋的煎饼果子
public class BattercakeWithEgg extends Battercake{
    @Override
    protected String getDesc() {
        return super.getDesc() + "加一个鸡蛋";
    }

    @Override
    protected int cost() {
        return super.cost() + 2;
    }
}

  1. 创建一个加蛋加烤肠的煎饼果子
public class BattercakeWithEggSausage extends BattercakeWithEgg{
    @Override
    protected String getDesc() {
        return super.getDesc() + "加一根烤肠";
    }

    @Override
    protected int cost() {
        return super.cost() + 2;
    }
}

  1. 我们现在可以得到三种类型的煎饼果子
public class Test {
    public static void main(String[] args) {
        Battercake battercake = new Battercake();
        System.out.println(battercake.getDesc() + ",价格:" + battercake.cost());

        BattercakeWithEgg battercakeWithEgg = new BattercakeWithEgg();
        System.out.println(battercakeWithEgg.getDesc() + ",价格:" + battercakeWithEgg.cost());

        BattercakeWithEggSausage battercakeWithEggSausage = new BattercakeWithEggSausage();
        System.out.println(battercakeWithEggSausage.getDesc() + ",价格:" + battercakeWithEggSausage.cost());
    }
}

执行结果

煎饼果子,价格:8
煎饼果子加一个鸡蛋,价格:10
煎饼果子加一个鸡蛋加一根烤肠,价格:12

UML
在这里插入图片描述
通过uml我们可以看出。这就是一个单纯的继承,它现在的扩展性是非常差的。假设我们的煎饼果子可以加很多不同的东西。那它的组合是非常复杂的。那按我们现在的这种写法,可能会发生类数量爆炸的情况。这是我们就要考虑让我们的代码更加优雅,如何实现呢,当然是我们的装饰者模式啦。

步骤

组成:抽象实体类,确定的实体类,抽象的装饰者,确定的装饰者

  1. 抽象实体类,我们要对煎饼进行抽象。
public abstract class AbstractBattercake {
    protected abstract String getDesc();
    protected abstract int cost();
}

  1. 确定的实体类,具体的煎饼
public class Battercake {
    protected String getDesc(){
        return "煎饼果子";
    }

    protected int cost(){
        return 8;
    }
}
  1. 抽象的装饰者
public abstract class AbstractDecorator extends AbstractBattercake{
    private AbstractBattercake abstractBattercake;
	//我们需要引入被修饰对象的实例变量,所以就作为构造参数输入了
    public AbstractDecorator(AbstractBattercake abstractBattercake) {
        this.abstractBattercake = abstractBattercake;
    }

    @Override
    protected String getDesc() {
        return this.abstractBattercake.getDesc();
    }

    @Override
    protected int cost() {
        return this.abstractBattercake.cost();
    }
}
  1. 具体的装饰者
public class EggDecorator extends AbstractDecorator{
    public EggDecorator(AbstractBattercake abstractBattercake) {
        super(abstractBattercake);
    }

    @Override
    protected String getDesc() {
        return super.getDesc() + "加一个鸡蛋";
    }

    @Override
    protected int cost() {
        return super.cost() + 2;
    }
}
public class SausageDecorator extends AbstractDecorator{
    public SausageDecorator(AbstractBattercake abstractBattercake) {
        super(abstractBattercake);
    }

    @Override
    protected String getDesc() {
        return super.getDesc()  + "加一根烤肠";
    }

    @Override
    protected int cost() {
        return super.cost() + 2;
    }
}

  1. 为了体现与开始写法不同。我们要获得一个 加两个鸡蛋一根烤肠的煎饼果子
public class Test {

    public static void main(String[] args) {
        AbstractBattercake abstractBattercake;
        abstractBattercake = new Battercake();
        abstractBattercake = new EggDecorator(abstractBattercake);
        abstractBattercake = new EggDecorator(abstractBattercake);
        abstractBattercake = new SausageDecorator(abstractBattercake);

        System.out.println(abstractBattercake.getDesc() + ",价格:" + abstractBattercake.cost());
    }
}

执行结果

煎饼果子加一个鸡蛋加一个鸡蛋加一根烤肠,价格:14

UML
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值