装饰器模式
之前我们说过软件设计模式的一个典型特征就是 使用面向接口而不是继承的编程 但是有种情况是特殊的 例如我们的装饰器模式 之所以需要装饰器模式 是因为需要运行时对某个类进行修饰 由于我们设计模式的准则是开放-关闭原则 即扩展性要较高 并且关闭修改 即我们肯定是不能够修改基类的 还要能增加新的特性 这就是为什么代码中不论是Beverage(饮料)还是Condiment(配料) 都需要一个共同的基类 因为要想不修改底层代码 还要增加新的特性 那么这不就是类继承的用法吗 虽然设计模式中我们不推荐使用继承 但要因事物而变 不能固定思维 通过使用继承我们可以将配料和饮料都定为同一类型 这样调用父类的方法就没有问题 最后通过类似于递归的方式 我们可以得到最终的结果 并且可以很好的保持运行时的扩展 可以可以看到我们的main方法中可以叠加不同种类的配料 这就达到了扩展 并且如果我们想增加一个配方 那么我们只需要再继承一个配料基类 或者 饮料基类 而不用改变基类的任何代码 然后最后在main方法中加以包装即可
/**
* @Title: StarBuzzTest.java
* @Package
* @Description: TODO(用一句话描述该文件做什么)
* @author Lustre
* @date 2019年12月8日
* @version V1.0
*/
/**
* @author Nigel
* @version 创建文件时间:2019年12月8日 下午7:36:30
*/
/**
* @ClassName: StarBuzzTest
* @Description: TODO(这里用一句话描述这个类的作用)
* @author Nigel
* @date 2019年12月8日
*
*/
/**
*
* @ClassName: Beverage
* @Description: 定义一个抽象基类 之所以这里用基类而不是接口 是因为调料必须和饮料是同一个基类! 不然装饰器模式就是空谈
* @author Nigel
* @date 2019年12月8日
*
*/
abstract class Beverage{
protected String description;
public String getDescription() {
return description;
}
/**
*
* @Title: cost
* @Description: 这个cost方法是需要被所有继承的实体类所重写的 因为每个实体必定有一个价钱 并且价钱也是不一致的
* @return
* @return Double
* @throws
*/
abstract Double cost();
}
/**
*
* @ClassName: CondimentDecorator
* @Description: 调料必须继承饮料类 这样才能发挥装饰类的特点!
* @author Nigel
* @date 2019年12月8日
*
*/
abstract class CondimentDecorator extends Beverage{
protected Beverage superClassBeverage;
/**
*
* <p>Title: getDescription</p>
* <p>Description: 每个调料对应的修饰自然也是不一样的
* @return
* @see Beverage#getDescription()
*/
public abstract String getDescription();
}
/**
*
* @ClassName: Espresso
* @Description: 此时为实体类 即实体饮料
* @author Nigel
* @date 2019年12月8日
*
*/
class Espresso extends Beverage {
public Espresso() {
// TODO Auto-generated constructor stub
description = "Espresso";
}
@Override
Double cost() {
// TODO Auto-generated method stub
return 1.99;
}
}
class HouseBlend extends Beverage {
/**
* 创建一个新的实例 HouseBlend.
*
*/
public HouseBlend() {
// TODO Auto-generated constructor stub
description = "HouseBlend";
}
@Override
Double cost() {
// TODO Auto-generated method stub
return .89;
}
}
class DarkRoast extends Beverage {
/**
* 创建一个新的实例 DarkRoast.
*
*/
public DarkRoast() {
// TODO Auto-generated constructor stub
description = "DarkRoast";
}
@Override
Double cost() {
// TODO Auto-generated method stub
return .99;
}
}
class Decaf extends Beverage {
/**
* 创建一个新的实例 Decaf.
*
*/
public Decaf() {
// TODO Auto-generated constructor stub
description = "Decaf";
}
@Override
Double cost() {
// TODO Auto-generated method stub
return 1.05;
}
}
//接下来让调料进行实例化 其基类也是Beverage
class Mocha extends CondimentDecorator {
/**
* 创建一个新的实例 Mocha. 需要提供一个参数来附加到对应的饮料实体上
*
*/
public Mocha(Beverage beverage) {
// TODO Auto-generated constructor stub
superClassBeverage = beverage;
}
/**
* <p>Title: getDescription</p>
* <p>Description:之所以要重写getDescription 是因为对于调料而言 我们是要叠加上去的 所以还需要返回上级的描述!
* @return
* @see CondimentDecorator#getDescription()
*/
@Override
public String getDescription() {
// TODO Auto-generated method stub
return superClassBeverage.getDescription() + "Mocha";
}
/**
* <p>Title: cost</p>
* <p>Description: </p>
* @return
* @see Beverage#cost()
*/
@Override
Double cost() {
// TODO Auto-generated method stub
return superClassBeverage.cost() + .20;
}
}
class Milk extends CondimentDecorator {
/**
* 创建一个新的实例 Milk.
*
*/
public Milk(Beverage beverage) {
// TODO Auto-generated constructor stub
superClassBeverage = beverage;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return superClassBeverage.description + "Milk";
}
@Override
Double cost() {
// TODO Auto-generated method stub
return superClassBeverage.cost() + .10;
}
}
class SoyaBean extends CondimentDecorator {
/**
* 创建一个新的实例 SoyaBean.
*
*/
public SoyaBean(Beverage beverage) {
// TODO Auto-generated constructor stub
superClassBeverage = beverage;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return superClassBeverage + "SoyaBean";
}
@Override
Double cost() {
// TODO Auto-generated method stub
return superClassBeverage.cost() + .15;
}
}
class Whip extends CondimentDecorator {
/**
* 创建一个新的实例 Whip.
*
*/
public Whip(Beverage beverage) {
// TODO Auto-generated constructor stub
superClassBeverage = beverage;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return superClassBeverage.getDescription() + "Whip";
}
/**
*
* <p>Title: cost</p>
* <p>Description: 以一种递归的方式来计算cost价格
* @return
* @see Beverage#cost()
*/
@Override
Double cost() {
// TODO Auto-generated method stub
return superClassBeverage.cost() + .10;
}
}
public class StarBuzzTest {
/**
* @Title: main
* @Description: TODO
* @param args
* @return void
* @throws
*/
public static void main(String[] args) {
//进行测试
System.out.print("不加配料的情况下:");
Beverage decafBeverage = new Decaf();//实例化一个decaf低咖啡因
System.out.println(decafBeverage.getDescription());//打印一下description
System.out.print("价钱:");
System.out.println(decafBeverage.cost());
//加上Milk后的描述和价钱
System.out.print("加Milk后的情况:");
CondimentDecorator decafWithMilk = new Milk(decafBeverage);
System.out.println( decafWithMilk.getDescription() );
System.out.print("价钱:");
System.out.printf("%.2f\n", decafWithMilk.cost());
//加Mocha后的情况
CondimentDecorator decafWithMilkAndMocha = new Mocha(decafWithMilk);
System.out.printf("再加上Mocha后的情形:");
System.out.println(decafWithMilkAndMocha.