軟件常見設計模式


1.創建型模式

單例模式

單例模式(Singleton Pattern)是一種常用的軟件設計模式,該模式的主要目的是確保某一個類只有一個實例存在。當你希望在整個系統中,某個類只能出現一個實例時,單例對象就能派上用場。

比如,某個服務器程序的配置信息存放在一個文件中,客戶端通過一個 AppConfig 的類來讀取配置文件的信息。如果在程序運行期間,有很多地方都需要使用配置文件的內容,也就是說,很多地方都需要創建 AppConfig 對象的實例,這就導致系統中存在多個 AppConfig 的實例對象,而這樣會嚴重浪費內存資源,尤其是在配置文件內容很多的情況下。事實上,類似 AppConfig 這樣的類,我們希望在程序運行期間只存在一個實例對象

復制代碼
 1 class Singleton(object):
 2     def __init__(self):
 3         pass
 4 
 5     def __new__(cls, *args, **kwargs):
 6         if not hasattr(Singleton, "_instance"): # 反射
 7             Singleton._instance = object.__new__(cls)
 8         return Singleton._instance
 9 
10 obj1 = Singleton()
11 obj2 = Singleton()
12 print(obj1, obj2) #<__main__.Singleton object at 0x004415F0> <__main__.Singleton object at 0x004415F0>
復制代碼
復制代碼
 1 class Singleton(object):
 2     def __init__(self):
 3         pass
 4 
 5     def __new__(cls, *args, **kwargs):
 6         if not hasattr(Singleton, "_instance"): # 反射
 7             Singleton._instance = object.__new__(cls)
 8         return Singleton._instance
 9 
10 obj1 = Singleton()
11 obj2 = Singleton()
12 print(obj1, obj2) #<__main__.Singleton object at 0x004415F0> <__main__.Singleton object at 0x004415F0>
復制代碼

 

工廠模式

工廠模式是一個在軟件開發中用來創建對象的設計模式。

工廠模式包涵一個超類。這個超類提供一個抽象化的接口來創建一個特定類型的對象,而不是決定哪個對象可以被創建。

為了實現此方法,需要創建一個工廠類創建並返回。 

當程序運行輸入一個“類型”的時候,需要創建於此相應的對象。這就用到了工廠模式。在如此情形中,實現代碼基於工廠模式,可以達到可擴展,可維護的代碼。當增加一個新的類型,不在需要修改已存在的類,只增加能夠產生新類型的子類。

簡短的說,當以下情形可以使用工廠模式:

1.不知道用戶想要創建什么樣的對象

2.當你想要創建一個可擴展的關聯在創建類與支持創建對象的類之間。

一個例子更能很好的理解以上的內容:

  1. 我們有一個基類Person ,包涵獲取名字,性別的方法 。有兩個子類male 和female,可以打招呼。還有一個工廠類。
  2.  工廠類有一個方法名getPerson有兩個輸入參數,名字和性別。
  3.  用戶使用工廠類,通過調用getPerson方法。

在程序運行期間,用戶傳遞性別給工廠,工廠創建一個與性別有關的對象。因此工廠類在運行期,決定了哪個對象應該被創建

class Person:
    def __init__(self):
        self.name = None
        self.gender = None

    def getName(self):
        return self.name

    def getGender(self):
        return self.gender

class Male(Person):
    def __init__(self, name):
        print "Hello Mr." + name

class Female(Person):
    def __init__(self, name):
        print "Hello Miss." + name

class Factory:
    def getPerson(self, name, gender):
        if gender == ‘M':
                return Male(name)
        if gender == 'F':
            return Female(name)


if __name__ == '__main__':
    factory = Factory()
    person = factory.getPerson("Chetan", "M")

 

復制代碼
class Person:
    def __init__(self):
        self.name = None
        self.gender = None

    def getName(self):
        return self.name

    def getGender(self):
        return self.gender

class Male(Person):
    def __init__(self, name):
        print "Hello Mr." + name

class Female(Person):
    def __init__(self, name):
        print "Hello Miss." + name

class Factory:
    def getPerson(self, name, gender):
        if gender == ‘M':
                return Male(name)
        if gender == 'F':
            return Female(name)


if __name__ == '__main__':
    factory = Factory()
    person = factory.getPerson("Chetan", "M")
復制代碼

建造者模式

將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。

相關模式:思路和模板方法模式很像,模板方法是封裝算法流程,對某些細節,提供接口由子類修改,建造者模式更為高層一點,將所有細節都交由子類實現

一個例子更能很好的理解以上的內容:

1. 有一個接口類,定義創建對象的方法。一個指揮員類,接受創造者對象為參數。兩個創造者類,創建對象方法相同,內部創建可自定義

2.一個指揮員,兩個創造者(瘦子 胖子),指揮員可以指定由哪個創造者來創造

from abc import ABCMeta, abstractmethod


class Builder():
    __metaclass__ = ABCMeta

    @abstractmethod
    def draw_left_arm(self):
        pass

    @abstractmethod
    def draw_right_arm(self):
        pass

    @abstractmethod
    def draw_left_foot(self):
        pass

    @abstractmethod
    def draw_right_foot(self):
        pass

    @abstractmethod
    def draw_head(self):
        pass

    @abstractmethod
    def draw_body(self):
        pass


class Thin(Builder):
    def draw_left_arm(self):
        print '畫左手'

    def draw_right_arm(self):
        print '畫右手'

    def draw_left_foot(self):
        print '畫左腳'

    def draw_right_foot(self):
        print '畫右腳'

    def draw_head(self):
        print '畫頭'

    def draw_body(self):
        print '畫瘦身體'


class Fat(Builder):
    def draw_left_arm(self):
        print '畫左手'

    def draw_right_arm(self):
        print '畫右手'

    def draw_left_foot(self):
        print '畫左腳'

    def draw_right_foot(self):
        print '畫右腳'

    def draw_head(self):
        print '畫頭'

    def draw_body(self):
        print '畫胖身體'


class Director():
    def __init__(self, person):
        self.person=person

    def draw(self):
        self.person.draw_left_arm()
        self.person.draw_right_arm()
        self.person.draw_left_foot()
        self.person.draw_right_foot()
        self.person.draw_head()
        self.person.draw_body()


if __name__=='__main__':
    thin=Thin()
    fat=Fat()
    director_thin=Director(thin)
    director_thin.draw()
    director_fat=Director(fat)
    director_fat.draw()
復制代碼
from abc import ABCMeta, abstractmethod


class Builder():
    __metaclass__ = ABCMeta

    @abstractmethod
    def draw_left_arm(self):
        pass

    @abstractmethod
    def draw_right_arm(self):
        pass

    @abstractmethod
    def draw_left_foot(self):
        pass

    @abstractmethod
    def draw_right_foot(self):
        pass

    @abstractmethod
    def draw_head(self):
        pass

    @abstractmethod
    def draw_body(self):
        pass


class Thin(Builder):
    def draw_left_arm(self):
        print '畫左手'

    def draw_right_arm(self):
        print '畫右手'

    def draw_left_foot(self):
        print '畫左腳'

    def draw_right_foot(self):
        print '畫右腳'

    def draw_head(self):
        print '畫頭'

    def draw_body(self):
        print '畫瘦身體'


class Fat(Builder):
    def draw_left_arm(self):
        print '畫左手'

    def draw_right_arm(self):
        print '畫右手'

    def draw_left_foot(self):
        print '畫左腳'

    def draw_right_foot(self):
        print '畫右腳'

    def draw_head(self):
        print '畫頭'

    def draw_body(self):
        print '畫胖身體'


class Director():
    def __init__(self, person):
        self.person=person

    def draw(self):
        self.person.draw_left_arm()
        self.person.draw_right_arm()
        self.person.draw_left_foot()
        self.person.draw_right_foot()
        self.person.draw_head()
        self.person.draw_body()


