裝飾模式——Decorator
案例展示——Decorator怎麼用?
現在有這樣一種場景:關於二手車我們都不會陌生,或多或少我們都會有接觸。那你有沒有想過,如何才能把一輛二手車賣出好的價錢呢?是直接和買主攤牌二手車的所有效能引數,還是會適當的加以修飾一下來獲得一個好的價位呢?誠然,所謂商場之道,誠信至上,我們當然需要誠實的與買主說清楚二手車的各種引數,但是在商言商,我想些許修飾也是不過分的,下面是一家二手車4S店賣二手車的一個類圖設計:
類圖元素分析:
-
SHCar:二手車抽象類,裡面有兩個基本的方法,show()方法用於向用戶展示二手車的基本引數;order()方法為使用者下訂單。
-
SHBaomaCar:具體的二手車型別
-
Decorator:一個抽象的裝飾類,它會對每輛二手車進行裝飾
-
PowerEngineDecorator:具體的裝飾類,繼承了Decorator,用於裝飾二手車的引擎
-
FastSpeedDecorator:具體的裝飾類,繼承了Decorator,用於裝飾二手車的速度
下面是具體的程式碼展示:
// 抽象車類
public abstract class SHCar {
// 給客戶展示二手車的基本資訊
public abstract void show();
// 使用者下訂單
public abstract void order(String name);
}
// 具體的型別
public class SHBaomaCar extends SHCar{
// 展示一下二手寶馬車
public void show() {
System.out.println("型號:寶馬X6");
System.out.println("顏色:寶石藍");
System.out.println("發動機:動力好");
System.out.println("推薦:價效比高,值得擁有");
}
// 使用者下訂單
public void order(String name) {
System.out.println("我是 " + name + ",這輛車我要了!");
}
}
// 抽象裝飾器
public abstract class Decorator extends SHCar{
// 那種型別的二手車:寶馬,賓士,奧迪,法拉利....
private SHCar sc;
// 建構函式,傳入二手車
public Decorator(SHCar sc) {
this.sc = sc;
}
// 檢視二手車的具體資訊
public void show() {
this.sc.show();
}
// 使用者下訂單
public void order(String name) {
this.sc.order(name);
}
}
// 引擎裝飾器
public class PowerEngineDecorator extends Decorator{
// 建構函式
public PowerEngineDecorator(SHCar sc) {
super(sc);
}
// 說說這輛車的強大的引擎
private void showEngine() {
System.out.println("====進口引擎,動力杆杆的!!!====");
}
// 在向用戶展示之前先給他說一下
@Override
public void show() {
this.showEngine();
super.show();
}
}
// 速度裝飾器
public class FastSpeedDecorator extends Decorator {
// 建構函式
public FastSpeedDecorator(SHCar sc) {
super(sc);
}
// 說說這輛車的速度:百米加速3秒!
private void showSpeed() {
System.out.println("=====百米加速3秒!!!=====");
}
// 在展示之後和使用者說一下,增加吸引力
@Override
public void show() {
super.show();
this.showSpeed();
}
}
// 客戶買車
public class Client {
public static void main(String[] args) {
// 沒有修飾的原裝車
SHCar sc = new SHBaomaCar();
// 修飾一下:強大的引擎
sc = new PowerEngineDecorator(sc);
// 強調一下:超快的速度
sc = new FastSpeedDecorator(sc);
// 展示
sc.show();
// 使用者很開心,下單!
sc.order("張三");
}
}
// 執行結果如下:
====進口引擎,動力杆杆的!!!====
型號:寶馬X6
顏色:寶石藍
發動機:動力好
推薦:價效比高,值得擁有
=====百米加速3秒!!!=====
我是 張三,這輛車我要了!
上面的例子中使用的就是裝飾模式,通過一個抽象的裝飾器得到它要裝飾的型別,然後交給具體的裝飾型別去裝飾,這樣在沒有改變二手車基本引數的情況下,使其給客戶的觀感更好,人家自然很高興就下單了。
深入分析——Decorator是什麼?
Decorator的定義
定義: 動態的給一個物件新增一些額外的職責,就增加功能來說,裝飾模式比生成子類更加靈活。下面是裝飾模式的通用類圖:
-
Conponent組建:一個介面或者抽象類,定義最核心的物件,如二手車
-
ConcreateComponent組建:具體的構建,被裝飾的物件
-
Decorator組建:裝飾者
-
ConcreateDecorator:具體的裝飾者
下面是具體程式碼
// 抽象構建
public abstract class Component {
// 抽象方法
public abstract void operate();
}
// 具體構建
public class ConcreateComponent extends Component {
// 具體實現
public void operate() {
// 業務邏輯
}
}
// 抽象裝飾器
public abstract class Decorator extends Component{
// 修飾哪個組建
private Component component = null;
// 通過建構函式傳遞被修飾者
public Decorator(Component component) {
this.component = component;
}
// 委託給被修飾者執行
@Override
public void operate() {
this.component.operate();
}
}
// 具體的裝飾器
public class ConcreateDecorator1 extends Decorator {
// 傳遞被修飾者
public ConcreateDecorator1(Component component) {
super(component);
}
// 定義自己的修飾方法
private void method1() {
// 修飾
}
// 重寫父類的operate()方法
public void operate() {
this.method1();
super.operate();
}
}
// 具體的裝飾器
public class ConcreateDecorator2 extends Decorator {
// 傳遞被修飾者
public ConcreateDecorator2(Component component) {
super(component);
}
// 定義自己的修飾方法
private void method2() {
// 修飾
}
// 重寫父類的operate()方法
public void operate() {
super.operate();
this.method2();
}
}
// 場景類
public class Client {
public static void main(String[] args) {
Component component = new ConcreateComponent();
// 第一次修飾
component = new ConcreateDecorator1(component);
// 第二次修飾
component = new ConcreateDecorator2(component);
// 執行
component.operate();
}
}
Decorator的優點
-
裝飾類和被裝飾類可以獨立發展,而不會相互耦合
-
裝飾模式是繼承關係的一個替代方案
-
裝飾模式可以動態的擴充套件一個實現類的功能
Decorator的缺點
-
裝飾類太多會增加複雜性
-
會產生很多小物件,增加系統的複雜性
-
雖然比繼承更加靈活,當時也意味著比繼承更加容易出錯。在出現錯誤後,由於多層裝飾,排錯很困難,需要逐級排查,較為繁瑣
Decorator的應用場景
-
需要擴張一個類的功能或給一個類增加附加功能
-
需要動態的給一個物件增加功能,這些功能可以再動態的撤銷
-
需要為一批兄弟類改裝或加裝功能
參考
《設計模式之禪》