装饰器模式:
动态地给对象添加额外的责任,就好比房子进行装修一样,房架子就好比要装饰的对象,我把拿过来一顿装饰,可能是增加了很多方法,可能是修改了属性值,让这个对象更丰富起来
条件:
必须具有一个装饰对象
装饰者与被装饰者必须具有相同类型,也就是继承了相同父类,这里的继承不是继承行为,而是继承类型
完美采用了开放-关闭原则:针对扩展开放,对修改关闭
类图:
现有小需求如下:
给星巴兹咖啡更新订单系统,是的,是星巴兹不是星巴克,咖啡暂定四种,HouseBlend,DarkRoast,Decaf,Espresso,调料四种Soy(豆浆)、Mocha(摩卡)、Milk(牛奶)、Whip(奶泡);但是组合有很多种,一种咖啡可以加很多调料,随意组合,系统来显示都点了啥,总共多少钱
类图如下:
1.我们先来写咖啡的抽象类
//咖啡基类抽象类
abstract class Beverage{
String description = "Unknown Beverage";//定义了一个属性用来描述你都点了啥
public String getDescription(){
return description;
}
public abstract double cost();//此处定义抽象方法让子类去实现
}
2.然后写装饰器的抽象类
//咖啡装饰抽象类 继承自Beverage 这样他的子类(具体装饰器)就也继承了Beverage,与被装饰对象具有相同父类
abstract class CondimentDecorator extends Beverage{
public abstract String getDescription();
}
3.然后我们来写具体的咖啡
//具体饮料
class Espresso extends Beverage {
public Espresso(){//构造函数的时候添加自己的描述
description = "Espresso";
}
public double cost(){//定义啥也不加多少钱
return 2.5;
}
}
//咖啡 同上
class HouseBlend extends Beverage {
public HouseBlend(){
description = "HouseBlend";
}
public double cost(){
return 3.3;
}
}
//DarkRoast
class DarkRoast extends Beverage{
public DarkRoast(){
description = "DarkRoast";
}
public double cost(){
return 6.6;
}
}
//Decaf
class Decaf extends Beverage{
public Decaf(){
description = "Decaf";
}
public double cost(){
return 7.7;
}
}
4.重点来了,具体装饰器在这实现,也就是每种调料是怎么装饰这些咖啡的
//摩卡装饰器
class Mocha extends CondimentDecorator{//继承抽象装饰器也就继承了Beverage
Beverage beverage;//声明一个父类对象
public Mocha(Beverage beverage){
this.beverage = beverage;//构造函数时把传过来的对象赋给当前beverage对象,
//传过来的参数也就是要装饰的对象,是具体的咖啡对象向上转型为父类型Beverage类型的对象,
//这也就说明了为什么装饰者要与被装饰者具有相同超类,不同的话你这对象赋值赋不过去啊
description = beverage.getDescription() +"、Mocha";//给继承过来的父类属性值装饰一下,记录我点了摩卡
}
public String getDescription(){
return beverage.description +"、Mocha";
}
public double cost(){
return beverage.cost()+3.33;//价钱计算在这了,拿到了要装饰的对象beverage,也就拿到了它现在多钱,再加上我摩卡的前就是总共的钱啦
}
}
//豆浆装饰器
class Soy extends CondimentDecorator{
Beverage beravage;
public Soy(Beverage bevarage){
this.beravage = bevarage;
description = beravage.getDescription() +"、Soy";
}
public String getDescription(){
return beravage.description + "、Soy";
}
public double cost(){
return beravage.cost()+4.44;
}
}
//奶泡装饰器
class Whip extends CondimentDecorator{
Beverage beverage;
public Whip(Beverage beverage){//相同类型、也就是相同超类,是为了保证这块参数放的进去
this.beverage = beverage;
description = beverage.getDescription() +"、Whip";
}
public String getDescription(){
return beverage.getDescription() +"、Whip";
}
public double cost(){
return beverage.cost()+5.54;
}
}
//牛奶装饰器
class Milk extends CondimentDecorator{
Beverage beverage ;
public Milk(Beverage beverage ){
this.beverage = beverage;
description = beverage.getDescription() +"、Milk";
}
public String getDescription(){
return beverage.getDescription()+"、Milk";
}
public double cost(){
return beverage.cost()+9.9;
}
}
5.现在就可以写个简单测试类啦
public class DecoratorPattern {
public static void main(String args[]){
Beverage beverage= new Espresso();
beverage = new Whip(beverage);//装饰器构造时就是决定往哪个对象添加装饰时
beverage = new Soy(beverage);
System.out.println("您好:你点了"+beverage.getDescription()+" 总共$"+beverage.cost());
Beverage beverage2 = new HouseBlend();
beverage2 = new Soy(beverage2);
beverage2 = new Soy(beverage2);
beverage2 = new Mocha(beverage2);
System.out.println("您好:你点了"+beverage2.getDescription()+" 总共$"+beverage2.cost());
Beverage b = new Mocha(new Mocha(new Whip(new DarkRoast())));
System.out.println("您好:你点了"+b.getDescription()+" 总共$"+b.cost());
// Beverage c = new Decaf();
// c = new Milk(c);
// c = new Milk(c);
// c = new Milk(c);
Beverage c = new Milk(new Milk(new Milk(new Decaf())));
System.out.println("您好:你点了"+c.getDescription()+" 总共$"+c.cost());
}
}
结果:
您好:你点了Espresso、Whip、Soy 总共$12.48
您好:你点了HouseBlend、Soy、Soy、Mocha 总共$15.51
您好:你点了DarkRoast、Whip、Mocha、Mocha 总共$18.8
您好:你点了Decaf、Milk、Milk、Milk 总共$37.4
装饰者模式:java I/O