if __name__=='__main__':
    thin=Thin()
    fat=Fat()
    director_thin=Director(thin)
    director_thin.draw()
    director_fat=Director(fat)
    director_fat.draw()
復制代碼

 

 

原型模式

 

原型模式

用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。
原型模式本質就是克隆對象,所以在對象初始化操作比較復雜的情況下,很實用,能大大降低耗時,提高性能,因為“不用重新初始化對象,而是動態地獲得對象運行時的狀態”。

淺拷貝(Shallow Copy):指對象的字段被拷貝,而字段引用的對象不會被拷貝,拷貝的對象和源對象只是名稱相同,但是他們共用一個實體。
深拷貝(deep copy):對對象實例中字段引用的對象也進行拷貝。

import copy
from collections import OrderedDict


class Book:
    def __init__(self, name, authors, price, **rest):
        '''rest的例子有:出版商、長度、標簽、出版日期'''
        self.name = name
        self.authors = authors
        self.price = price  # 單位為美元
        self.__dict__.update(rest)

    def __str__(self):
        mylist = []
        ordered = OrderedDict(sorted(self.__dict__.items()))
        for i in ordered.keys():
            mylist.append('{}: {}'.format(i, ordered[i]))
            if i == 'price':
                mylist.append('$')
            mylist.append('\n')
            return ''.join(mylist)


class Prototype:
    def __init__(self):
        self.objects = dict()

    def register(self, identifier, obj):
        self.objects[identifier] = obj

    def unregister(self, identifier):
        del self.objects[identifier]

    def clone(self, identifier, **attr):
        found = self.objects.get(identifier)
        if not found:
            raise ValueError('Incorrect object identifier: {}'.format(identifier))
        obj = copy.deepcopy(found)
        obj.__dict__.update(attr)
        return obj


def main():
    b1 = Book('The C Programming Language', ('Brian W. Kernighan', 'Dennis M.Ritchie'),
              price=118, publisher='Prentice Hall', length=228, publication_date='1978-02-22',
              tags=('C', 'programming', 'algorithms', 'data structures'))
    prototype = Prototype()
    cid = 'k&r-first'
    prototype.register(cid, b1)
    b2 = prototype.clone(cid, name='The C Programming Language(ANSI)', price=48.99,
                         length=274, publication_date='1988-04-01', edition=2)
    for i in (b1, b2):
        print(i)
    print("ID b1 : {} != ID b2 : {}".format(id(b1), id(b2)))


if __name__ == '__main__':
    main()

"""
>>> python3 prototype.py
authors: ('Brian W. Kernighan', 'Dennis M. Ritchie')
length: 228
name: The C Programming Language
price: 118$
publication_date: 1978-02-22
publisher: Prentice Hall
tags: ('C', 'programming', 'algorithms', 'data structures')


authors: ('Brian W. Kernighan', 'Dennis M. Ritchie')
edition: 2
length: 274
name: The C Programming Language (ANSI)
price: 48.99$
publication_date: 1988-04-01
publisher: Prentice Hall
tags: ('C', 'programming', 'algorithms', 'data structures')

ID b1 : 140004970829304 != ID b2 : 140004970829472
"""
復制代碼
import copy
from collections import OrderedDict


class Book:
    def __init__(self, name, authors, price, **rest):
        '''rest的例子有:出版商、長度、標簽、出版日期'''
        self.name = name
        self.authors = authors
        self.price = price  # 單位為美元
        self.__dict__.update(rest)

    def __str__(self):
        mylist = []
        ordered = OrderedDict(sorted(self.__dict__.items()))
        for i in ordered.keys():
            mylist.append('{}: {}'.format(i, ordered[i]))
            if i == 'price':
                mylist.append('$')
            mylist.append('\n')
            return ''.join(mylist)


class Prototype:
    def __init__(self):
        self.objects = dict()

    def register(self, identifier, obj):
        self.objects[identifier] = obj

    def unregister(self, identifier):
        del self.objects[identifier]

    def clone(self, identifier, **attr):
        found = self.objects.get(identifier)
        if not found:
            raise ValueError('Incorrect object identifier: {}'.format(identifier))
        obj = copy.deepcopy(found)
        obj.__dict__.update(attr)
        return obj


