本文专栏:设计模式篇-装饰者模式
本文简述:装饰者模式的详解以及jdk中的应用
上一篇文章: 设计模式篇(Java):桥接模式
有任何问题,都可以私聊我,文章最后有vx名片。感谢支持!
知道的越多,不知道的越多!!!不能停下学习的脚步
引出装饰者模式的示例
咖啡吧订单问题:
那么使用传统方法(最笨的)
问题分析
优化方法一
前面分析到方案1因为咖啡单品+调料 组合会造成类的倍增,因此可以做改进,将调料内置到Drink类,这样就不会造成类数量过多。从而提高项目的维护性。
问题分析:
优化方法二:装饰者模式
装饰者模式定义
装饰者模式原理
Component 主体:比如类似前面的Drink
ConcreteComponent和Decorator
在如图的Component与ConcreteComponent之间,如果 ConcreteComponent类很多,还可以设计一个缓冲层,将共有的部分提取出来, 抽象层一个类
使用装饰者模式设计的方案
说明:
代码示例
Drink类
/**
* Drink类就是抽象的被装饰者,给具体的装饰者和被修饰者继承
* @author cVzhanshi
* @create 2023-09-05 15:16
*/
@Data
public abstract class Drink {
// 描述
private String des;
// 价格
private float price = 0.0f;
// 计算费用的抽象方法
// 子类来实现
public abstract float cost();
}
Coffee类(缓冲层)
/**
* 缓冲层
* @author cVzhanshi
* @create 2023-09-05 15:32
*/
public class Coffee extends Drink {
@Override
public float cost() {
return super.getPrice();
}
}
具体的被装饰者——各种咖啡
/**
* @author cVzhanshi
* @create 2023-09-05 15:33
*/
public class BCoffee extends Coffee {
public BCoffee() {
setDes("BCoffee");
setPrice(3.0f);
}
}
/**
* @author cVzhanshi
* @create 2023-09-05 15:33
*/
public class ACoffee extends Coffee {
public ACoffee() {
setDes("ACoffee");
setPrice(5.0f);
}
}
Decorator装饰类
/**
* Decorator 是一个装饰类,含有一个被装饰的对象(Drink obj)
* @author cVzhanshi
* @create 2023-09-05 15:59
*/
public class Decorator extends Drink{
private Drink coffee;
public Decorator(Drink coffee) {
this.coffee = coffee;
}
@Override
public float cost() {
// 调料的价格 + coffee的总价格
return coffee.cost() + super.getPrice();
}
@Override
public String getDes() {
return super.getDes() + " || " + coffee.getDes();
}
}
具体的装饰类
/**
* @author cVzhanshi
* @create 2023-09-05 16:09
*/
public class Milk extends Decorator {
public Milk(Drink coffee) {
super(coffee);
setPrice(1.0f);
setDes(" 牛奶 ");
}
}
/**
* @author cVzhanshi
* @create 2023-09-05 16:10
*/
public class Soy extends Decorator {
public Soy(Drink coffee) {
super(coffee);
setDes(" 糖 ");
setPrice(9.0f);
}
}
制作咖啡(允许效果)
/**
* @author cVzhanshi
* @create 2023-09-05 16:11
*/
public class CoffeeBar {
public static void main(String[] args) {
// 装饰者模式下订一份A咖啡 + 一份糖 + 两份牛奶
// 1、点一份a咖啡
Drink aCoffee = new ACoffee();
System.out.println("费用1 = " + aCoffee.cost());
System.out.println("描述 = " + aCoffee.getDes());
// 2、a咖啡加入一份糖
aCoffee = new Soy(aCoffee);
System.out.println("aCoffee 加入一份糖 费用 = " + aCoffee.cost());
System.out.println("aCoffee 加入一份糖 描述 = " + aCoffee.getDes());
//2、再加入两份份牛奶
aCoffee = new Milk(aCoffee);
System.out.println("aCoffee 加入一份糖 一份牛奶 费用 = " + aCoffee.cost());
System.out.println("aCoffee 加入一份糖 一份牛奶 描述 = " + aCoffee.getDes());
aCoffee = new Milk(aCoffee);
System.out.println("aCoffee 加入一份糖 两份牛奶 费用 = " + aCoffee.cost());
System.out.println("aCoffee 加入一份糖 两份牛奶 描述 = " + aCoffee.getDes());
}
}
// 允许效果
// 费用1 = 5.0
// 描述 = ACoffee
// aCoffee 加入一份糖 费用 = 14.0
// aCoffee 加入一份糖 描述 = 糖 || ACoffee
// aCoffee 加入一份糖 一份牛奶 费用 = 15.0
// aCoffee 加入一份糖 一份牛奶 描述 = 牛奶 || 糖 || ACoffee
// aCoffee 加入一份糖 两份牛奶 费用 = 16.0
// aCoffee 加入一份糖 两份牛奶 描述 = 牛奶 || 牛奶 || 糖 || ACoffee
通过阅读源码可知jdk中的io结构就是一个很典型的装饰者模式
public abstract class InputStream implements Closeable {
// ....
}
FilelnputStrearm 是 InputStream 子类,是具体的被装饰者类似我们前面的ACoffee、BCofee
FilterInputStream 是InputStream 子类:类似我们前面的 Decorator 修饰者
public class FilterInputStream extends InputStream {
/**
FilterinputStream 类有 protected volatile InputStream in;即含被装饰者
* The input stream to be filtered.
*/
protected volatile InputStream in;
// ...
}