开头说几句
博主的博客地址:https://www.jeffcc.top/ 推荐入门学习设计模式java版本的数据Head First 《设计模式》
专业定义:装饰者模式可以动态得讲责任附加到对象上,若要拓展功能,装饰者模式提供了比继承更加有弹性的替代方案。 个人见解:装饰者模式重点在于装饰者,我们可以不修改对象的前提下,对对象进行功能的拓展,不通过继承来实现行为的拓展,而是通过组合和委托来实现!以免出现继承泛滥以及一些其他的业务修改对象代码而带来的bug。
一家咖啡店需要设计一个订单系统,其中的订单价格和订单描述这一方面需要设计出一种优秀的模式, 每款饮料都继承自Beverage,饮料配有配料以及本身的价格以及杯的大小的价格不同而有不同的定价。
package shop;
/**
* 咖啡店的饮料抽象类 所有饮料都要继承自它
* 提供两个方法
*/
public abstract class Beverage {
public String description = "Unkonw Beverage";
public String getDescription() {
return description;
}
/**
* 计算价格的抽象方法
* @return
*/
public abstract double cost();
}
package condiment;
import shop.Beverage;
/**
*调料抽象类 所有调料的装饰者都要继承
* 注意这里一定要继承Beverage!!!否则无法进行嵌套的装饰
*/
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
package shop.impl;
import shop.Beverage;
/**
* 饮料1 Espresso
*/
public class Espresso extends Beverage {
public Espresso() {
description = "Espresso";
}
/**
* 装饰者装饰价格1 饮料本身的价格
* @return
*/
@Override
public double cost() {
return 1.99;
}
}
package shop.impl;
import shop.Beverage;
/**
* 饮料2 HouseBlend
*/
public class HouseBlend extends Beverage {
public HouseBlend() {
description = "HouseBlend";
}
/**
* 装饰者装饰价格2 HouseBlend饮料本身的价格
* @return
*/
@Override
public double cost() {
return 0.80;
}
}
package condiment.impl;
import condiment.CondimentDecorator;
import shop.Beverage;
/**
* 调料1 Mocha
*/
public class Mocha extends CondimentDecorator {
// 定义要搭配的饮料类型
public Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
/**
* 增加饮料的描述 加上配料
* @return
*/
@Override
public String getDescription() {
return beverage.getDescription()+"Mocha";
}
/**
*装饰者装饰调料价格 在基础上加0.2
* @return
*/
public double cost(){
return beverage.cost() + 0.20;
}
}
package condiment.impl;
import condiment.CondimentDecorator;
import shop.Beverage;
/**
* 调料2 Whip
*/
public class Whip extends CondimentDecorator {
// 定义要搭配的饮料类型
public Beverage beverage;
public Whip(Beverage beverage) {
this.beverage = beverage;
}
/**
* 增加饮料的描述 加上配料
* @return
*/
@Override
public String getDescription() {
return beverage.getDescription()+"Whip";
}
/**
*装饰者装饰调料价格 在基础上加0.2
* @return
*/
public double cost(){
return beverage.cost() + 0.50;
}
}
咖啡店测试
package test;
import condiment.impl.Mocha;
import condiment.impl.Whip;
import shop.Beverage;
import shop.impl.Espresso;
import shop.impl.HouseBlend;
/**
* 咖啡店的测试开业
*/
public class StarbuzzCoffee {
public static void main(String[] args) {
// 定一杯 饮料 Espresso 不加任何调料
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription()+" $"+beverage.cost());
// 再定一杯 Espresso
Beverage beverage2 = new Espresso();
// 开始装饰 加上一个mocha配料 反复定义
beverage2 = new Mocha(beverage2);
// 加上一个whip配料
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription()+" $"+beverage2.cost());
// 再定一杯 HouseBlend
Beverage beverage3 = new HouseBlend();
// 开始装饰 加上一个mocha配料 反复定义
beverage3 = new Mocha(beverage3);
// 加上一个whip配料
beverage3 = new Whip(beverage3);
System.out.println(beverage3.getDescription()+" $"+beverage3.cost());
}
}
关键在于:装饰者CondimentDecorator一定要注意继承被装饰者的抽象类Beverage,这样才能够实现不断得进行装饰。
Java世界中有太多的装饰者模式的设计了,java.io包中就有许多这样的装饰者; FileInputStream就是一个被装饰的组件,提供最基本的io功能; 而BufferedInputStream是一个具体的装饰者,它加入两种行为:利用缓冲输入来改善性能,用一个readLine方法来增强了接口; LineNumberInputStream也是一个具体的装饰者,它加上了计算行数的功能。
挖掘源码我们也可以发现: 这些io的装饰者都继承自同一个超类,这样使得io的装饰起来便捷了很多
利用装饰者模式造成的设计中有大量的小类,数量十分多,可能会造成使用此API的程序员的困扰。但是我们理解了装饰者模式的工作原理了,就能够在以后的工作中容易的辨识出类是如何组织的,也就能高效的进行开发了!