def main():
    b1 = Book('The C Programming Language', ('Brian W. Kernighan', 'Dennis M.Ritchie'),
              price=118, publisher='Prentice Hall', length=228, publication_date='1978-02-22',
              tags=('C', 'programming', 'algorithms', 'data structures'))
    prototype = Prototype()
    cid = 'k&r-first'
    prototype.register(cid, b1)
    b2 = prototype.clone(cid, name='The C Programming Language(ANSI)', price=48.99,
                         length=274, publication_date='1988-04-01', edition=2)
    for i in (b1, b2):
        print(i)
    print("ID b1 : {} != ID b2 : {}".format(id(b1), id(b2)))


if __name__ == '__main__':
    main()

"""
>>> python3 prototype.py
authors: ('Brian W. Kernighan', 'Dennis M. Ritchie')
length: 228
name: The C Programming Language
price: 118$
publication_date: 1978-02-22
publisher: Prentice Hall
tags: ('C', 'programming', 'algorithms', 'data structures')


authors: ('Brian W. Kernighan', 'Dennis M. Ritchie')
edition: 2
length: 274
name: The C Programming Language (ANSI)
price: 48.99$
publication_date: 1988-04-01
publisher: Prentice Hall
tags: ('C', 'programming', 'algorithms', 'data structures')

ID b1 : 140004970829304 != ID b2 : 140004970829472
"""
復制代碼

 

 

2.結構型模式

適配器模式

所謂適配器模式是指是一種接口適配技術,它可通過某個類來使用另一個接口與之不兼容的類,運用此模式,兩個類的接口都無需改動。

適配器模式主要應用於希望復用一些現存的類,但是接口又與復用環境要求不一致的情況,比如在需要對早期代碼復用一些功能等應用上很有實際價值。

解釋二:

適配器模式(Adapter Pattern):將一個類的接口轉換成為客戶希望的另外一個接口.Adapter Pattern使得原本由於接口不兼容而不能一起工作的那些類可以一起工作.
應用場景:系統數據和行為都正確,但接口不符合時,目的是使控制范圍之外的一個原有對象與某個接口匹配,適配器模式主要應用於希望復用一些現存的類,但接口又與復用環境不一致的情況

適配器模式

class Target(object):
    def request(self):
        print "普通請求"

class Adaptee(object):

    def specific_request(self):
        print "特殊請求"

class Adapter(Target):

    def __init__(self):
        self.adaptee = Adaptee()

    def request(self):
        self.adaptee.specific_request()

if __name__ == "__main__":
    target = Adapter()
    target.request()
復制代碼
class Target(object):
    def request(self):
        print "普通請求"

class Adaptee(object):

    def specific_request(self):
        print "特殊請求"

class Adapter(Target):

    def __init__(self):
        self.adaptee = Adaptee()

    def request(self):
        self.adaptee.specific_request()

if __name__ == "__main__":
    target = Adapter()
    target.request()
復制代碼

 

修飾器模式

該模式雖名為修飾器,但這並不意味着它應該只用於讓產品看起來更漂亮。修飾器模式通常用於擴展一個對象的功能。這類擴展的實際例子有,給槍加一個消音器、使用不同的照相機鏡頭

import functools
def memoize(fn):
    known = dict()
    @functools.wraps(fn)
    def memoizer(*args):
        if args not in known:
            known[args] = fn(*args)
        return known[args]
    return memoizer
@memoize
def nsum(n):
    '''返回前n個數字的和'''
    assert(n >= 0), 'n must be >= 0'
    return 0 if n == 0 else n + nsum(n-1)
@memoize
def fibonacci(n):
    '''返回斐波那契數列的第n個數'''
    assert(n >= 0), 'n must be >= 0'
    return n if n in (0, 1) else fibonacci(n-1) + fibonacci(n-2)
