設計模式之裝飾模式

裝飾模式

一:裝飾模式概述

裝飾模式能夠在不改變一個對象自己功能的基礎上給對象增長額外的新行爲,好比把房子裝修就是一個很典型的場景。java

裝飾模式是一種用於替代繼承的技術,它經過一種無須定義子類的方式來給對象動態增長職責,使用對象之間的關聯關係取代類之間的繼承關係。在裝飾模式中引入了裝飾類,在裝飾類中既能夠調用待裝飾的原有類的方法,還能夠增長新的方法,以擴充原有類的功能。編程

定義以下:ide

裝飾模式(Decorator Pattern):動態地給一個對象增長一些額外的職責,就增長對象功能來講,裝飾模式比生成子類實現更爲靈活。裝飾模式是一種對象結構型模式。性能


二:裝飾模式結構圖

結構如圖:this

1545730197442

角色說明:spa

  • Component(抽象構件):它是具體構件和抽象裝飾類的都要繼承的接口(也能夠是父類,建議接口,面向接口編程),聲明瞭在具體構件中實現的業務方法,它的引入可使客戶端以一致的方式處理未被裝飾的對象以及裝飾以後的對象,實現客戶端的透明操做。
  • ConcreteComponent(具體構件):它是抽象構件類的子類,用於定義具體的構件對象,實現了在抽象構件中聲明的方法,裝飾器能夠給它增長額外的職責(方法)。
  • Decorator(抽象裝飾類):它也是抽象構件類的子類,用於給具體構件增長職責,可是具體職責在其子類中實現。它維護一個指向抽象構件對象的引用,經過該引用能夠調用裝飾以前構件對象的方法,並經過其子類擴展該方法,以達到裝飾的目的。
  • ConcreteDecorator(具體裝飾類):它是抽象裝飾類的子類,負責向構件添加新的職責。每個具體裝飾類都定義了一些新的行爲,它能夠調用在抽象裝飾類中定義的方法,並能夠增長新的方法用以擴充對象的行爲。

因爲具體構件類和裝飾類都實現了相同的抽象構件接口,所以裝飾模式以對客戶透明的方式動態地給一個對象附加上更多的責任,換言之,客戶端並不會以爲對象在裝飾前和裝飾後有什麼不一樣。裝飾模式能夠在不須要創造更多子類的狀況下,將對象的功能加以擴展。.net


三:裝飾模式實戰

咱們如今能夠畫圓,可是須要自定義線條的粗細和線條的風格,怎麼經過裝飾器來實現這一個功能呢?設計

先來看一下代碼:調試

Shape:code

// 形狀的接口
public interface Shape {
    // 畫圖
    void draw();
}
複製代碼

Circle:

// 圓形
public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("畫圓");
    }

}
複製代碼

ShapeDecorator:

// 抽象類形狀裝飾器
public abstract class ShapeDecorator implements Shape {
    protected Shape decoratedShape;
    public ShapeDecorator(Shape decoratedShape) {
        super();
        this.decoratedShape = decoratedShape;
    }
}
複製代碼

LineStyleDecorator:

//自定義線條裝飾器
public class LineStyleDecorator extends ShapeDecorator {
    protected LineStyle style;
    public LineStyleDecorator(Shape decoratedShape, LineStyle style) {
        super(decoratedShape);
        this.style = style;
    }
    @Override
    public void draw() {
        decoratedShape.draw();
        System.out.println("線條風格: " + style);
    }

}
複製代碼

LineThinknessDecorator:

// 自定義線條粗細裝飾器
public class LineThinknessDecorator extends ShapeDecorator {
    // 厚度
    protected double thickness;
    public LineThinknessDecorator(Shape decoratedShape, double thickness) {
        super(decoratedShape);
        this.thickness = thickness;
    }
    @Override
    public void draw() {
        decoratedShape.draw();
        System.out.println("線條粗細:" + thickness);
    }

}
複製代碼

LineStyle:

// 線條風格
public enum LineStyle {
    SOLID, // 實心
    DASH, // 長劃
    DOT, // 點
    DOUBLE_DASH, // 雙線
}
複製代碼

client:

public class Client {
    public static void main(String[] args) {
        Shape circle = new Circle();
        circle.draw();
        System.out.println();

        // 經過兩個裝飾類,定義了線條的粗細以及線條的風格
        Shape circle1 = new LineStyleDecorator(
                             new LineThinknessDecorator(new Circle(), 2.0d),
                LineStyle.DASH);
        circle1.draw();
    }
}
複製代碼

結果打印:

畫圓

畫圓 線條粗細:2.0 線條風格: DASH

**說明:**抽象裝飾器ShapeDecorator和具體的構件Circle都實現了抽象構件Shape,ShapeDecorator維護了一個Shape引用,經過該引用指向裝飾前的構件對象,並經過子類LineStyleDecorator和LineThinknessDecorator來擴展對象行爲。


四:裝飾模式注意事項

  1. 儘可能保持裝飾類的接口與被裝飾類的接口相同,這樣,對於客戶端而言,不管是裝飾以前的對象仍是裝飾以後的對象均可以一致對待
  2. 儘可能保持具體構件類ConcreteComponent是一個「輕」類,也就是說不要把太多的行爲放在具體構件類中,咱們能夠經過裝飾類對其進行擴展。

四:裝飾模式總結

優點:

  1. 對於擴展一個對象的功能,裝飾模式比繼承更加靈活性,不會致使類的個數急劇增長。
  2. 能夠經過一種動態的方式來擴展一個對象的功能,經過配置文件能夠在運行時選擇不一樣的具體裝飾類,從而實現不一樣的行爲。
  3. 能夠對一個對象進行屢次裝飾,經過使用不一樣的具體裝飾類以及這些裝飾類的排列組合,能夠創造出不少不一樣行爲的組合,獲得功能更爲強大的對象。
  4. 具體構件類與具體裝飾類能夠獨立變化,用戶能夠根據須要增長新的具體構件類和具體裝飾類,原有類庫代碼無須改變,符合「開閉原則」。

劣勢:

  1. 使用裝飾模式進行系統設計時將產生不少小對象,這些對象的區別在於它們之間相互鏈接的方式有所不一樣,而不是它們的類或者屬性值有所不一樣,大量小對象的產生勢必會佔用更多的系統資源,在必定程序上影響程序的性能。
  2. 裝飾模式提供了一種比繼承更加靈活機動的解決方案,但同時也意味着比繼承更加易於出錯,排錯也很困難,對於屢次裝飾的對象,調試時尋找錯誤可能須要逐級排查,較爲繁瑣。

五:適用場景

  1. 在不影響其餘對象的狀況下,以動態、透明的方式給單個對象添加職責。
  2. 當不能採用繼承的方式對系統進行擴展或者採用繼承不利於系統擴展和維護時可使用裝飾模式。不能採用繼承的狀況主要有兩類:第一類是系統中存在大量獨立的擴展,爲支持每一種擴展或者擴展之間的組合將產生大量的子類,使得子類數目呈爆炸性增加;第二類是由於類已定義爲不能被繼承。

參考:blog.csdn.net/lovelion/ar…

相關文章
相關標籤/搜索