架构与设计模式

装饰者模式

2020-03-27  本文已影响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类图的六大关系
八种单例模式分析
由浅入深工厂模式
原型模式及深浅拷贝详解
建造者模式
适配器设计模式
桥接模式

更多精彩,关注“咋家”

上一篇下一篇

猜你喜欢

热点阅读