if __name__ == '__main__':
    from timeit import Timer
    measure = [ {'exec':'fibonacci(100)', 'import':'fibonacci',
    'func':fibonacci},{'exec':'nsum(200)', 'import':'nsum',
    'func':nsum} ]
    for m in measure:
        t = Timer('{}'.format(m['exec']), 'from __main__ import{}'.format(m['import']))
        print('name: {}, doc: {}, executing: {}, time:{}'.format(m['func'].__name__, m['func'].__doc__,m['exec'], t.timeit()))

"""
>>> python3 mymath.py
name: fibonacci, doc: Returns the nth number of the Fibonacci
sequence, executing: fibonacci(100), time: 0.4169441329995607
name: nsum, doc: Returns the sum of the first n numbers,
executing: nsum(200), time: 0.4160157349997462
"""
復制代碼
import functools
def memoize(fn):
    known = dict()
    @functools.wraps(fn)
    def memoizer(*args):
        if args not in known:
            known[args] = fn(*args)
        return known[args]
    return memoizer
@memoize
def nsum(n):
    '''返回前n個數字的和'''
    assert(n >= 0), 'n must be >= 0'
    return 0 if n == 0 else n + nsum(n-1)
@memoize
def fibonacci(n):
    '''返回斐波那契數列的第n個數'''
    assert(n >= 0), 'n must be >= 0'
    return n if n in (0, 1) else fibonacci(n-1) + fibonacci(n-2)
if __name__ == '__main__':
    from timeit import Timer
    measure = [ {'exec':'fibonacci(100)', 'import':'fibonacci',
    'func':fibonacci},{'exec':'nsum(200)', 'import':'nsum',
    'func':nsum} ]
    for m in measure:
        t = Timer('{}'.format(m['exec']), 'from __main__ import{}'.format(m['import']))
        print('name: {}, doc: {}, executing: {}, time:{}'.format(m['func'].__name__, m['func'].__doc__,m['exec'], t.timeit()))

"""
>>> python3 mymath.py
name: fibonacci, doc: Returns the nth number of the Fibonacci
sequence, executing: fibonacci(100), time: 0.4169441329995607
name: nsum, doc: Returns the sum of the first n numbers,
executing: nsum(200), time: 0.4160157349997462
"""
復制代碼

 

 

外觀模式

外觀模式又叫做門面模式。在面向對象程序設計中,解耦是一種推崇的理念。但事實上由於某些系統中過於復雜,從而增加了客戶端與子系統之間的耦合度。例如:在家觀看多媒體影院時,更希望按下一個按鈕就能實現影碟機,電視,音響的協同工作,而不是說每個機器都要操作一遍。這種情況下可以采用外觀模式,即引入一個類對子系統進行包裝,讓客戶端與其進行交互。

外觀模式(Facade Pattern):外部與一個子系統的通信必須通過一個統一的外觀對象進行,為子系統中的一組接口提供一個一致的界面,外觀模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。外觀模式又稱為門面模式,它是一種對象結構型模式。

from enum import Enum
from abc import ABCMeta, abstractmethod

State = Enum('State', 'new running sleeping restart zombie')


class User:
    pass


class Process:
    pass


class File:
    pass


class Server(metaclass=ABCMeta):
    @abstractmethod
    def __init__(self):
        pass

    def __str__(self):
        return self.name

    @abstractmethod
    def boot(self):
        pass

    @abstractmethod
    def kill(self, restart=True):
        pass


class FileServer(Server):
    def __init__(self):
        '''初始化文件服務進程要求的操作'''
        self.name = 'FileServer'
        self.state = State.new

    def boot(self):
        print('booting the {}'.format(self))
        '''啟動文件服務進程要求的操作'''
        self.state = State.running

    def kill(self, restart=True):
        print('Killing {}'.format(self))
        '''終止文件服務進程要求的操作'''
        self.state = State.restart if restart else State.zombie

    def create_file(self, user, name, permissions):
        '''檢查訪問權限的有效性、用戶權限等'''
        print("trying to create the file '{}' for user '{}' with permissions{}".format(name, user, permissions))


