標籤:
裝飾者模式定義 動態地將責任附加到對象上。若要擴充功能,裝飾者提供比繼承更有彈性的替代方案
實作類別圖
裝飾者模式的特點
A 裝飾者和被裝飾對象有相同的超類型。(注意這是利用繼承達到”類型匹配“,而不是利用繼承獲得”行為“,行為來自裝飾者和基礎組件,或者與其他裝飾者之間的組合關係)
B 可以用一個或多個裝飾者封裝一個對象。
C 因為裝飾者和被裝飾者具有相同的類型,所以任何需要原始對象的場合,可以用裝飾過的對象代替。
D 裝飾者可以在所委託被裝飾者的行為之前與/或之後,加上自己的行為,以達到特定的目的。
E 對象可以在任何時候被裝飾,所以可以在運行時動態地、不限量地用你喜歡的裝飾者來裝飾對象
裝飾者模式實現例子
interface Widget { void draw(); } // 1. "lowest common denominator"class TextField implements Widget { // 3. "Core" class with "isa" rel private int width, height; public TextField( int w, int h ) { width = w; height = h; } public void draw() { System.out.println( "TextField: " + width + ", " + height );} } // 2. Second level base classabstract class Decorator implements Widget { // with "isa" relationship private Widget wid; // 4. "hasa" relationship public Decorator( Widget w ) { wid = w; } public void draw() { wid.draw(); } // 5. Delegation}class BorderDecorator extends Decorator { // 6. Optional embellishment public BorderDecorator( Widget w ) { super( w ); } public void draw() { super.draw(); // 7. Delegate to base class System.out.println( " BorderDecorator" ); // and add extra stuff} }class ScrollDecorator extends Decorator { // 6. Optional embellishment public ScrollDecorator( Widget w ) { super( w ); } public void draw() { super.draw(); // 7. Delegate to base class System.out.println( " ScrollDecorator" ); // and add extra stuff} }//裝飾者可以在所委託被裝飾者的行為之前或者之後,加上自己的行為,以達到特定的目的public class DecoratorDemo { public static void main( String[] args ) { // 8. Client has the responsibility to compose desired configurations Widget aWidget = new BorderDecorator( new BorderDecorator( new ScrollDecorator( new TextField( 80, 24 )))); aWidget.draw();} }
輸出結果為:TextField: 80, 24
ScrollDecorator
BorderDecorator
BorderDecorator
對比python裝飾模式實現的一個類似程式
def bread(func): def wrapper(): print "</''''''\>" func() print "<\______/>" return wrapperdef ingredients(func): def wrapper(): print "#tomatoes#" func() print "~salad~" return wrapper@bread@ingredientsdef sandwich(food="--ham--"): print foodif (__name__=="__main__"): sandwich()
JAVA I/O類 就是利用裝飾者模式來實現諸多的讀取方式,InputStream是裝飾者中的抽象組件。FilterInputStream是一個抽象裝飾者,LIneNumberInputStream是一個具體裝飾者,加上了計算行數的能力,BufferInputStream是一個加上緩衝輸入功能和readline()方法的具體裝飾者
下面一個例子是編寫自己的Java I./O裝飾器,把輸入資料流內所有的大寫字元轉換成小寫
import java.io.*;class LowerCaseInputStream extends FilterInputStream{public LowerCaseInputStream (InputStream in) {super(in);}//必須實現兩個read方法 一個針對位元組 一個針對位元組數組public int read() throws IOException {int c = super.read();return (c == -1 ? c : Character.toLowerCase((char) (c)));}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;}}public class InputTest {public static void main(String[] args) {int c;try{InputStream in = new LowerCaseInputStream(new BufferedInputStream(new FileInputStream("test.txt") ) );while((c = in.read() ) >= 0) {System.out.print((char)c);}in.close();}catch (IOException e){e.printStackTrace();}}
設計模式-Python Java裝飾者模式