当我们来到KFC开始点餐的时候,一开始还不是特别有胃口,所以只点了一份汉堡套餐,有一份汉堡和饮料,但后来又点了一份薯条,最后干脆再点一份炸鸡腿,那么如何来计算我们花了多少钱呢?
在这个场景下,装饰者模式会起到很好的效果。
装饰者模式
定义:动态的将责任附加到对象身上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
即通过将装饰者和组件组合的方式,来加入新的行为。行为来自装饰者和组件的组合,或者是装饰者和其他装饰者之间的组合关系。
UML类图
- 组件:具体组件和装饰者需要实现的超类
- 具体组件:我们将要动态的加上新行为的对象(被包在最里面)
- 装饰者:每个装饰者都包装着一个组件
- 具体装饰者:装饰者加上新的方法,即新行为来扩展。
例子
就以一开始举的KFC为例子
KFCFood接口
package decorator;
public abstract class KFCFood {
private String des = "我是KFC里所有食物(包括饮料)的父类";
public String getDes() {
return des;
}
public abstract double cost();
}
一汉堡一饮料套餐
package decorator;
/**
* 套餐
*/
public class Setmeal extends KFCFood{
private Hamberger hamberger;
private Cola cola;
public Setmeal() {
des = "a kind of cheap set meal";
}
@Override
public double cost() {
return 15;
}
}
装饰者接口
package decorator;
/**
* 小食接口
*/
public abstract class Refreshments extends KFCFood{
public abstract String getDes();
}
具体实现类
package decorator;
/**
* 具体装饰者,包含着被装饰的对象
* 被装饰对象可以是具体实现类,也可以是另一个装饰者
*/
public class FrenchFries extends Refreshments {
KFCFood kfcFood;
public FrenchFries(KFCFood kfcFood) {
this.kfcFood = kfcFood;
}
@Override
public String getDes() {
return kfcFood.getDes() + ",French fries";
}
@Override
public double cost() {
return 5 + kfcFood.cost();
}
}
package decorator;
/**
* 具体装饰者,包含着被装饰的对象
* 被装饰对象可以是具体实现类,也可以是另一个装饰者
*/
public class Drumstick extends Refreshments{
KFCFood kfcFood;
public Drumstick(KFCFood kfcFood) {
this.kfcFood = kfcFood;
}
@Override
public String getDes() {
return kfcFood.getDes() + ",Drumstick";
}
@Override
public double cost() {
return 10 + kfcFood.cost();
}
}
测试
package test.decorator;
import decorator.Drumstick;
import decorator.FrenchFries;
import decorator.KFCFood;
import decorator.Setmeal;
public class test {
public static void main(String args[]){
KFCFood setmeal = new Setmeal();
KFCFood frenchfries = new FrenchFries(setmeal);
KFCFood drumstcik = new Drumstick(frenchfries);
System.out.println(drumstcik.cost());
System.out.println(drumstcik.getDes());
}
}
小结
装饰者模式符合了组合原则外,还符合这么一条原则:
对扩展开放,对修改关闭
- 装饰者模式可以在被装饰者的行为前或者后面添加上自己的行为,甚至将被装饰者的行为整个替换掉,而达到特定的目的。
- 装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。
- 装饰者会导致设计中出现许多小对象,如果过度使用,将使程序变得很复杂。
源码在这里:我的github地址
其他设计模式:设计模式学习笔记