class ProcessServer(Server):
    def __init__(self):
        '''初始化進程服務進程要求的操作'''
        self.name = 'ProcessServer'
        self.state = State.new

    def boot(self):
        print('booting the {}'.format(self))
        '''啟動進程服務進程要求的操作'''
        self.state = State.running

    def kill(self, restart=True):
        print('Killing {}'.format(self))
        '''終止進程服務進程要求的操作'''
        self.state = State.restart if restart else State.zombie

    def create_process(self, user, name):
        '''檢查用戶權限和生成PID等'''
        print("trying to create the process '{}' for user '{}'".format(name, user))


class WindowServer:
    pass


class NetworkServer:
    pass


class OperatingSystem:
    '''外觀'''

    def __init__(self):
        self.fs = FileServer()
        self.ps = ProcessServer()

    def start(self):
        [i.boot() for i in (self.fs, self.ps)]

    def create_file(self, user, name, permissions):
        return self.fs.create_file(user, name, permissions)

    def create_process(self, user, name):
        return self.ps.create_process(user, name)


def main():
    os = OperatingSystem()
    os.start()
    os.create_file('foo', 'hello', '-rw-r-r')
    os.create_process('bar', 'ls /tmp')


if __name__ == '__main__':
    main()

"""
booting the FileServer
booting the ProcessServer
trying to create the file 'hello' for user 'foo' with permissions-rw-r-r
trying to create the process 'ls /tmp' for user 'bar'
"""
復制代碼
from enum import Enum
from abc import ABCMeta, abstractmethod

State = Enum('State', 'new running sleeping restart zombie')


class User:
    pass


class Process:
    pass


class File:
    pass


class Server(metaclass=ABCMeta):
    @abstractmethod
    def __init__(self):
        pass

    def __str__(self):
        return self.name

    @abstractmethod
    def boot(self):
        pass

    @abstractmethod
    def kill(self, restart=True):
        pass


class FileServer(Server):
    def __init__(self):
        '''初始化文件服務進程要求的操作'''
        self.name = 'FileServer'
        self.state = State.new

    def boot(self):
        print('booting the {}'.format(self))
        '''啟動文件服務進程要求的操作'''
        self.state = State.running

    def kill(self, restart=True):
        print('Killing {}'.format(self))
        '''終止文件服務進程要求的操作'''
        self.state = State.restart if restart else State.zombie

    def create_file(self, user, name, permissions):
        '''檢查訪問權限的有效性、用戶權限等'''
        print("trying to create the file '{}' for user '{}' with permissions{}".format(name, user, permissions))


class ProcessServer(Server):
    def __init__(self):
        '''初始化進程服務進程要求的操作'''
        self.name = 'ProcessServer'
        self.state = State.new

    def boot(self):
        print('booting the {}'.format(self))
        '''啟動進程服務進程要求的操作'''
        self.state = State.running

    def kill(self, restart=True):
        print('Killing {}'.format(self))
        '''終止進程服務進程要求的操作'''
        self.state = State.restart if restart else State.zombie

    def create_process(self, user, name):
        '''檢查用戶權限和生成PID等'''
        print("trying to create the process '{}' for user '{}'".format(name, user))


class WindowServer:
    pass


class NetworkServer:
    pass


class OperatingSystem:
    '''外觀'''

    def __init__(self):
        self.fs = FileServer()
        self.ps = ProcessServer()

    def start(self):
        [i.boot() for i in (self.fs, self.ps)]

    def create_file(self, user, name, permissions):
        return self.fs.create_file(user, name, permissions)

    def create_process(self, user, name):
        return self.ps.create_process(user, name)


def main():
    os = OperatingSystem()
    os.start()
    os.create_file('foo', 'hello', '-rw-r-r')
    os.create_process('bar', 'ls /tmp')


if __name__ == '__main__':
    main()

"""
booting the FileServer
booting the ProcessServer
trying to create the file 'hello' for user 'foo' with permissions-rw-r-r
trying to create the process 'ls /tmp' for user 'bar'
"""
復制代碼

 

