簡介
裝飾模式也算一種比較常見的設計模式,工作過程中很少刻意的去實現這種模式,因為這種模式也會帶來一些問題。
比如小類太多,組織起來比較麻煩,對客戶端完全可見,如果不瞭解各個類的功能會很亂等等
當然也有很多優點: 可以動態的給類增加一些職責,增加功能更加靈活,比起繼承來說也更加具有彈性
下面我們來看看它究竟是什麼樣子的
場景設定
以買車業務模型為例(本人未買過車,業務場景純屬臆想)
車裡面還有很多裝備可以選擇,根據不同的選擇裝飾決定最後到手的價格:
商品 | 價格 |
---|---|
裸車 | 100000 |
加熱座椅(可選) | 4000 |
真皮內飾(可選) | 8000 |
蹦迪音響(可選) | 5000 |
第一版本實現(我們在一個類裡面完成)
package car;
public class Car {
//總價
private int allPrice = 0;
//裸車價格 --實際數值從資料庫查詢,此處略
private int nakedPrice = 100000;
//加熱座椅
private int heatedSeat = 4000;
//真皮內飾
private int dermalInteriors = 8000;
//蹦迪音響
private int bengdiSound = 5000;
public Car() {
this.allPrice += this.nakedPrice;
}
/**
* 新增真皮座椅
*/
public void addHeatedSeat() {
this.allPrice += this.heatedSeat;
}
/**
* 新增真皮內飾
*/
public void addDermalInteriors() {
this.allPrice += this.dermalInteriors;
}
/**
* 新增蹦迪音響
*/
public void addBengdiSound() {
this.allPrice += this.bengdiSound;
}
/**
* 獲取總價
*
* @return
*/
public int cost() {
return this.allPrice;
}
}
複製程式碼
客戶端呼叫:
package car;
public class Main {
public static void main(String[] args) {
Car car = new Car();
car.addBengdiSound();
System.out.println("總花費價格:" + car.cost());
}
}
複製程式碼
output:
花費價格105000
複製程式碼
看起來很簡潔呢,並且也很好的實現了功能
首先這是我們的場景足夠的簡單,所涉及的配套元件也比較少,實際中可能針對某個方法可能有很複雜的獲取和計算邏輯,元件也會有很多種選擇,會造成類爆炸,無法繼續維護下去
如果我們使用裝飾模式,會帶來什麼改變呢,會給我們帶來什麼樣的體驗呢
設計:
實現:
宣告抽象類(被裝飾者和裝飾者繼承此類,目的對實現方法進行規正)
package car;
public abstract class Car {
public String name;
public abstract String cost();
}
複製程式碼
主角:被裝飾者類-裸車
package car;
/**
* 被裝飾的類 -> 裸車
*/
public class NakeCar extends Car {
//裸車價格 --實際數值從資料庫查詢,此處略
private int nakedPrice = 100000;
public NakeCar() {
this.name = "裸車";
}
/**
* 獲取總價
*
* @return
*/
public String cost() {
return this.name + ":" + this.nakedPrice;
}
}
複製程式碼
具體裝飾類:
加熱座椅
package car;
/**
* 裝飾元件
*/
public class HeatedSeat extends Car {
//加熱座椅
private int heatedSeat = 4000;
//汽車物件
private Car car;
public HeatedSeat(Car car) {
this.name = "加熱座椅";
this.car = car;
}
/**
* 獲取價格
*
* @return
*/
public String cost() {
//todo
return this.car.cost() + "||" + this.name + ":" + this.heatedSeat;
}
}
複製程式碼
真皮內飾
package car;
public class DermalInteriors extends Car {
//真皮內飾
private int dermalInteriors = 8000;
//汽車物件
private Car car;
public DermalInteriors(Car car) {
this.name = "真皮內飾";
this.car = car;
}
/**
* 獲取價格
*
* @return
*/
public String cost() {
//todo
return this.car.cost() + "||" + this.name + ":" + this.dermalInteriors;
}
}
複製程式碼
蹦迪音響
package car;
public class BengdiSound extends Car {
//蹦迪音響
private int bengdiSound = 5000;
//汽車物件
private Car car;
public BengdiSound(Car car) {
this.name = "蹦迪音響";
this.car = car;
}
/**
* 獲取價格
*
* @return
*/
public String cost() {
//todo
return this.car.cost() + "||" + this.name + ":" + this.bengdiSound;
}
}
複製程式碼
客戶端呼叫:
package car;
public class Main {
public static void main(String[] args) {
NakeCar car = new NakeCar();
HeatedSeat heatedSeat = new HeatedSeat(car);
BengdiSound bengdiSound = new BengdiSound(heatedSeat);
System.out.println("總花費價格:" + bengdiSound.cost());
}
}
複製程式碼
output:
總花費價格:裸車:100000||加熱座椅:4000||蹦迪音響:5000
複製程式碼
總結
-
裝飾模式的優點:
可以為已有的功能(被裝飾物件)動態的新增功能,簡化原有類。在我們的例子中, 裸車是主類,相當於業務中的核心,而一些動態的元件可以根據實際情況使用,也就相當於我們業務線中的附屬擴充功能。主邏輯和擴充邏輯的區分會使我們的程式碼更具擴充性。
-
裝飾模式的缺點:
我們可以看到裝飾模式的引入會增多類的數量,以及客戶端的使用會有複雜度上升。裝飾模式的類依賴特定的型別,需要嚴格遵守規約(抽象類的約束)
更多精彩內容關注公眾號: