装饰者模式
场景
小张的朋友小李在星巴滋(是的,和星巴克一样是卖饮料的,咖啡,茶),准备更新他们订单系统,小李找小张帮忙设计一下,订单系统里有:咖啡,茶,还有可以加的佐料:牛奶,糖,摩卡,柠檬…
并且咖啡可以加佐料,并且可以加多份佐料。
小张的需求分析
如果直接设计,那么只要穷尽小李他们的咖啡,茶,和佐料的混合,建立对象就可以了,但是穷尽下来,类已经很多了,如果再有新的饮料和佐料加入,那么类的数量太多会造类爆炸,这样做是不符合设计原则的,并且也没有面向抽象编程。
小张想了一下,应该用下设计模式吧,但是不知道用哪种设计模式。
小张: 王哥,我这个有个问题,需要请教下你 …(复述上述需求)…
老王:这个可以用装饰者模式,这个模式你应该在学java的时候就遇到了,java的io就是使用装饰者模式。
小张: 哦,怪不得当时用io的时候很难理解,那我去了解下装饰者模式。
小张的装饰者实现
/**
*
*饮料类接口
* @Author xuelongjiang
*/
public interface Beverage {
public int cost();
}
/**
*
* 咖啡
* @Author xuelongjiang
*/
public class Coffee implements Beverage {
public int cost() {
return 5;
}
}
/**
* 茶
* @Author xuelongjiang
*/
public class Tea implements Beverage {
public int cost() {
return 4;
}
}
/**
* 佐料
* @Author xuelongjiang
*/
abstract class Condiment implements Beverage{
}
/**
* 牛奶
* @Author xuelongjiang
*/
public class Milk extends Condiment {
private Beverage beverage;
public Milk(Beverage beverage) {
this.beverage = beverage;
}
public int cost() {
return 2+ beverage.cost();
}
}
/**
* 摩卡
* @Author xuelongjiang
*/
public class Mocha extends Condiment {
private Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
public int cost() {
return 3+beverage.cost();
}
}
/**
* 装饰者模式测试
* @Author xuelongjiang
*/
public class DecoratorTest {
private static Logger logger = LoggerFactory.getLogger(DecoratorTest.class);
public static void main(String[] args) {
logger.info("纯咖啡");
Beverage coffee = new Coffee();
logger.info(""+coffee.cost());
logger.info("咖啡加牛奶");
coffee = new Milk(coffee);
logger.info(""+coffee.cost());
logger.info("咖啡加牛奶加摩卡");
coffee = new Mocha(coffee);
logger.info(""+coffee.cost());
}
}
测试输出:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zUAivEqN-1596105624732)(https://github.com/longjiangxue/blogImage/blob/master/decorator/%E8%A3%85%E9%A5%B0%E8%80%85%E6%B5%8B%E8%AF%95%E8%BE%93%E5%87%BA.png?raw=true)]
类图
我们佐料类作为装饰者,用来装饰咖啡和茶,这样我们可以在咖啡中无限的增加佐料,我只需要两个对象就可以。
装饰者模式
装饰者模式动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更加有弹性的替代方案。
增加类的行为
要点
- 继承属于扩展形式之一,但不见得是达到弹性设计的最佳方案
- 在我们的设计中,应该允许行为可以为扩展,而无需修改现有的代码
- 组合和委托可用于在运动时动态地加上新的行为
- 除了继承,装饰者模式也可以让我们扩展行为
- 装饰者会导致设计中出现很多小对象,如果过度使用,会让程序变得复杂(这也是java io api难以使用的原因)