享元模式

運用共享技術有效地支持大量細粒度的對象。
內部狀態:享元對象中不會隨環境改變而改變的共享部分。比如圍棋棋子的顏色。
外部狀態:隨環境改變而改變、不可以共享的狀態就是外部狀態。比如圍棋棋子的位置。

應用場景:程序中使用了大量的對象,如果刪除對象的外部狀態,可以用相對較少的共享對象取代很多組對象,就可以考慮使用享元模式。

1 import random
2 from enum import Enum
3 TreeType = Enum('TreeType', 'apple_tree cherry_tree peach_tree')
4
5 class Tree:
6 pool = dict()
7 def __new__(cls, tree_type):
8 obj = cls.pool.get(tree_type, None)
9 if not obj:
10 obj = object.__new__(cls)
11 cls.pool[tree_type] = obj
12 obj.tree_type = tree_type
13 return obj
14
15 def render(self, age, x, y):
16 print('render a tree of type {} and age {} at ({}, {})'.format(self.tree_type, age, x, y))
17
18
19 def main():
20 rnd = random.Random()
21 age_min, age_max = 1, 30 # 單位為年
22 min_point, max_point = 0, 100
23 tree_counter = 0
24 for _ in range(10):
25 t1 = Tree(TreeType.apple_tree)
26 t1.render(rnd.randint(age_min, age_max),
27 rnd.randint(min_point, max_point),
28 rnd.randint(min_point, max_point))
29 tree_counter += 1
30 for _ in range(3):
31 t2 = Tree(TreeType.cherry_tree)
32 t2.render(rnd.randint(age_min, age_max),
33 rnd.randint(min_point, max_point),
34 rnd.randint(min_point, max_point))
35 tree_counter += 1
36 for _ in range(5):
37 t3 = Tree(TreeType.peach_tree)
38 t3.render(rnd.randint(age_min, age_max),
39 rnd.randint(min_point, max_point),
40 rnd.randint(min_point, max_point))
41 tree_counter += 1
42
43 print('trees rendered: {}'.format(tree_counter))
44 print('trees actually created: {}'.format(len(Tree.pool)))
45 t4 = Tree(TreeType.cherry_tree)
46 t5 = Tree(TreeType.cherry_tree)
47 t6 = Tree(TreeType.apple_tree)
48 print('{} == {}? {}'.format(id(t4), id(t5), id(t4) == id(t5)))
49 print('{} == {}? {}'.format(id(t5), id(t6), id(t5) == id(t6)))
50
51 main()
52
53 """
54 render a tree of type TreeType.apple_tree and age 28 at (29, 80)
55 render a tree of type TreeType.apple_tree and age 28 at (38, 94)
56 render a tree of type TreeType.apple_tree and age 16 at (82, 84)
57 render a tree of type TreeType.apple_tree and age 18 at (43, 98)
58 render a tree of type TreeType.apple_tree and age 2 at (84, 72)
59 render a tree of type TreeType.apple_tree and age 16 at (89, 29)
60 render a tree of type TreeType.apple_tree and age 30 at (91, 53)
61 render a tree of type TreeType.apple_tree and age 12 at (92, 73)
62 render a tree of type TreeType.apple_tree and age 3 at (11, 54)
63 render a tree of type TreeType.apple_tree and age 1 at (34, 59)
64 render a tree of type TreeType.cherry_tree and age 11 at (67, 72)
65 render a tree of type TreeType.cherry_tree and age 27 at (65, 81)
66 render a tree of type TreeType.cherry_tree and age 27 at (10, 48)
67 render a tree of type TreeType.peach_tree and age 11 at (35, 38)
68 render a tree of type TreeType.peach_tree and age 3 at (58, 83)
69 render a tree of type TreeType.peach_tree and age 18 at (73, 50)
70 render a tree of type TreeType.peach_tree and age 24 at (94, 3)
71 render a tree of type TreeType.peach_tree and age 4 at (2, 9)
72 trees rendered: 18
73 trees actually created: 3
74 4866032 == 4866032? True
75 4866032 == 4742704? False
76
77 """

