装饰者模式

作者: 咋家 | 来源:发表于2020-03-27 10:05 被阅读0次

装饰者模式,实现动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,其体现了开闭原则。这么说,比较抽象,我们通过一个项目需求也体会装饰者模式的好处。

1、咖啡订单项目

具体需求如下:

咖啡种类有多种:Espresso(意大利咖啡),LongBlack(美式咖啡),Decaf(无因咖啡)

调料:Milk,Chocolate

要求在扩展新的咖啡种类时,具有良好的扩展性,改动方便

计算不同种类咖啡的费用:客户可以点单品咖啡,也可以点单品咖啡+调料组合

2、传统方案1

一套继承解决,类图如下:

把Drink做成一个抽象类,表示饮料,然后各个咖啡种类与调料的组合去继承实现,非常简单暴力。带来的问题也很明显,当增加一个咖啡种类或新的调料时,类的数量就会倍增,出现类爆炸。

3、传统方式2

考虑到咖啡种类+调料会造成类爆炸,可以将调料内置到Drink类中,通过选项控制有无调料,这样就不会造成类数量过多。


好处是可以控制类的数量,但是在增加或者删除调料种类时,代码维护量很大。下面我们引入装饰者模式。

4、装饰者模式

装饰者模式就像打包一个快速

主体:比如,陶瓷、衣服等称为被装饰者

包装:比如报纸填充,塑料泡沫等称为装饰器

其角色主要分为三类:

Component主体:多为抽象类或接口,需要装饰器和被装饰者来实现

ConcreteComponent:主体的一个具体实现

Decorator:装饰器,同样要实现主体,同时要聚合主体

具体原理如下:

下面来实现具体代码

Drink即为主体,其中Coffee是对子类公共部分的的进一步封装:

public abstract class Drink {
    private String des;
    private float price=0.0f;

    public String getDes() {
        return des;
    }

    public void setDes(String des) {
        this.des = des;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    //计算费用的抽象方法
    public abstract float cost();
}

class Coffee extends Drink{

    @Override
    public float cost() {
        return super.getPrice();
    }
}

被装饰者实现主体

class Decaf extends Coffee{
    public Decaf(){
        setDes("无因咖啡");
        setPrice(1.0f);
    }
}

装饰器继承主体并聚合

public class Decorator extends Drink {
    //组合
    private Drink drink;
    public Decorator(Drink drink){
        this.drink=drink;
    }
    @Override
    public float cost() {
        //返回调料的价格和咖啡的价格
        return getPrice()+drink.getPrice();
    }

    @Override
    public String getDes() {
        return super.getDes()+drink.getDes();
    }
}

装饰器的一个具体实现

class Milk extends Decorator{

    public Milk(Drink drink) {
        super(drink);
        setDes("牛奶");
        setPrice(2.0f);
    }
}

客户端

public class Client {
    public static void main(String[] args) {
        Drink decaf = new Decaf();
        System.out.println(decaf.getDes());
        System.out.println(decaf.getPrice());

        //加点牛奶
        decaf=new Milk(decaf);
        System.out.println(decaf.getDes());
        System.out.println(decaf.getPrice());
    }
}

5、总结

装饰者模式与继承的目的都是扩展对象的功能,但是装饰者可以提供比继承更多的灵活性。以下情况可以考虑使用装饰者模式:

扩展类的功能或给一个类添加职责

需要动态的给一个对象添加功能,这些功能可以动态的撤销

需要增加一些由基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实

当不能采用子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类爆炸性增长;另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类

推荐阅读

设计模式七大原则
UML类图的六大关系
八种单例模式分析
由浅入深工厂模式
原型模式及深浅拷贝详解
建造者模式
适配器设计模式
桥接模式

更多精彩,关注“咋家”

相关文章

  • 如何利用装饰者模式在不改变原有对象的基础上扩展功能

    目录 什么是装饰者模式 普通示例 装饰者模式示例 类图关系 装饰者模式使用场景 装饰者模式优点 装饰者模式缺点 什...

  • 装饰者模式

    装饰者模式 装饰者模式和适配器模式对比 装饰者模式 是一种特别的适配器模式 装饰者与被装饰者都要实现同一个接口,主...

  • java IO 的知识总结

    装饰者模式 因为java的IO是基于装饰者模式设计的,所以要了解掌握IO 必须要先清楚什么事装饰者模式(装饰者模式...

  • 设计模式-装饰者模式

    装饰者模式概念: 装饰者模式又名包装(Wrapper)模式。装饰者模式以对客户端透明的方式扩展对象的功能,是继承关...

  • java - 装饰者模式

    装饰者模式 装饰者模式:动态将责任添加到对象上。如果需要扩展功能,装饰者提供了比继承更有弹性的解决方案。装饰者模式...

  • 设计模式之装饰者模式(Decorator Pattern)

    What: 装饰者模式又名包装(Wrapper)模式。装饰者模式动态地将责任附加到对象身上。若要扩展功能,装饰者提...

  • 装饰者(Decorator)模式

    装饰者(Decorator)模式装饰模式又名包装(Wrapper)模式。装饰模式是继承关系的一个替代方案。装饰模式...

  • 2、装饰者模式

    装饰者模式 一、基本概念 二、结构 三、案例1、装饰者模式案例2、JavaIO中使用装饰者模式 四、总结 一、基本...

  • PHP的设计模式-装饰者模式

    装饰者模式 装饰者模式 装饰者模式类似蛋糕,有草莓味、奶酪等种类,但是它们的核心都是蛋糕。 不断地将对象添加装饰的...

  • 设计模式 | 装饰者模式及典型应用

    前言 本文的主要内容: 介绍装饰者模式 示例 源码分析装饰者模式的典型应用Java I/O 中的装饰者模式spri...

网友评论

    本文标题:装饰者模式

    本文链接:https://www.haomeiwen.com/subject/ejbuyhtx.html