前言:html
設計模式是對你們實際工做中寫的各類代碼進行高層次抽象的總結,其中最出名的當屬 Gang of Four (GoF) 的分類了,他們將設計模式分類爲 23 種經典的模式,根據用途咱們又能夠分爲三大類,分別爲建立型模式、結構型模式和行爲型模式。是的,我不善於扯這些有的沒的,仍是少點廢話吧~~~java
有一些重要的設計原則在開篇和你們分享下,這些原則將貫通全文:算法
面向接口編程,而不是面向實現。這個很重要,也是優雅的、可擴展的代碼的第一步,這就不須要多說了吧。數據庫
職責單一原則。每一個類都應該只有一個單一的功能,而且該功能應該由這個類徹底封裝起來。編程
對修改關閉,對擴展開放。對修改關閉是說,咱們辛辛苦苦加班寫出來的代碼,該實現的功能和該修復的 bug 都完成了,別人可不能說改就改;對擴展開放就比較好理解了,也就是說在咱們寫好的代碼基礎上,很容易實現擴展。1、設計模式入門:設計模式
1.設計模式是人們在面對同類型軟件工程設計問題所總結出的一些有用經驗。模式不是代碼,而是某類問題的通用設計解決方案
2.設計模式的本質目的是使軟件工程在維護性、擴展性、變化性、複雜度方面成O(N)
3.OOP是原則,設計模式是具體方法、工具 瀏覽器
首先咱們看下各個模式之間的關係圖,下面這張圖是網上比較典型的一個類圖關係:安全
從上面的類圖之間能夠看出,學習設計模式或者說學懂徹底理解全部的設計模式仍是挺難的,只能說不斷的重複學習,不斷的去領悟纔是惟一的方法,固然不排除有些人是天才看一篇就學會了,惋惜鄙人不是,因此必須不斷重複學習來加深本身的理解。我的感受,單例、工廠、裝飾者、觀察者、代理模式使用的頻率比較高;固然不是說其餘模糊就不使用,只是我的的見解而已,o(* ̄︶ ̄*)o。服務器
學習設計模式,首先要學習的就是設計原則,所以我從設計原則來開始第一個節。網絡
(一)、設計原則
1.單一職責
2.里氏替換原則 (Liskov Substitution Principle)
3.依賴倒置原則 (Dependence Inversion Principle)
4.接口隔離原則 (Interface Segregation Principle)
5.迪米特法則(最少知道原則) (Demeter Principle)
6.開閉原則(Open Close Principle
咱們用一幅圖來講明一下
詳細請參考:www.cnblogs.com/pony1223/p/7594803.html
(二)、什麼是設計模式
設計模式(Design pattern)是一套被反覆使用、多數人知曉的、通過分類編目的、代碼設計經驗的總結。使用設計模式是爲了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。 毫無疑問,設計模式於己於他人於系統都是多贏的,設計模式使代碼編制真正工程化,設計模式是軟件工程的基石,如同大廈的一塊塊磚石同樣。項目中合理的運用設計模式能夠完美的解決不少問題,每種模式在如今中都有相應的原理來與之對應,每個模式描述了一個在咱們周圍不斷重複發生的問題,以及該問題的核心解決方案,這也是它能被普遍應用的緣由。簡單說:
模式:在某些場景下,針對某類問題的某種通用的解決方案。
場景:項目所在的環境
問題:約束條件,項目目標等
解決方案:通用、可複用的設計,解決約束達到目標。
(三)、設計模式的三個分類
建立型模式:對象實例化的模式,建立型模式用於解耦對象的實例化過程。
結構型模式:把類或對象結合在一塊兒造成一個更大的結構。
行爲型模式:類和對象如何交互,及劃分責任和算法。
以下圖所示:
各分類中模式的關鍵點
單例模式:某個類只能有一個實例,提供一個全局的訪問點。
簡單工廠:一個工廠類根據傳入的參量決定建立出那一種產品類的實例。
工廠方法:定義一個建立對象的接口,讓子類決定實例化那個類。
抽象工廠:建立相關或依賴對象的家族,而無需明確指定具體類。
建造者模式:封裝一個複雜對象的構建過程,並能夠按步驟構造。
原型模式:經過複製現有的實例來建立新的實例。
適配器模式:將一個類的方法接口轉換成客戶但願的另一個接口。
組合模式:將對象組合成樹形結構以表示「」部分-總體「」的層次結構。
裝飾模式:動態的給對象添加新的功能。
代理模式:爲其餘對象提供一個代理以便控制這個對象的訪問。
亨元(蠅量)模式:經過共享技術來有效的支持大量細粒度的對象。
外觀模式:對外提供一個統一的方法,來訪問子系統中的一羣接口。
橋接模式:將抽象部分和它的實現部分分離,使它們均可以獨立的變化。
模板模式:定義一個算法結構,而將一些步驟延遲到子類實現。
解釋器模式:給定一個語言,定義它的文法的一種表示,並定義一個解釋器。
策略模式:定義一系列算法,把他們封裝起來,而且使它們能夠相互替換。
狀態模式:容許一個對象在其對象內部狀態改變時改變它的行爲。
觀察者模式:對象間的一對多的依賴關係。
備忘錄模式:在不破壞封裝的前提下,保持對象的內部狀態。
中介者模式:用一箇中介對象來封裝一系列的對象交互。
命令模式:將命令請求封裝爲一個對象,使得能夠用不一樣的請求來進行參數化。
訪問者模式:在不改變數據結構的前提下,增長做用於一組對象元素的新功能。
責任鏈模式:將請求的發送者和接收者解耦,使的多個對象都有處理這個請求的機會。
迭代器模式:一種遍歷訪問聚合對象中各個元素的方法,不暴露該對象的內部結構。
2、概說23種設計模式 :
1.單例模式
單例模式,它的定義就是確保某一個類只有一個實例,而且提供一個全局訪問點。
單例模式具有典型的3個特色:一、只有一個實例。 二、自我實例化。 三、提供全局訪問點。
所以當系統中只須要一個實例對象或者系統中只容許一個公共訪問點,除了這個公共訪問點外,不能經過其餘訪問點訪問該實例時,可使用單例模式。
單例模式的主要優勢就是節約系統資源、提升了系統效率,同時也可以嚴格控制客戶對它的訪問。也許就是由於系統中只有一個實例,這樣就致使了單例類的職責太重,違背了「單一職責原則」,同時也沒有抽象類,因此擴展起來有必定的困難。其UML結構圖很是簡單,就只有一個類,以下圖:
懶漢式:
public class Singleton { /* 持有私有靜態實例,防止被引用,此處賦值爲null,目的是實現延遲加載 */ private static Singleton instance = null; /* 私有構造方法,防止被實例化 */ private Singleton() {} /* 1:懶漢式,靜態工程方法,建立實例 */ public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
調用:Singleton.getInstance().method();
雙重線程檢查模式:
public class SingletonInner { private static volatile SingletonInner sInst = null; // <<< 這裏添加了 volatile /** * 私有的構造函數 */ private SingletonInner() {} public static SingletonInner getInstance() { SingletonInner inst = sInst; // <<< 在這裏建立臨時變量 if (inst == null) { synchronized (SingletonInner.class) { inst = sInst; if (inst == null) { inst = new SingletonInner(); sInst = inst; } } } return inst; // <<< 注意這裏返回的是臨時變量 } protected void method() { System.out.println("SingletonInner"); } }
調用:Singleton.getInstance().method();
2.工廠方法模式
做爲抽象工廠模式的孿生兄弟,工廠方法模式定義了一個建立對象的接口,但由子類決定要實例化的類是哪個,也就是說工廠方法模式讓實例化推遲到子類。
工廠方法模式很是符合「開閉原則」,當須要增長一個新的產品時,咱們只須要增長一個具體的產品類和與之對應的具體工廠便可,無須修改原有系統。同時在工廠方法模式中用戶只須要知道生產產品的具體工廠便可,無須關係產品的建立過程,甚至連具體的產品類名稱都不須要知道。雖然他很好的符合了「開閉原則」,可是因爲每新增一個新產品時就須要增長兩個類,這樣勢必會致使系統的複雜度增長。其UML結構圖:
示例代碼:
public class Factory{ //getClass 產生Sample 通常可以使用動態類裝載裝入類。 public static Sample creator(int which){ if (which==1) return new SampleA(); else if (which==2) return new SampleB(); } }
/抽象產品角色 public interface Moveable { void run(); } //具體產品角色 public class Plane implements Moveable { @Override public void run() { System.out.println("plane...."); } } //具體產品角色 public class Broom implements Moveable { @Override public void run() { System.out.println("broom....."); } } //抽象工廠 public abstract class VehicleFactory { abstract Moveable create(); } //具體工廠 public class PlaneFactory extends VehicleFactory{ public Moveable create() { return new Plane(); } } //具體工廠 public class BroomFactory extends VehicleFactory{ public Moveable create() { return new Broom(); } } //測試類 public class Test { public static void main(String[] args) { VehicleFactory factory = new BroomFactory(); Moveable m = factory.create(); m.run(); } }
3.抽象工廠模式
所謂抽象工廠模式就是提供一個接口,用於建立相關或者依賴對象的家族,而不須要明確指定具體類。他容許客戶端使用抽象的接口來建立一組相關的產品,而不須要關係實際產出的具體產品是什麼。這樣一來,客戶就能夠從具體的產品中被解耦。它的優勢是隔離了具體類的生成,使得客戶端不須要知道什麼被建立了,而缺點就在於新增新的行爲會比較麻煩,由於當添加一個新的產品對象時,須要更加須要更改接口及其下全部子類。其UML結構圖以下:
示例代碼:
//抽象工廠類 public abstract class AbstractFactory { public abstract Vehicle createVehicle(); public abstract Weapon createWeapon(); public abstract Food createFood(); } //具體工廠類,其中Food,Vehicle,Weapon是抽象類, public class DefaultFactory extends AbstractFactory{ @Override public Food createFood() { return new Apple(); } @Override public Vehicle createVehicle() { return new Car(); } @Override public Weapon createWeapon() { return new AK47(); } } //測試類 public class Test { public static void main(String[] args) { AbstractFactory f = new DefaultFactory(); Vehicle v = f.createVehicle(); v.run(); Weapon w = f.createWeapon(); w.shoot(); Food a = f.createFood(); a.printName(); } }
4.建造者模式
對於建造者模式而已,它主要是將一個複雜對象的構建與表示分離,使得一樣的構建過程能夠建立不一樣的表示。適用於那些產品對象的內部結構比較複雜。
建造者模式將複雜產品的構建過程封裝分解在不一樣的方法中,使得建立過程很是清晰,可以讓咱們更加精確的控制複雜產品對象的建立過程,同時它隔離了複雜產品對象的建立和使用,使得相同的建立過程可以建立不一樣的產品。可是若是某個產品的內部結構過於複雜,將會致使整個系統變得很是龐大,不利於控制,同時若幾個產品之間存在較大的差別,則不適用建造者模式,畢竟這個世界上存在相同點大的兩個產品並非不少,因此它的使用範圍有限。其UML結構圖:
如何使用??
首先假設一個複雜對象是由多個部件組成的,Builder模式是把複雜對象的建立和部件的建立分別開來,分別用Builder類和Director類來表示。
首先,須要一個接口,它定義如何建立複雜對象的各個部件:
public interface Builder { //建立部件A 好比建立汽車車輪void buildPartA(); //建立部件B 好比建立汽車方向盤void buildPartB(); //建立部件C 好比建立汽車發動機void buildPartC(); //返回最後組裝成品結果 (返回最後裝配好的汽車) //成品的組裝過程不在這裏進行,而是轉移到下面的Director類中進行. //從而實現瞭解耦過程和部件 Product getResult(); }
用Director構建最後的複雜對象,而在上面Builder接口中封裝的是如何建立一個個部件(複雜對象是由這些部件組成的),也就是說Director的內容是如何將部件最後組裝成成品:
public class Director { private Builder builder; public Director( Builder builder ) { this.builder = builder; } // 將部件partA partB partC最後組成複雜對象 //這裏是將車輪 方向盤和發動機組裝成汽車的過程 public void construct() { builder.buildPartA(); builder.buildPartB(); builder.buildPartC(); } }
Builder的具體實現ConcreteBuilder:
public class ConcreteBuilder implements Builder { Part partA, partB, partC; public void buildPartA() { //這裏是具體如何構建 } public void buildPartB() { //這裏是具體如何構建 } public void buildPartC() { //這裏是具體如何構建 } public Product getResult() { //返回最後組裝成品結果 } }
複雜對象:產品Product:
public interface Product { }
複雜對象的部件:
public interface Part { }
咱們看看如何調用Builder模式:
ConcreteBuilder builder = new ConcreteBuilder(); Director director = new Director( builder ); director.construct(); Product product = builder.getResult();
5.觀察者模式
基本概念:觀察者模式定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一主題對象。這個主題對象在狀態發生變化時,會通知全部觀察者對象,使它們可以自動更新本身。觀察者模式又叫發佈-訂閱(Publish/Subscribe)模式。
UML結構圖:
如何使用??
例如:老師有電話號碼,學生須要知道老師的電話號碼以便於在合適的時候撥打,在這樣的組合中,老師就是一個被觀察者(Subject),學生就是須要知道信息的觀察者,當老師的電話號碼發生改變時,學生獲得通知,並更新相應的電話記錄。
先建立一個Subject類: /** * Subject(目標,Subject): * 目標知道它的觀察者。能夠有任意多個觀察者觀察同一個目標。 * 提供註冊和刪除觀察者對象的接口。 */ public interface Subject { public void attach(Observer mObserver); public void detach(Observer mObserver); public void notice(); }
建立Observer類:
/** * Observer(觀察者,Observer): * 爲那些在目標發生改變時須要得到通知的對象定義一個更新接口。 */ public interface Observer { public void update(); }
建立ConcreteSubject類:
/** * ConcreteSubject(具體目標,Teacher) * 將有關狀態存入各ConcreteObserve對象。 * 當他的狀態發生改變時,向他的各個觀察者發出通知。 */ public class Teacher implements Subject{ private String phone; private Vector students; public Teacher(){ phone = ""; students = new Vector(); } @Override public void attach(Observer mObserver) { students.add(mObserver); } @Override public void detach(Observer mObserver) { students.remove(mObserver); } @Override public void notice() { for(int i=0;i<students.size();i++){ ((Observer)students.get(i)).update(); } } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; notice(); } }
建立ConcreteObserver類:
/** * ConcreteObserver(具體觀察者, Student): * 維護一個指向ConcreteSubject對象的引用。 * 存儲有關狀態,這些狀態應與目標的狀態保持一致。 * 實現Observer的更新接口以使自身狀態與目標的狀態保持一致。 */ public class Student implements Observer{ private String name; private String phone; private Teacher mTeacher; public Student(String name,Teacher t){ this.name = name; mTeacher = t; } public void show(){ System.out.println("Name:"+name+"\nTeacher'sphone:" + phone); } @Override public void update() { phone = mTeacher.getPhone(); } }
客戶端測試:
/** * 觀察者(Observer)模式測試類 */ public class ObserverClient { public static void main(String[] args) { Vector students = new Vector(); Teacher t = new Teacher(); for(int i= 0;i<10;i++){ Student st = new Student("Andy.Chen"+i,t); students.add(st); t.attach(st); } System.out.println("Welcome to Andy.Chen Blog!" +"\n" +"Observer Patterns." +"\n" +"-------------------------------"); t.setPhone("12345678"); for(int i=0;i<3;i++) ((Student)students.get(i)).show(); t.setPhone("87654321"); for(int i=0;i<3;i++) ((Student)students.get(i)).show(); } }
程序運行結果以下:
Welcome to Andy.Chen Blog! Observer Patterns. ------------------------------- Name:Andy.Chen0 Teacher'sphone:12345678 Name:Andy.Chen1 Teacher'sphone:12345678 Name:Andy.Chen2 Teacher'sphone:12345678 Name:Andy.Chen0 Teacher'sphone:87654321 Name:Andy.Chen1 Teacher'sphone:87654321 Name:Andy.Chen2 Teacher'sphone:87654321
六、適配器(Adapter)模式
基本概念:適配器模式把一個類的接口變換成客戶端所期待的另外一種接口,從而使本來因接口不匹配而沒法在一塊兒工做的兩個類可以在一塊兒工做。
適配器模式的用途
用電器作例子,筆記本電腦的插頭通常都是三相的,即除了陽極、陰極外,還有一個地極。而有些地方的電源插座卻只有兩極,沒有地極。電源插座與筆記本電腦的電源插頭不匹配使得筆記本電腦沒法使用。這時候一個三相到兩相的轉換器(適配器)就能解決此問題,而這正像是本模式所作的事情。
適配器模式的結構
適配器模式有類的適配器模式
和對象的適配器模式
兩種不一樣的形式。
示例代碼:
public interface Target { /** * 這是源類Adaptee也有的方法 */ public void sampleOperation1(); /** * 這是源類Adapteee沒有的方法 */ public void sampleOperation2(); }
上面給出的是目標角色的源代碼,這個角色是以一個Java接口的形式實現的。能夠看出,這個接口聲明瞭兩個方法:sampleOperation1()和sampleOperation2()。而源角色Adaptee是一個具體類,它有一個sampleOperation1()方法,可是沒有sampleOperation2()方法。
public class Adaptee { public void sampleOperation1(){} }
適配器角色Adapter擴展了Adaptee,同時又實現了目標(Target)接口。因爲Adaptee沒有提供sampleOperation2()方法,而目標接口又要求這個方法,所以適配器角色Adapter實現了這個方法。
public class Adapter extends Adaptee implements Target { /** * 因爲源類Adaptee沒有方法sampleOperation2() * 所以適配器補充上這個方法 */ @Override public void sampleOperation2() { //寫相關的代碼 } }
對象適配器模式:
從上圖能夠看出,Adaptee類並無sampleOperation2()方法,而客戶端則期待這個方法。爲使客戶端可以使用Adaptee類,須要提供一個包裝(Wrapper)類Adapter。這個包裝類包裝了一個Adaptee的實例,從而此包裝類可以把Adaptee的API與Target類的API銜接起來。Adapter與Adaptee是委派關係,這決定了適配器模式是對象的。
示例代碼:
public interface Target { /** * 這是源類Adaptee也有的方法 */ public void sampleOperation1(); /** * 這是源類Adapteee沒有的方法 */ public void sampleOperation2(); } public class Adaptee { public void sampleOperation1(){} }
適配器類:
public class Adapter { private Adaptee adaptee; public Adapter(Adaptee adaptee){ this.adaptee = adaptee; } /** * 源類Adaptee有方法sampleOperation1 * 所以適配器類直接委派便可 */ public void sampleOperation1(){ this.adaptee.sampleOperation1(); } /** * 源類Adaptee沒有方法sampleOperation2 * 所以由適配器類須要補充此方法 */ public void sampleOperation2(){ //寫相關的代碼 } }
類適配器和對象適配器的權衡
對於類適配器因爲適配器直接繼承了Adaptee,使得適配器不能和Adaptee的子類一塊兒工做,由於繼承是靜態的關係,當適配器繼承了Adaptee後,就不可能再去處理 Adaptee的子類了。
對於對象適配器一個適配器能夠把多種不一樣的源適配到同一個目標。換言之,同一個適配器能夠把源類和它的子類都適配到目標接口。由於對象適配器採用的是對象組合的關係,只要對象類型正確,是否是子類都無所謂。
對於類適配器適配器能夠重定義Adaptee的部分行爲,至關於子類覆蓋父類的部分實現方法。
對於對象適配器要重定義Adaptee的行爲比較困難,這種狀況下,須要定義Adaptee的子類來實現重定義,而後讓適配器組合子類。雖然重定義Adaptee的行爲比較困難,可是想要增長一些新的行爲則方便的很,並且新增長的行爲可同時適用於全部的源。
對於類適配器,僅僅引入了一個對象,並不須要額外的引用來間接獲得Adaptee。
對於對象適配器,須要額外的引用來間接獲得Adaptee。
建議儘可能使用對象適配器的實現方式,多用合成或聚合、少用繼承。固然,具體問題具體分析,根據須要來選用實現方式,最適合的纔是最好的。
適配器模式的優勢
更好的複用性:系統須要使用現有的類,而此類的接口不符合系統的須要。那麼經過適配器模式就可讓這些功能獲得更好的複用。
更好的擴展性:在實現適配器功能的時候,能夠調用本身開發的功能,從而天然地擴展系統的功能。
適配器模式的缺點
過多的使用適配器,會讓系統很是零亂,不易總體進行把握。好比,明明看到調用的是A接口,其實內部被適配成了B接口的實現,一個系統若是太多出現這種狀況,無異於一場災難。所以若是不是頗有必要,能夠不使用適配器,而是直接對系統進行重構。
基本概念:爲其餘對象提供一種代理以控制對這個對象的訪問。也能夠說,在出發點到目的地之間有一道中間層,意爲代理。
爲何要使用
受權機制不一樣級別的用戶對同一對象擁有不一樣的訪問權利,如在論壇系統中,就使用Proxy進行受權機制控制,訪問論壇有兩種人:註冊用戶和遊客(未註冊用戶),論壇就經過相似ForumProxy這樣的代理來控制這兩種用戶對論壇的訪問權限。
某個客戶端不能直接操做到某個對象,但又必須和那個對象有所互動。
舉例兩個具體狀況:
總之原則是,對於開銷很大的對象,只有在使用它時才建立,這個原則能夠爲咱們節省不少寶貴的Java內存。因此,有些人認爲Java耗費資源內存,我覺得這和程序編制思路也有必定的關係。
如何使用??
以論壇系統爲例,訪問論壇系統的用戶有多種類型:註冊普通用戶、論壇管理者、系統管理者、遊客。註冊普通用戶才能發言,論壇管理者能夠管理他被受權的論壇,系統管理者能夠管理全部事務等,這些權限劃分和管理是使用Proxy完成的。
在Forum中陳列了有關論壇操做的主要行爲,如論壇名稱,論壇描述的獲取和修改,帖子發表刪除編輯等,在ForumPermissions中定義了各類級別權限的用戶:
public class ForumPermissions implements Cacheable { /** * Permission to read object. */ public static final int READ = 0; /** * Permission to administer the entire sytem. */ public static final int SYSTEM_ADMIN = 1; /** * Permission to administer a particular forum. */ public static final int FORUM_ADMIN = 2; /** * Permission to administer a particular user. */ public static final int USER_ADMIN = 3; /** * Permission to administer a particular group. */ public static final int GROUP_ADMIN = 4; /** * Permission to moderate threads. */ public static final int MODERATE_THREADS = 5; /** * Permission to create a new thread. */ public static final int CREATE_THREAD = 6; /** * Permission to create a new message. */ public static final int CREATE_MESSAGE = 7; /** * Permission to moderate messages. */ public static final int MODERATE_MESSAGES = 8; public boolean isSystemOrForumAdmin() { return (values[FORUM_ADMIN] || values[SYSTEM_ADMIN]); } //相關操做代碼 }
所以,Forum中各類操做權限是和ForumPermissions定義的用戶級別有關係的,做爲接口Forum的實現:ForumProxy正是將這種對應關係聯繫起來。好比,修改Forum的名稱,只有論壇管理者或系統管理者能夠修改,代碼以下:
public class ForumProxy implements Forum { private ForumPermissions permissions; private Forum forum; this.authorization = authorization; public ForumProxy(Forum forum, Authorization authorization,ForumPermissions permissions){ this.forum = forum; this.authorization = authorization; this.permissions = permissions; } ..... public void setName(String name) throws UnauthorizedException, ForumAlreadyExistsException{ //只有是系統或論壇管理者才能夠修更名稱 if (permissions.isSystemOrForumAdmin()) { forum.setName(name); } else { throw new UnauthorizedException(); } } ... }
而DbForum纔是接口Forum的真正實現,以修改論壇名稱爲例:
public class DbForum implements Forum, Cacheable { ... public void setName(String name) throws ForumAlreadyExistsException { .... this.name = name; //這裏真正將新名稱保存到數據庫中 saveToDb(); .... } ... }
凡是涉及到對論壇名稱修改這一事件,其餘程序都首先得和ForumProxy打交道,由ForumProxy決定是否有權限作某同樣事情,ForumProxy是個名副其實的"網關","安全代理系統"。
在平時應用中,無可避免總要涉及到系統的受權或安全體系,無論你有無心識的使用Proxy,實際你已經在使用Proxy了。
流程圖
基本概念:裝飾模式(Decorator),動態地給一個對象添加一些額外的職責,就增長功能來講,裝飾模式比生成子類更爲靈活。
UML結構圖:
上圖是Decorator 模式的結構圖,讓咱們能夠進行更方便的描述:
Component
是定義一個對象接口,能夠給這些對象動態地添加職責。
ConcreteComponent
是定義了一個具體的對象,也能夠給這個對象添加一些職責。
Decorator是裝飾抽象類,繼承了Component,從外類來擴展Component類的功能,但對於Component來講,是無需知道Decorator存在的。ConcreteDecorator就是具體的裝飾對象,起到給Component添加職責的功能。
如何使用??
假設情景:某人裝扮本身形象,穿衣服,褲子,鞋子,戴帽子等來把本身給包裝起來,須要把所需的功能按正確的順序串聯起來進行控制,咱們應該如何設計才能作到呢?以下,先看下代碼結構圖:
先建立一個接口類:Component.java
public interface Component { void show(); }
建立一個具體的 ConcreteComponent 來實現 Component 接口:Person.java
public class Person implements Component{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Person(String name){ this.name = name; } @Override public void show() { System.out.println("裝扮的" + name); } }
建立裝飾類 Decorator 實現 Component 接口
public class Decorator implements Component{ private Component mComponent; public void decoratorObj(Component component){ mComponent = component; } @Override public void show() { if(mComponent != null){ mComponent.show(); } } }
分別建立具體的裝飾類:Jeans.java , Pelisse.java, Sandal.java ...等等,分別繼承 Decorator.java 類
/** 牛仔褲 */ public class Jeans extends Decorator { @Override public void show(){ System.out.println("穿牛仔褲"); super.show(); } }
客戶端測試類
/** * 裝飾模式測試客戶端 */ public class DecoratorClient { public static void main(String[] args) { System.out.println("Welcome to Andy.Chen Blog!" +"\n" +"Decorator Patterns." +"\n"); Person mPerson = new Person("Andy"); Sandal mSandal = new Sandal(); Jeans mJeans = new Jeans(); TShirt mShirt = new TShirt(); mShirt.decoratorObj(mPerson); mJeans.decoratorObj(mShirt); mSandal.decoratorObj(mJeans); mSandal.show(); } }
測試結果
Welcome to Andy.Chen Blog! Decorator Patterns. 穿涼鞋 穿牛仔褲 穿T-Shirt 裝扮的Andy
總結
Decorator
模式有如下的優缺點:
比靜態繼承更靈活與對象的靜態繼承相比,Decorator模式提供了更加靈活的向對象添加職責的方式,可使用添加和分離的方法,用裝飾在運行時刻增長和刪除職責。使用繼承機制增長職責須要建立一個新的子類,若是須要爲原來全部的子類都添加功能的話,每一個子類都須要重寫,增長系統的複雜度,此外能夠爲一個特定的Component類提供多個Decorator,這種混合匹配是適用繼承很難作到的。
Decorator 與它的Component不同Decorator是一個透明的包裝,若是咱們從對象標識的觀點出發,一個被裝飾了的組件與這個組件是有差異的,所以使用裝飾時不該該以來對象標識。
產生許多小對象,採用Decorator模式進行系統設計每每會產生許多看上去相似的小對象,這些對象僅僅在他們相互鏈接的方式上有所不一樣。
1,http://www.cnblogs.com/forlina/archive/2011/06/21/2086114.html
2,http://www.cnblogs.com/java-my-life/archive/2012/04/13/2442795.html
3,http://blog.csdn.net/cjjky/article/details/7478788
4,http://blog.csdn.net/cjjky/article/details/7384951
5,http://blog.csdn.net/cjjky/article/details/7327200
6,https://www.cnblogs.com/pony1223/p/7608955.html