一、介绍
装饰器模式:动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰器模式也体现了开闭原则(ocp)
二、星巴克咖啡例子
类结构
Drink
package com.swust.pattern.结构型.装饰器模式;
/**
* @Date Created in 2022/9/22 16:49
* @Description 抽象类 装饰者和被装饰者都继承自该类
*/
public abstract class Drink {
private String des; // 描述
private float price; // 价格
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
// 计算费用的抽象方法
public abstract float cost();
}
Coffee:被装饰者
package com.swust.pattern.结构型.装饰器模式;
/**
* @Date Created in 2022/9/22 16:50
* @Description 咖啡
*/
public class Coffee extends Drink{
@Override
public float cost() {
return super.getPrice();
}
}
class EspressoCoffee extends Coffee{
public EspressoCoffee() {
setDes("意大利咖啡");
setPrice(6);
}
}
public class LongBlack extends Coffee{
public LongBlack() {
setDes("美式咖啡");
setPrice(10);
}
}
Decorator:装饰者
package com.swust.pattern.结构型.装饰器模式;
/**
* @Date Created in 2022/9/22 16:54
* @Description 装饰者 - 调料
*/
public class Decorator extends Drink{
private Drink drink; // 被装饰者
public Decorator(Drink drink) {
this.drink = drink;
}
@Override
public float cost() {
return getPrice() + drink.cost();
}
@Override
public String getDes() {
return super.getDes() + ":" +super.getPrice() + "->" + drink.getDes();
}
}
class Milk extends Decorator{
public Milk(Drink drink) {
super(drink);
setDes("牛奶");
setPrice(1.5f);
}
}
class Chocolate extends Decorator{
public Chocolate(Drink drink) {
super(drink);
setDes("巧克力");
setPrice(2);
}
}
Client
package com.swust.pattern.结构型.装饰器模式;
import java.io.*;
/**
* @Date Created in 2022/9/22 16:59
* @Description
*/
public class Client {
public static void main(String[] args) throws FileNotFoundException {
// 订单:点2份巧克力和一份牛奶的美式咖啡
// 点美式咖啡
Drink drink = new LongBlack();
System.out.println(drink.getDes());
System.out.println(drink.cost());
// 加一份牛奶
drink = new Milk(drink);
System.out.println(drink.getDes());
System.out.println(drink.cost());
// 加一份巧克力
drink = new Chocolate(drink);
System.out.println(drink.getDes());
System.out.println(drink.cost());
// 加一份巧克力
drink = new Chocolate(drink);
System.out.println(drink.getDes());
System.out.println(drink.cost());
}
}
执行结果
美式咖啡
10.0
牛奶:1.5->美式咖啡
11.5
巧克力:2.0->牛奶:1.5->美式咖啡
13.5
巧克力:2.0->巧克力:2.0->牛奶:1.5->美式咖啡
15.5
三、JDK源码分析
/**
* JDK源码
* FileInputStream : 被装饰者
* FilterInputStream : 装饰者
* protected volatile InputStream in;
* DataInputStream : 继承自FilterInputStream
*/
DataInputStream stream =
new DataInputStream(new FileInputStream(""));
四、注意事项
装饰器设计模式有多个装饰类的时候,可以一层一层包下去,每一层的功能都是相对独立的,甚至包装的顺序都是可以变化的,我们只需要保证的是最里层的是我们的被装饰类