源码地址:https://github.com/877148107/java-design-pattern
-
装饰者模式:动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(ocp)
-
这里提到的动态的将新功能附加到对象和ocp****原则,在后面的应用实例上会以代码的形式体现。
-
装饰者模式就像打包一个快递
主体:比如:陶瓷、衣服 (Component) // 被装饰者
包装:比如:报纸填充、塑料泡沫、纸板、木板(Decorator)
-
Component主体
-
ConcreteComponent:具体的主体,Decorator: 装饰者
-
在如图的Component与ConcreteComponent之间,如果ConcreteComponent类很多,还可以设计一个缓冲层,将共有的部分提取出来,抽象层一个类。
-
咖啡种类/单品咖啡:Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(无因咖啡)
-
调料:Milk、Soy(豆浆)、Chocolate
-
要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便、维护方便
-
使用OO的来计算不同种类咖啡的费用:客户可以点单品咖啡,也可以单品咖啡+调料组合。
2、UML类图
1)Drink就是一个被装饰类(主体)就是前面说的抽象类, Component,
2)ShortBlack 就单品咖啡
3)Decorator 是一个装饰类,含有一个被装饰的对象(Drink obj)
4)Decorator 的cost 方法 进行一个费用的叠加计算,递归的计算价格
Drink就是需求中的咖啡,coffee就是具体美式咖啡、意大利浓咖啡等的父类,Decorator装饰咖啡的在咖啡里面加牛奶、巧克力等。这里Coffee和Decorator就代表了具体的被装饰者和具体的装饰着。
3、代码实现
被装饰类(主体)
public abstract class Drink {
/**
* 描述
*/
private String description;
/**
* 单价
*/
private float price;
/**
* 抽象方法,子类实现计算费用
* @return
*/
public abstract float cost();
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
}
装饰类,包含了被装饰类
public class Decorator extends Drink {
Drink drink;
public Decorator(Drink drink) {
this.drink = drink;
}
@Override
public float cost() {
return super.getPrice()+drink.cost();
}
@Override
public String getDescription() {
return super.getDescription()+"-"+super.getPrice()+"&&"+drink.getDescription();
}
}
class Milk extends Decorator{
public Milk(Drink drink) {
super(drink);
setDescription("一份牛奶");
setPrice(5f);
}
}
class Chocolate extends Decorator{
public Chocolate(Drink drink) {
super(drink);
setDescription("一份巧克力");
setPrice(2f);
}
}
具体的被装饰类(具体的主体)
public class Coffee extends Drink {
@Override
public float cost() {
return super.getPrice();
}
}
class Espresso extends Coffee{
public Espresso() {
setDescription("意大利浓咖啡");
setPrice(5f);
}
}
class ShortBlack extends Coffee{
public ShortBlack() {
setDescription("浓咖啡");
setPrice(4f);
}
}
class LongBlack extends Coffee{
public LongBlack() {
setDescription("美式咖啡");
setPrice(6f);
}
}
测试
public class CoffeeClient {
public static void main(String[] args) {
Drink longBlack = new LongBlack();
System.out.println("描述:"+longBlack.getDescription());
System.out.println("价格:"+longBlack.cost());
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
Drink espresso = new Espresso();
System.out.println("描述:"+espresso.getDescription());
System.out.println("价格:"+espresso.cost());
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
System.out.println("=====美式咖啡+一份牛奶+两份巧克力======");
longBlack = new Milk(longBlack);
longBlack = new Chocolate(longBlack);
longBlack = new Chocolate(longBlack);
System.out.println("描述:"+longBlack.getDescription());
System.out.println("加一份牛奶,两份巧克力价格:"+longBlack.cost());
System.out.println("=====意大利浓咖啡+一份牛奶+一份巧克力======");
espresso = new Milk(espresso);
espresso = new Chocolate(espresso);
System.out.println("描述:"+espresso.getDescription());
System.out.println("加一份牛奶,一份巧克力价格:"+espresso.cost());
}
}
-
JDK源码分析
装饰者模式在JDK应用的源码分析
Java的IO结构,FilterInputStream就是一个装饰者。
1、InputStream就是一个抽象类,跟前面案例的drink一样
2、FileInputStream是InputStream子类,类似前面案例的LongBlack、Espresso
3、FilterInputStream是InputStream子类,类似前面案例的Decorator,里面包含了被装饰着InputStream
4、DataInputStream是FilterInputStream子类,类似前面的Milk、Chocolat
public abstract class InputStream implements Closeable {
public abstract int read() throws IOException;
}
public class FilterInputStream extends InputStream {
/**
* The input stream to be filtered.
*/
protected volatile InputStream in;
/**
* Creates a <code>FilterInputStream</code>
* by assigning the argument <code>in</code>
* to the field <code>this.in</code> so as
* to remember it for later use.
*
* @param in the underlying input stream, or <code>null</code> if
* this instance is to be created without an underlying stream.
*/
protected FilterInputStream(InputStream in) {
this.in = in;
}
}
public class DataInputStream extends FilterInputStream implements DataInput {
public DataInputStream(InputStream in) {
super(in);
}
}