装饰者模式

作者: 咋家 | 来源:发表于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类图的六大关系
    八种单例模式分析
    由浅入深工厂模式
    原型模式及深浅拷贝详解
    建造者模式
    适配器设计模式
    桥接模式

    更多精彩,关注“咋家”

    相关文章

      网友评论

        本文标题:装饰者模式

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