一,裝飾者模式
裝飾者模式:
動態的將新功能附加到對象上,在功能擴展方面比繼承更具有彈性,體現了OCP原則;
二,原理類圖
意圖: 動態地給一個對象添加一些額外的職責。就增加功能來說,Decorator 模式相比生成子類更爲靈活。
適用性:
- 在不影響其他對象的情況下,以動態、透明的方式給單個對象添加職責。
- 處理那些可以撤消的職責。
- 當不能採用生成子類的方法進行擴充時。一種情況是,可能有大量獨立的擴展,爲支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增長。另一種情況可能是因爲類定義被隱藏,或類定義不能用於生成子類。
三,實例
抽象類
package com.neei.decorator;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/7 16:23
* @Description: 遊學網
* @throws:
*/
public abstract class Drink {
private String desc;
private double price = 0.0d;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public abstract double cost();
}
緩存層
package com.neei.decorator.coffee;
import com.neei.decorator.Drink;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/7 16:25
* @Description: 遊學網
* @throws:
*/
public class Coffee extends Drink {
@Override
public double cost() {
return super.getPrice();
}
}
被裝飾物
package com.neei.decorator.coffee;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/7 16:29
* @Description: 遊學網
* @throws:
*/
public class Latte extends Coffee {
public Latte() {
setDesc("拿鐵咖啡");
setPrice(8D);
}
}
public class Civet extends Coffee {
public Civet() {
setDesc("貓屎咖啡");
setPrice(88D);
}
}
裝飾者
package com.neei.decorator;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/7 16:31
* @Description: 遊學網
* @throws:
*/
public class Decorator extends Drink {
private Drink drink;
public Decorator(Drink drink) {
this.drink = drink;
}
@Override
public double cost() {
return super.getPrice() + drink.cost();
}
//輸出裝飾者信息
@Override
public String getDesc() {
return super.getDesc() + ":" + super.getPrice() + "&&" + drink.getDesc() + ":" + drink.getPrice();
}
}
裝飾物
package com.neei.decorator.season;
import com.neei.decorator.Decorator;
import com.neei.decorator.Drink;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/7 16:36
* @Description: 遊學網
* @throws:
*/
public class Chocolate extends Decorator {
public Chocolate(Drink drink) {
super(drink);
setDesc("巧克力");
setPrice(3D);
}
}
public class Milk extends Decorator {
public Milk(Drink drink) {
super(drink);
setDesc("牛奶");
setPrice(2D);
}
}
public class Sugar extends Decorator {
public Sugar(Drink drink) {
super(drink);
setDesc("糖");
setPrice(1D);
}
}
調用
package com.neei.decorator;
import com.neei.decorator.coffee.Civet;
import com.neei.decorator.season.Chocolate;
import com.neei.decorator.season.Milk;
import com.neei.decorator.season.Sugar;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/7 16:39
* @Description: 遊學網
* @throws:
*/
public class CoffeeBar {
public static void main(String[] args) {
//點一份貓屎,加糖,牛奶,巧克力各一份
Drink drink = new Civet();
System.out.println(drink.cost());
System.out.println(drink.getDesc());
//加糖
drink = new Sugar(drink);
System.out.println(drink.cost());
System.out.println(drink.getDesc());
//加牛奶
drink=new Milk(drink);
System.out.println(drink.cost());
System.out.println(drink.getDesc());
//加巧克力
drink=new Chocolate(drink);
System.out.println(drink.cost());
System.out.println(drink.getDesc());
}
}
四,源碼分析
JDK源碼中使用的裝飾者模式,如FilterInputStream;
public class FilterInputStream extends InputStream {
/**
* The input stream to be filtered.
*/
protected volatile InputStream in;
...
}