什么是“装饰者模式”
装饰者模式:装饰者模式可以动态地将责任附加到对象上。若要拓展功能,装饰者模式提供了比继承更有弹性的替代方案。
在面向对象设计过程中,我们可以遵循一个原则:开闭原则(对拓展开放,对修改关闭)
而装饰者模式就很好的遵循了这个原则,在对类进行拓展的时候可以不修改代码,以便搭配新的行为。这种设计更具有弹性,可以更好地应对改变和接收新的需求。
为什么要用“装饰者模式”
我们举个简单的例子:
我们需要设计一个咖啡订单系统,我们很容易就可以想到,新建一个抽象类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
欢迎联系我共同交流