裝飾者模式java
Decorator模式(別名Wrapper):動態將職責附加到對象上,若要擴展功能,裝飾者提供了比繼承更具彈性的代替方案。編程
意圖:架構
動態地給一個對象添加一些額外的職責。就增長功能來講,Decorator模式相比生成子類更爲靈活。app
設計原則:less
1. 多用組合,少用繼承。ide
利用繼承設計子類的行爲,是在編譯時靜態決定的,並且全部的子類都會繼承到相同的行爲。然而,若是可以利用組合的作法擴展對象的行爲,就能夠在運行時動態地進行擴展。性能
2. 類應設計的對擴展開放,對修改關閉。測試
要點:this
1. 裝飾者和被裝飾對象有相同的超類型。設計
2. 能夠用一個或多個裝飾者包裝一個對象。
3. 裝飾者能夠在所委託被裝飾者的行爲以前或以後,加上本身的行爲,以達到特定的目的。
4. 對象能夠在任什麼時候候被裝飾,因此能夠在運行時動態的,不限量的用你喜歡的裝飾者來裝飾對象。
5. 裝飾模式中使用繼承的關鍵是想達到裝飾者和被裝飾對象的類型匹配,而不是得到其行爲。
6. 裝飾者通常對組件的客戶是透明的,除非客戶程序依賴於組件的具體類型。在實際項目中能夠根據須要爲裝飾者添加新的行爲,作到「半透明」裝飾者。
7. 適配器模式的用意是改變對象的接口而不必定改變對象的性能,而裝飾模式的用意是保持接口並增長對象的職責。
實現:
Component:
定義一個對象接口,能夠給這些對象動態地添加職責。
public interface Component { void operation(); }
Concrete Component:
定義一個對象,能夠給這個對象添加一些職責。
public class ConcreteComponent implements Component { public void operation() { // Write your code here } }
Decorator:
維持一個指向Component對象的引用,並定義一個與 Component接口一致的接口。
public class Decorator implements Component { public Decorator(Component component) { this.component = component; } public void operation() { component.operation(); } private Component component; }
Concrete Decorator:
在Concrete Component的行爲以前或以後,加上本身的行爲,以「貼上」附加的職責。
public class ConcreteDecorator extends Decorator { public void operation() { //addBehavior也能夠在前面 super.operation(); addBehavior(); } private void addBehavior() { //your code } }
模式的簡化:
1. 若是隻有一個Concrete Component類而沒有抽象的Component接口時,可讓Decorator繼承Concrete Component。
2. 若是隻有一個Concrete Decorator類時,能夠將Decorator和Concrete Decorator合併。
適用性:
如下狀況使用Decorator模式
1. 須要擴展一個類的功能,或給一個類添加附加職責。
2. 須要動態的給一個對象添加功能,這些功能能夠再動態的撤銷。
3. 須要增長由一些基本功能的排列組合而產生的很是大量的功能,從而使繼承關係變的不現實。
4. 當不能採用生成子類的方法進行擴充時。一種狀況是,可能有大量獨立的擴展,爲支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增加。另外一種狀況多是由於類定義被隱藏,或類定義不能用於生成子類。
優勢:
1. Decorator模式與繼承關係的目的都是要擴展對象的功能,可是Decorator能夠提供比繼承更多的靈活性。
2. 經過使用不一樣的具體裝飾類以及這些裝飾類的排列組合,設計師能夠創造出不少不一樣行爲的組合。
缺點:
1. 這種比繼承更加靈活機動的特性,也同時意味着更加多的複雜性。
2. 裝飾模式會致使設計中出現許多小類,若是過分使用,會使程序變得很複雜。
3. 裝飾模式是針對抽象組件(Component)類型編程。可是,若是你要針對具體組件編程時,就應該從新思考你的應用架構,以及裝飾者是否合適。固然也能夠改變Component接口,增長新的公開的行爲,實現「半透明」的裝飾者模式。在實際項目中要作出最佳選擇。
裝飾模式在Java I/O庫中的應用:
編寫一個裝飾者把全部的輸入流內的大寫字符轉化成小寫字符:
import java.io.FilterInputStream;import java.io.IOException;import java.io.InputStream;public class LowerCaseInputStream extends FilterInputStream { protected LowerCaseInputStream(InputStream in) { super(in); } @Override public int read() throws IOException { int c = super.read(); return (c == -1 ? c : Character.toLowerCase((char) c)); } @Override public int read(byte[] b, int offset, int len) throws IOException { int result = super.read(b, offset, len); for (int i = offset; i < offset + result; i++) { b[i] = (byte) Character.toLowerCase((char) b[i]); } return result; } }
測試咱們的裝飾者類:
import java.io.*;public class InputTest { public static void main(String[] args) throws IOException { int c; try { InputStream in = new LowerCaseInputStream(new BufferedInputStream( new FileInputStream("D:\\test.txt"))); while ((c = in.read()) >= 0) { System.out.print((char) c); } in.close(); } catch (IOException e) { e.printStackTrace(); } } }