基本定義 裝飾者模式屬於 結構型模式 ,它可以 動態的 將新功能 附加到對象上 ,同時又 不改變其結構 。在對象功能擴展方面,它比繼承更有彈性,裝飾者模式也體現了開閉原則(OCP)。 模式結構 裝飾者和被裝飾者有 相同的超類型 ,因為裝飾者和被裝飾者必須是一樣的類型, 利用繼承是為了達到類型的匹配, ...
基本定義
裝飾者模式屬於結構型模式,它可以動態的將新功能附加到對象上,同時又不改變其結構。在對象功能擴展方面,它比繼承更有彈性,裝飾者模式也體現了開閉原則(OCP)。
模式結構
裝飾者和被裝飾者有相同的超類型,因為裝飾者和被裝飾者必須是一樣的類型,利用繼承是為了達到類型的匹配,而不是利用繼承獲取行為
- Component:裝飾者和被裝飾者共同的父類,是一個介面或者抽象類,用來定義基本行為
- ConcreteComponent:定義具體對象,即被裝飾者
- Decorator:抽象裝飾者,繼承自 Component,從外類來擴展 ConcreteComponent。對於 ConcreteComponent來說,不需要知道Decorator的存在,Decorator 是一個介面或抽象類
- ConcreteDecorator:具體裝飾者,用於擴展 ConcreteComponent
舉例說明
在咖啡店客人想點一杯加兩份糖一份牛奶的摩卡咖啡,各個商品的價格如下,我們需要根據用戶點的咖啡、加的配料,動態的計算價格
商品 | 價格 |
---|---|
拿鐵咖啡(LatteCoffee) | 4.5 |
摩卡咖啡(MochaCoffe) | 5.5 |
糖(Sugar) | 1.0 |
牛奶(Milk) | 2.0 |
「實體類」 Coffee
public abstract class Coffee{
public String des = "咖啡"; //描述
private float price = 0.0f; //價格
protected abstract float cost(); //計算費用
//省略getter setter方法
}
「被裝飾者」LatteCoffee
public class LatteCoffee extends Coffee{
public LatteCoffee() {
setDes("拿鐵咖啡");
setPrice(4.5f);
}
@Override
protected float cost() {
return getPrice();
}
}
「被裝飾者」MochaCoffee
public class MochaCoffee extends Coffee {
public MochaCoffee() {
setDes("摩卡咖啡");
setPrice(5.5f);
}
@Override
protected float cost() {
return getPrice();
}
}
「抽象裝飾者」Decorator
public class Decorator extends Coffee {
private Coffee coffee;
public Decorator(Coffee drink) {
this.coffee = drink;
}
@Override
protected float cost() {
return getPrice() + coffee.cost();
}
@Override
public String getDes() {
return coffee.getDes() + "加" + super.getDes();
}
}
「具體裝飾者」SugarDecorator
public class SugarDecorator extends Decorator{
public SugarDecorator(Coffee coffee) {
super(coffee);
setDes("糖");
setPrice(1.0f);
}
}
「具體裝飾者」MilkDecorator
public class MilkDecorator extends Decorator{
public MilkDecorator(Coffee coffee) {
super(coffee);
setDes("牛奶");
setPrice(2.0f);
}
}
「測試類」Client
public class Client {
/**
* 點一杯 加兩份糖一份牛奶的摩卡咖啡
*/
@Test
public void test01() {
Coffee order = new MochaCoffee();
System.out.println(order.getDes() + ",價格:" + order.cost());
//加兩份糖
order = new SugarDecorator(new SugarDecorator(order));
System.out.println(order.getDes() + ",價格:" + order.cost());
//加一份牛奶
order = new MilkDecorator(order);
System.out.println(order.getDes() + ",價格:" + order.cost());
}
}
「結果」result
摩卡咖啡,價格:5.5
摩卡咖啡加糖加糖,價格:7.5
摩卡咖啡加糖加糖加牛奶,價格:9.5
在 Java IO 流中的應用
在上圖所示的關係中
- 實體類是 InputStream
- 被裝飾者是FileInputStream、StringBufferInputStream、ByteArrayInputStream
- 抽象裝飾者是FilterInputStream
- 具體裝飾者是BufferInputStream、DataInputStream、LineNumberInputStream
具體使用如下:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("G:\\a.txt"));
裝飾者模式總結
1、利用繼承設計子類,只能在編譯時靜態決定,並且所有子類都會繼承相同的行為;利用組合擴展對象,就可以在運行時動態的進行擴展。
2、裝飾者和被裝飾者對象有相同的超類型,所以在任何需要原始對象(被裝飾者)的場合,都可以用裝飾過的對象代替原始對象。
3、可以用一個或多個裝飾者包裝一個對象(被裝飾者)。
4、裝飾者可以在所委托的裝飾者行為之前或之後加上自己的行為,以達到特定的目的。
5、被裝飾者可以在任何時候被裝飾,所以可以在運行時動態地、不限量地用你喜歡的裝飾者來裝飾對象。
6、裝飾者會導致出現很多小對象,如果過度使用,會讓程式變得複雜。