装饰者模式:
动态地将责任附加到对象上。想要扩展功能,装饰者提供有别于继承的另一种选择。
涉及设计模式:
1.多用组合,少用继承
2.类应该对扩展开放,对修改关闭
问题简单描述:
星巴克有很多饮料。一开始的设计是有一个饮料超类(包含getDescription()、cost()方法),所有的饮料都继承这个饮料超类,但是饮料的种类非常的多,使得类的种类非常非常多,简直是“类爆炸”。后来又想到另外一种饮料基类,增加了包含了各种调料的布尔值,还有获取是否含有各种调料的方法,设置各种调料的方法,cost方法根据调料的布尔值判断是否加调料的价钱得出饮料的价格。只需要几种基本的饮料继承饮料基类,通过设置不同的调料就可以得到大部分的饮料,从而解决了类爆炸的问题。但是仍然存在很多问题,调料的价格调整或者新调料出现就需要改变基类的代码,也有一些饮料无法通过这样的方法表示(如双倍摩卡咖啡,因为一个调料在基类只有一个布尔值,虽然通过改变基类可以实现,但是基类变得复杂)。
解决思路:
用调料来“装饰”(包装可能更好理解)基本的饮料,每次计算价格的时候调用最外圈的cost(),外圈的cost()委托里层cost()来计算直到递归到最里层的基本饮料,再一层层的返回到最外层,没经过一层都会加上那一层的价格。
UML图:
实现代码:
Beverage基类:package decorator;
/**
* 饮料超类(装饰者基类)
* @author terry
*
*/
public abstract class Beverage {
String description="Unkonwn Beverage";
public String getDescription() {
return description;
}
public abstract double cost();
}
基本饮料
package decorator;
/**
* 低咖啡因咖啡(基本饮料)
* @author terry
*
*/
public class Decaf extends Beverage{
public Decaf(){
description="Decaf";
}
@Override
public double cost() {
return 0.9;
}
}
package decorator;
/**
* 浓缩咖啡(基本饮料)
*
*/
public class Espresso extends Beverage {
public Espresso(){
description="Espresso";
}
@Override
public double cost() {
return 1.99;
}
}
调料超类(也需要继承饮料超类)
package decorator;
/**
* 调料装饰者超类(也需要继承饮料超类,达到跟基本饮料属于同一个类型)
* @author terry
*
*/
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
调料实现类
package decorator;
/**
* 摩卡(调料实现类)
* @author terry
*
*/
public class Mocha extends CondimentDecorator{
//调料实现类需要有饮料属性,需要有被装饰者
Beverage beverage;
public Mocha(Beverage beverage){
this.beverage=beverage;
}
@Override
public String getDescription() {
return beverage.getDescription()+",Mocha";
}
@Override
public double cost() {
//计算价格先把调用委托给装饰对象,计算出价格后再加上摩卡本身的价格
return beverage.cost()+0.3;
}
}
package decorator;
/**
* 奶泡(调料实现类)
* @author terry
*
*/
public class Whip extends CondimentDecorator {
Beverage beverage;
public Whip(Beverage beverage){
this.beverage=beverage;
}
@Override
public String getDescription() {
return beverage.getDescription()+",Whip";
}
@Override
public double cost() {
return beverage.cost()+0.2;
}
}
测试类
package decorator;
public class Test {
public static void main(String[] args){
//双摩卡奶泡浓缩咖啡
Beverage beverage=new Espresso();
beverage=new Mocha(beverage);
beverage=new Whip(beverage);
beverage=new Mocha(beverage);
/*
* 可能这样写更有包裹的感觉
* beverage=new Mocha(new Whip(new Mocha(beverage)));
*/
System.out.println(beverage.getDescription()+" cost:"+beverage.cost());
}
}
输出结果
欢迎批评指正^ ^