decorator是一個滿常使用的方式,只要透過裝飾,就能很容易新增一個功能,然而被裝飾者,完全不必知道裝飾者的存在,減少耦合性。
例如今天有一個Canvas,要將文字畫在canvas上,並且加上邊框,文字並不需要知道邊框存不存在,這時就可以使用decorator附加上去。
Example:
首先簡單定義一個canvas,draw會先將內容寫在變數裡,然後在由show將結果顯示在terminal上面。
class Canvas( object ): """ Define a sample canvas for terminal. """ def __init__( self, width=15, height=5 ): """ Init a params. """ self.__data = [] self.__width = width self.__height = height self.__setup( width, height ) def __setup( self, width, height ): """ Create a data block. """ for hi in range( height ): self.__data.append( [] ) for wi in range( width ): self.__data[ hi ].append( " " ) def draw( self, content, x, y ): """ Draw content to data block. """ width = self.__width for char in content: if x >= width: break self.__data[y][x] = char x = x + 1 def show( self ): """ Print to terminal. """ for hi in range( self.__height ): print "".join( self.__data[ hi ] )
接著View定義了基本的位置,和width計算,在由drawTo繪製到canvas。
class View( object ): """ Define a sample view. """ def setY( self, y ): """ Set a position of y. """ self._y = y def getY( self ): """ Get a position of y. """ return self._y def setX( self, x ): """ Set a position of x. """ self._x = x def getX( self ): """ Get a position of x. """ return self._x def getWidth( self ): """ Get the view width. """ return 0 def drawTo( self, canvas, parent = None ): """ Draw something to canvas. """ pass
定義一個decorator,讓border裝飾。
class ViewDecorator( object ): """ Decorator of View. """ def __init__( self, *views ): self.__views = views def __call__( self, drawTo ): views = self.__views; def draw_chain( base_view, canvas ): drawTo( base_view, canvas ) for view in views: view.drawTo( canvas, base_view ) return draw_chain
Text和border分別繼承於View,text會將文字畫到canvas,而border則是畫框([]),此時可以看到text已經裝飾了border "@ViewDecorator``( Border() )"
。
class Border( View ): """ Extend a View. """ def drawTo( self, canvas, parent = None ): """ Draw a border to canvas by parent position. """ if parent: width = parent.getWidth() x = parent.getX() y = parent.getY() canvas.draw( "[", x - 1 , y ) canvas.draw( "]", width + x , y ) class Text( View ): """ Extend a view. """ def __init__( self, content ): """ Set a text. """ self.__content = content def getWidth( self ): """ Get a width of text. """ return len( self.__content ) @ViewDecorator( Border() ) def drawTo( self, canvas, parent = None ): """ Draw a text to canvas. """ canvas.draw( self.__content, self.getX(), self.getY() )
執行python decorator.py
canvas = Canvas() text = Text( "Sparrow" ) text.setX( 3 ) text.setY( 2 ) text.drawTo( canvas ) canvas.show()
最後就會顯示下列資訊在螢幕上。
[Sparrow]