手抓饼加生菜加鸡蛋的装饰器模式

装饰器模式

装饰器模式(Decorator Patter),也称为包装模式(Wrapper Pattern)是指在不改变原有对象的基础之上,将功能附加在对象上,提供了比继承更有弹性的替代方案(扩展原有对象的功能),属于结构型模式。

装饰器模式的核心是功能扩展。使用装饰器可以透明且动态地扩展类的功能。

下面是通用的UML类图:

生活中的应用场景

看完上面的概念以及类图可能比较抽象,接下来我会举一个生活中的场景,来通俗易懂的讲解装饰器模式。

我们在早上上班途中,往往会在公司门口买一个手抓饼,然后带到工位上慢慢吃,相信很多小伙伴有过类似的经历。那么一个手抓饼什么都不加就是五块钱,我们把这个叫做标配,当然也可以按照你的喜好做一些定制化的需求,加里脊,加生菜,加培根等等,全凭个人的喜好来,这个过程就是一个装饰器模式。

下面我们用代码还原一下码农的生活。首先创建一个手抓饼的抽象Pancake类:

/**
 * @author jackxu
 */
public abstract class Pancake {

    protected abstract String getMsg();

    protected abstract int getPrice();

}

创建一个基本的手抓饼类BasePancake,我们把这个叫做标配,就是什么都不加的五块钱一个

/**
 * @author jackxu
 */
public class BasePancake extends Pancake {

    @Override
    protected String getMsg() {
        return "标配手抓饼";
    }

    @Override
    public int getPrice() {
        return 5;
    }

}

然后再创建一个扩展手抓饼的抽象装饰器PancakeDecorator类:

/**
 * @author jackxu
 */
public class PancakeDecorator extends Pancake {


    private Pancake pancake;


    public PancakeDecorator(Pancake pancake) {
        this.pancake = pancake;
    }

    @Override
    protected String getMsg() {
        return this.pancake.getMsg();
    }

    @Override
    public int getPrice() {
        return this.pancake.getPrice();
    }

}

创建一个继承自抽象装饰器类的生菜装饰器LettuceDecorator类:

/**
 * @author jackxu
 */
public class LettuceDecorator extends PancakeDecorator {

    public LettuceDecorator(Pancake pancake) {
        super(pancake);
    }

    @Override
    protected String getMsg() {
        return super.getMsg() + "+1片生菜";
    }

    @Override
    public int getPrice() {
        return super.getPrice() + 1;
    }

}

同理创建一个鸡蛋装饰器EggDecorator类:

/**
 * @author jackxu
 */
public class EggDecorator extends PancakeDecorator {

    public EggDecorator(Pancake pancake) {
        super(pancake);
    }

    @Override
    protected String getMsg() {
        return super.getMsg() + "+1个鸡蛋";
    }

    @Override
    public int getPrice() {
        return super.getPrice() + 1;
    }

}

好,现在所有的类都已经写完了,让我们写个测试用例来测试一下:

/**
 * @author xhj
 * @date 2021/2/23 16:45
 */
public class Test {

    public static void main(String[] args) {
        //A同学买了一个标配
        Pancake pancake = new BasePancake();
        System.out.println("A同学买了一个" + pancake.getMsg() + ",总价是" + pancake.getPrice() + "元");

        //B同学买了加鸡蛋的手抓饼
        Pancake pancakeWithEgg = new EggDecorator(pancake);
        System.out.println("B同学买了一个" + pancakeWithEgg.getMsg() + ",总价是" + pancakeWithEgg.getPrice() + "元");

        //C同学买了加生菜的手抓饼
        Pancake pancakeWithLettuce = new LettuceDecorator(pancake);
        System.out.println("C同学买了一个" + pancakeWithLettuce.getMsg() + ",总价是" + pancakeWithLettuce.getPrice() + "元");

        //D同学买了加鸡蛋加生菜的手抓饼
        Pancake pancakeWithEggAndLettuce = new LettuceDecorator(pancakeWithEgg);
        System.out.println("D同学买了一个" + pancakeWithEggAndLettuce.getMsg() + ",总价是" + pancakeWithEggAndLettuce.getPrice() + "元");
    }

}

运行结果:

怎样,与我们预期希望看到的结果相符吧,我们用代码还原了现实生活中的一个场景。标配还是那个标配,对于别的需求,我们可以通过层层包装、装饰来实现很多的排列组合,而不是通过继承的方式,为每一种情况都生成一个类,那这样就会产生很多的类,这就是装饰器巧妙、灵活的地方。

最后让我们看下这几个类的UML类图:

和上面通用的类图长的一样吧,这里的PancakeDecorator抽象装饰器是非必需的,如果装饰器多的话我们可以抽象一个出来,如果装饰器单一的话,就可以省略该类,直接继承Pancake实现一个具体装饰器即可。

源码中的应用场景

当我在学习mybatis里面的一级缓存和二级缓存的时候,我看它的源码,发现在cache包下面有一个熟悉的单词,那就是decorators,这个就是装饰的意思,我大胆的猜测它用的就是装饰器模式。

查看了一下引用,发现一段似曾相识的代码,原来decorators包下的每一个类都是装饰类,这里面将cache层层的包装,达到对缓存作用增强的功能。

具体增强的功能如下:

装饰器模式的优缺点

优点:

  • 装饰器是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地给一个对象扩展功能,即插即用。
  • 通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果。
  • 装饰器完全遵守开闭原则。
    缺点:
  • 会出现更多的代码,更多的类,增加程序复杂性。
  • 动态装饰时,多层装饰会更复杂。

源码

https://github.com/xuhaoj/pattern-demo ,其他设计模式的例子也在该项目中,谢谢大家的观看。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值