每天一个设计模式之装饰者模式

什么是“装饰者模式”

装饰者模式:装饰者模式可以动态地将责任附加到对象上。若要拓展功能,装饰者模式提供了比继承更有弹性的替代方案。

在面向对象设计过程中,我们可以遵循一个原则:开闭原则(对拓展开放,对修改关闭)

而装饰者模式就很好的遵循了这个原则,在对类进行拓展的时候可以不修改代码,以便搭配新的行为。这种设计更具有弹性,可以更好地应对改变和接收新的需求。

为什么要用“装饰者模式”

我们举个简单的例子:

我们需要设计一个咖啡订单系统,我们很容易就可以想到,新建一个抽象类Beverage

/**
 * 咖啡的接口
 * */
public abstract class Beverage {
    String description = "这只是个咖啡,我也不知道是什么咖啡";

    public String getDescription() {
        return description;
    }
    public abstract double cost();
}

然后通过子类继承Beverage并实现抽象方法cost(),得到不同的价格。

那么问题来了: 如果我要在咖啡中添加各种调料,例如:蒸奶、豆浆、摩卡、奶泡等等。 添加不同的调料收取的价格不同,我们该怎么办?有些人会想到,根据不同的搭配组合实现不同的类,那么这个想法会发生什么事情呢?没错。。。类爆炸!

如何使用装饰者模式

那么这个时候,装饰者模式就可以上场了:

我们首先来看看装饰者模式的类图

装饰者模式类图

组成

  • Component 抽象构件 :一个抽象类或者一个接口
  • ComcreateComponent 具体构件:抽象类或者接口的实现,我们要装饰的就是它(咖啡)
  • Decorator 装饰角色: 一个抽象类或者一个接口,里面必然有一个指向Component 抽象构件的属性
  • 具体装饰角色:装饰用的具体角色,实现或继承了Decorator 装饰角色

实现

了解了具体的组成角色,那么我们就可以实现一下了

首先,根据类图我们需要准备一个Component 抽象构件,其实我们在文章开始就已经准备好了:

/**
 * 咖啡的接口
 * */
public abstract class Beverage {
    String description = "这只是个咖啡,我也不知道是什么咖啡";

    public String getDescription() {
        return description;
    }
    public abstract double cost();
}

接下来,我们准备一个ComcreateComponent 具体构件,也就是需要被我们装饰的对象(这里是咖啡)

/**
 * 通过继承Beverage抽象类,可以根据不同的咖啡定义不同的价格
 * */
public class Espresso extends Beverage {
    public Espresso() {
        super.description = "浓缩咖啡";
    }

    @Override
    public double cost() {
        return 18.8;
    }
}

然后,我们准备一个Decorator 装饰角色

 **
 * Decorator 装饰角色, 继承Beverage就可以对它的价格进行修改
 * */
public abstract class CondimentDecorator extends Beverage {
    public abstract String getDescription();

}

最后,我们实现一个这个Decorator 装饰角色抽象类,使它变成具体的装饰角色

public class Mocha extends CondimentDecorator {
    Beverage beverage;

    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }

    //添加上摩卡
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", 摩卡";
    }
    //将价格改变为添加摩卡后的价格
    @Override
    public double cost() {
        return beverage.cost() + 2.0;
    }
}

/*=======================================================*/

public class Whip extends CondimentDecorator {
    Beverage beverage;

    public Whip(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + ", 奶泡";
    }

    @Override
    public double cost() {
        return beverage.cost() + 1.0;
    }
}

//其实我们可以多实现几种调料,这样可能会吸引更多顾客呢

完成之后,我们测试一下被我们装饰后的咖啡长什么样:

public class StarbuzzCoffee {
    public static void main(String[] args){

        Beverage beverage = new Espresso();
        beverage = new Mocha(beverage);
        beverage = new Whip(beverage);
        System.out.println(beverage.getDescription() + " ¥" + beverage.cost());
    }

输出结果:

浓缩咖啡, 摩卡, 奶泡 ¥21.8

从输出结果看,我们确实根据调料改变了浓缩咖啡的价格,所以这就是装饰者模式的好处。

那么,总结来了

优点:

  • 装饰类和被装饰类可以独立发展,不会互相耦合。
  • 装饰者模式是继承的一个替代方案。我们不管装饰多少层,最终返回的还是该对象。
  • 装饰者模式可以动态拓展一个实现类的功能。

缺点:

  • 装饰层数过多的话,会导致调试困难,系统复杂度提高。

应用场景:

  • 需要动态地拓展某个类的功能或者添加一个附加功能。
  • 需要为一批兄弟类添加功能或者改装,首选装饰者模式。

感谢阅读本博客。

欢迎关注我的博客:https://li-weijian.github.io/

欢迎关注我的CSDN:https://blog.csdn.net/qq352642663

需要联系请加QQ:352642663

欢迎联系我共同交流

猜你喜欢

转载自blog.csdn.net/qq352642663/article/details/80621992