享元模式

復制代碼
 1 import random
 2 from enum import Enum
 3 TreeType = Enum('TreeType', 'apple_tree cherry_tree peach_tree')
 4 
 5 class Tree:
 6     pool = dict()
 7     def __new__(cls, tree_type):
 8         obj = cls.pool.get(tree_type, None)
 9         if not obj:
10             obj = object.__new__(cls)
11             cls.pool[tree_type] = obj
12             obj.tree_type = tree_type
13         return obj
14 
15     def render(self, age, x, y):
16         print('render a tree of type {} and age {} at ({}, {})'.format(self.tree_type, age, x, y))
17 
18 
19 def main():
20     rnd = random.Random()
21     age_min, age_max = 1, 30 # 單位為年
22     min_point, max_point = 0, 100
23     tree_counter = 0
24     for _ in range(10):
25         t1 = Tree(TreeType.apple_tree)
26         t1.render(rnd.randint(age_min, age_max),
27                 rnd.randint(min_point, max_point),
28                 rnd.randint(min_point, max_point))
29         tree_counter += 1
30     for _ in range(3):
31         t2 = Tree(TreeType.cherry_tree)
32         t2.render(rnd.randint(age_min, age_max),
33                 rnd.randint(min_point, max_point),
34                 rnd.randint(min_point, max_point))
35         tree_counter += 1
36     for _ in range(5):
37         t3 = Tree(TreeType.peach_tree)
38         t3.render(rnd.randint(age_min, age_max),
39                     rnd.randint(min_point, max_point),
40                     rnd.randint(min_point, max_point))
41         tree_counter += 1
42 
43     print('trees rendered: {}'.format(tree_counter))
44     print('trees actually created: {}'.format(len(Tree.pool)))
45     t4 = Tree(TreeType.cherry_tree)
46     t5 = Tree(TreeType.cherry_tree)
47     t6 = Tree(TreeType.apple_tree)
48     print('{} == {}? {}'.format(id(t4), id(t5), id(t4) == id(t5)))
49     print('{} == {}? {}'.format(id(t5), id(t6), id(t5) == id(t6)))
50 
51 main()
52 
53 """
54 render a tree of type TreeType.apple_tree and age 28 at (29, 80)
55 render a tree of type TreeType.apple_tree and age 28 at (38, 94)
56 render a tree of type TreeType.apple_tree and age 16 at (82, 84)
57 render a tree of type TreeType.apple_tree and age 18 at (43, 98)
58 render a tree of type TreeType.apple_tree and age 2 at (84, 72)
59 render a tree of type TreeType.apple_tree and age 16 at (89, 29)
60 render a tree of type TreeType.apple_tree and age 30 at (91, 53)
61 render a tree of type TreeType.apple_tree and age 12 at (92, 73)
62 render a tree of type TreeType.apple_tree and age 3 at (11, 54)
63 render a tree of type TreeType.apple_tree and age 1 at (34, 59)
64 render a tree of type TreeType.cherry_tree and age 11 at (67, 72)
65 render a tree of type TreeType.cherry_tree and age 27 at (65, 81)
66 render a tree of type TreeType.cherry_tree and age 27 at (10, 48)
67 render a tree of type TreeType.peach_tree and age 11 at (35, 38)
68 render a tree of type TreeType.peach_tree and age 3 at (58, 83)
69 render a tree of type TreeType.peach_tree and age 18 at (73, 50)
70 render a tree of type TreeType.peach_tree and age 24 at (94, 3)
71 render a tree of type TreeType.peach_tree and age 4 at (2, 9)
72 trees rendered: 18
73 trees actually created: 3
74 4866032 == 4866032? True
75 4866032 == 4742704? False
76 
77 """
復制代碼

 

模型-視圖-控制器模式

代理模式

3.行為型模式

責任鏈模式

命令模式

解釋器模式

觀察者模式

狀態模式

策略模式

模板模式

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM