Python class decorators for classes

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]

source code

Factory pattern for javascript

在提到factory pattern之前,讓我們先來理解一些基本的概念。

當javascript的private變數必須以var定義,反之沒加var則為global變數。而由function建立的object,裡面的this將會指向物件本身,同時也是public的屬性。一般prototype與this定義的function有一個很大差異,由this定義的function,每個function都是獨立的,簡單來說都佔由實體空間,而由prototype定義的,則是多個物件共用同一個資源。

以下是一個簡單的factory pattern
/**
* @name Car
* @class
* @constructor
* @see carFactory
*/

/** @namespace */
var carFactory = (function(){
    var _count = 0;

    /**
    * @lends Car
    * @inner
    */
    function Car(){
        //private
        var _color = "black";
        var _doors = "4";

        /**
        * @public
        * @param {String} color
        */
        this.setColor = function(color){
            _color = color;
        }

        /**
        * @type {String}
        */
        this.getColor = function(){
            return _color;
        }

        /**
        * @type int
        */
        this.getDoorTotal = function(){
            return _doors;
        }

    }

    /**
    * Show this car info.
    */
    Car.prototype.show = function(){

        console.log("color:"+this.getColor());
        console.log("door total:"+this.getDoorTotal());
    }

    /**
    * @lends carFactory
    */
    return {
        /**
        * @type Car
        * @memberOf carFactory
        */
        create:function(){
            _count++;
            return new Car();
        },
        /** @memberOf carFactory */
        getCount:function(){
            return _count;
        }
    };
})();

首先我們定義了一個carFactory物件,裡面有個內部class名稱為Car,分別定義了setColor、getColor、getDoorTotal、show四個function。接著再由carFactory的create,將car object export出去,而getCount則是計算了建立car object的total。

最後是實際使用的code:
var car1 = carFactory.create();
    car1.setColor("blue");
    car1.show();
var car2 = carFactory.create();
    car2.setColor("gray");
    car2.show();
var car3 = carFactory.create();
    car3.show();

    console.log("car total:"+carFactory.getCount());

result: