《大話設計模式》Python版代碼實現(新增多年實踐的心得)


  上一周把《大話設計模式》看完了,對面向對象技術有了新的理解,對於一個在C下寫代碼比較多、偶爾會用到一些腳本語言寫腳本的人來說,很是開闊眼界。《大話設計模式》的代碼使用C#寫成的,而在本人接觸到的面向對象語言中,只對C++和Python還算了解,為了加深對各個模式的理解,我在網上下載了一個C++版的源代碼,並根據自己的理解邊讀這本書邊動手實踐C++源代碼,同時將其改寫成了Python代碼,算是一箭三雕吧。

  由於這些代碼的目的是展示各個設計模式而非完成一個具體的復雜任務,基於C++版本改寫,例子的取材也和《大話設計模式》基本相同,再加上個人水平有限,因此這些Python版代碼寫的比較簡單,雖然能跑起來是不假,不過難免有bug,而且實現也不一定最優,C++的味道比較濃而不夠pythonic,還請高手包容指正。不過我還是盡量把或多或少有些pythonic的東西放在每個模式的“代碼特點”部分進行展示,而這個“代碼特點”里也不僅僅是pythonic的東西。

  使用Python版本為2.6。

  配圖同樣摘自《大話設計模式》,因此是C#風格的UML類圖,為了便於排版已經縮小了。

  

一、簡單工廠模式

模式特點:工廠根據條件產生不同功能的類。

程序實例:四則運算計算器,根據用戶的輸入產生相應的運算類,用這個運算類處理具體的運算。

代碼特點:C/C++中的switch...case...分支使用字典的方式代替。

     使用異常機制對除數為0的情況進行處理。

簡單工廠模式
class Operation:
    def GetResult(self):
        pass

class OperationAdd(Operation):
    def GetResult(self):
        return self.op1+self.op2


class OperationSub(Operation):
    def GetResult(self):
        return self.op1-self.op2


class OperationMul(Operation):
    def GetResult(self):
        return self.op1*self.op2


class OperationDiv(Operation):
    def GetResult(self):
        try:
            result = self.op1/self.op2
            return result
        except:
            print "error:divided by zero."
            return 0

class OperationUndef(Operation):
    def GetResult(self):
        print "Undefine operation."
        return 0

class OperationFactory:
    operation = {}
    operation["+"] = OperationAdd();
    operation["-"] = OperationSub();
    operation["*"] = OperationMul();
    operation["/"] = OperationDiv();
    def createOperation(self,ch):        
        if ch in self.operation:
            op = self.operation[ch]
        else:
            op = OperationUndef()
        return op

if __name__ == "__main__":
    op = raw_input("operator: ")
    opa = input("a: ")
    opb = input("b: ")
    factory = OperationFactory()
    cal = factory.createOperation(op)
    cal.op1 = opa
    cal.op2 = opb
    print cal.GetResult()

 

二、策略模式

模式特點:定義算法家族並且分別封裝,它們之間可以相互替換而不影響客戶端。

程序實例:商場收銀軟件,需要根據不同的銷售策略方式進行收費

代碼特點:不同於同例1,這里使用字典是為了避免關鍵字不在字典導致bug的陷阱。

策略模式
class CashSuper:
    def AcceptCash(self,money):
        return 0

class CashNormal(CashSuper):
    def AcceptCash(self,money):
        return money

class CashRebate(CashSuper):
    discount = 0
    def __init__(self,ds):
        self.discount = ds
    def AcceptCash(self,money):
        return money * self.discount

class CashReturn(CashSuper):
    total = 0;
    ret = 0;
    def __init__(self,t,r):
        self.total = t
        self.ret = r
    def AcceptCash(self,money):
        if (money>=self.total):
            return money - self.ret
        else:
            return money

class CashContext:
    def __init__(self,csuper):
        self.cs = csuper
    def GetResult(self,money):
        return self.cs.AcceptCash(money)

if __name__ == "__main__":
    money = input("money:")
    strategy = {}
    strategy[1] = CashContext(CashNormal())
    strategy[2] = CashContext(CashRebate(0.8))
    strategy[3] = CashContext(CashReturn(300,100))
    ctype = input("type:[1]for normal,[2]for 80% discount [3]for 300 -100.")
    if ctype in strategy:
        cc = strategy[ctype]
    else:
        print "Undefine type.Use normal mode."
        cc = strategy[1]
    print "you will pay:%d" %(cc.GetResult(money))

三、裝飾模式

模式特點:動態地為對象增加額外的職責

程序實例:展示一個人一件一件穿衣服的過程。

代碼特點:無

裝飾模式
class Person:
    def __init__(self,tname):
        self.name = tname
    def Show(self):
       print "dressed %s" %(self.name)

class Finery(Person):
    componet = None
    def __init__(self):
        pass
    def Decorate(self,ct):
        self.componet = ct
    def Show(self):
    if(self.componet!=None):
        self.componet.Show()

class TShirts(Finery):
    def __init__(self):
        pass
    def Show(self):
        print "Big T-shirt "
        self.componet.Show()

class BigTrouser(Finery):
    def __init__(self):
        pass
    def Show(self):
        print "Big Trouser "
        self.componet.Show()

if __name__ == "__main__":
    p = Person("somebody")
    bt = BigTrouser()
    ts = TShirts()
    bt.Decorate(p)
    ts.Decorate(bt)
    ts.Show()

四、代理模式

模式特點:為其他對象提供一種代理以控制對這個對象的訪問。

程序實例:同模式特點描述。

代碼特點:無

代理模式
class Interface :
    def Request(self):
    return 0

class RealSubject(Interface): 
    def Request(self):
        print "Real request."

class Proxy(Interface):
    def Request(self):
        self.real = RealSubject()
        self.real.Request()

if __name__ == "__main__":
    p = Proxy()
    p.Request()

五、工廠方法模式

模式特點:定義一個用於創建對象的接口,讓子類決定實例化哪一個類。這使得一個類的實例化延遲到其子類。

程序實例:基類雷鋒類,派生出學生類和志願者類,由這兩種子類完成“學雷鋒”工作。子類的創建由雷鋒工廠的對應的子類完成。

代碼特點:無

工廠方法模式
class LeiFeng:
    def Sweep(self):
        print "LeiFeng sweep"

class Student(LeiFeng):
    def Sweep(self):
        print "Student sweep"

class Volenter(LeiFeng):
    def Sweep(self):
        print "Volenter sweep"

class LeiFengFactory:
    def CreateLeiFeng(self):
        temp = LeiFeng()
        return temp

class StudentFactory(LeiFengFactory):
    def CreateLeiFeng(self):
        temp = Student()
        return temp

class VolenterFactory(LeiFengFactory):
    def CreateLeiFeng(self):
        temp = Volenter()
        return temp

if __name__ == "__main__":
    sf = StudentFactory()
    s=sf.CreateLeiFeng()
    s.Sweep()
    sdf = VolenterFactory()
    sd=sdf.CreateLeiFeng()
    sd.Sweep()

 

 六、原型模式

模式特點:用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。

程序實例:從簡歷原型,生成新的簡歷

代碼特點:簡歷類Resume提供的Clone()方法其實並不是真正的Clone,只是為已存在對象增加了一次引用。

     Python為對象提供的copy模塊中的copy方法和deepcopy方法已經實現了原型模式,但由於例子的層次較淺,二者看不出區別。

    

原型模式
import copy
class WorkExp:
    place=""
    year=0

class Resume:
    name = ''
    age = 0
    def __init__(self,n):
        self.name = n
    def SetAge(self,a):
        self.age = a
    def SetWorkExp(self,p,y):
        self.place = p
        self.year = y
    def Display(self):
        print self.age
        print self.place
        print self.year
    def Clone(self):
    #實際不是“克隆”,只是返回了自身
        return self

if __name__ == "__main__":
    a = Resume("a")
    b = a.Clone()
    c = copy.copy(a)
    d = copy.deepcopy(a)
    a.SetAge(7)
    b.SetAge(12)
    c.SetAge(15)
    d.SetAge(18)
    a.SetWorkExp("PrimarySchool",1996)
    b.SetWorkExp("MidSchool",2001)
    c.SetWorkExp("HighSchool",2004)
    d.SetWorkExp("University",2007)
    a.Display()
    b.Display()
    c.Display()
    d.Display()

七、模板方法模式

 

模式特點:定義一個操作中的算法骨架,將一些步驟延遲至子類中。

程序實例:考試時使用同一種考卷(父類),不同學生上交自己填寫的試卷(子類方法的實現)

代碼特點:無

模板方法模式
class TestPaper:
    def TestQuestion1(self):
        print "Test1:A. B. C. D."
        print "(%s)" %self.Answer1()

    def TestQuestion2(self):
        print "Test1:A. B. C. D."
        print "(%s)" %self.Answer2()
    def Answer1(self):
        return ""
    def Answer2(self):
        return ""

class TestPaperA(TestPaper):
    def Answer1(self):
        return "B"
    def Answer2(self):
        return "C";

class TestPaperB(TestPaper):
    def Answer1(self):
        return "D"
    def Answer2(self):
        return "D";

if __name__ == "__main__":
    s1 = TestPaperA()
    s2 = TestPaperB()
    print "student 1"
    s1.TestQuestion1()
    s1.TestQuestion2()
    print "student 2"
    s2.TestQuestion1()
    s2.TestQuestion2()

 

 八、外觀模式

模式特點:為一組調用提供一致的接口。

程序實例:接口將幾種調用分別組合成為兩組,用戶通過接口調用其中的一組。

代碼特點:無

外觀模式
class SubSystemOne:
    def MethodOne(self):
        print "SubSysOne"

class SubSystemTwo:
    def MethodTwo(self):
        print "SubSysTwo"

class SubSystemThree:
    def MethodThree(self):
        print "SubSysThree"

class SubSystemFour:
    def MethodFour(self):
        print "SubSysFour"


class Facade:
    def __init__(self):
        self.one = SubSystemOne()
        self.two = SubSystemTwo()
        self.three = SubSystemThree()
        self.four = SubSystemFour()
    def MethodA(self):
        print "MethodA"
        self.one.MethodOne()
        self.two.MethodTwo()
        self.four.MethodFour()
    def MethodB(self):
        print "MethodB"
        self.two.MethodTwo()
        self.three.MethodThree()

if __name__ == "__main__":
    facade = Facade()
    facade.MethodA()
    facade.MethodB()

 

九、建造者模式

 

模式特點:將一個復雜對象的構建(Director)與它的表示(Builder)分離,使得同樣的構建過程可以創建不同的表示(ConcreteBuilder)。

程序實例:“畫”出一個四肢健全(頭身手腿)的小人

代碼特點:無

建造者模式
class Person:
    def CreateHead(self):
        pass
    def CreateHand(self):
        pass
    def CreateBody(self):
        pass
    def CreateFoot(self):
        pass

class ThinPerson(Person):
    def CreateHead(self):
        print "thin head"
    def CreateHand(self):
        print "thin hand"
    def CreateBody(self):
        print "thin body"
    def CreateFoot(self):
        print "thin foot"

class ThickPerson(Person):
    def CreateHead(self):
        print "thick head"
    def CreateHand(self):
        print "thick hand"
    def CreateBody(self):
        print "thick body"
    def CreateFoot(self):
        print "thick foot"

class Director:
    def __init__(self,temp):
        self.p = temp
    def Create(self):
        self.p.CreateHead()
        self.p.CreateBody()
        self.p.CreateHand()
        self.p.CreateFoot()

if __name__ == "__main__":
    p = ThickPerson()
    d = Director(p)
    d.Create()

 

十、觀察者模式

模式特點:定義了一種一對多的關系,讓多個觀察對象同時監聽一個主題對象,當主題對象狀態發生變化時會通知所有觀察者。

程序實例:公司里有兩種上班時趁老板不在時偷懶的員工:看NBA的和看股票行情的,並且事先讓老板秘書當老板出現時通知他們繼續做手頭上的工作。

程序特點:無

觀察者模式
class Observer:
    def __init__(self,strname,strsub):
        self.name = strname
        self.sub = strsub
    def Update(self):
        pass

class StockObserver(Observer):
    #no need to rewrite __init__()
    def Update(self):
        print "%s:%s,stop watching Stock and go on work!" %(self.name,self.sub.action)

class NBAObserver(Observer):
    def Update(self):
        print "%s:%s,stop watching NBA and go on work!" %(self.name,self.sub.action)

class SecretaryBase:
    def __init__(self):
        self.observers = []
    def Attach(self,new_observer):
        pass 
    def Notify(self):
        pass

class Secretary(SecretaryBase):
    def Attach(self,new_observer):
        self.observers.append(new_observer)
    def Notify(self):
        for p in self.observers:
            p.Update()

if __name__ == "__main__":
    p = Secretary()
    s1 = StockObserver("xh",p)
    s2 = NBAObserver("wyt",p)
    p.Attach(s1);
    p.Attach(s2);
    p.action = "WARNING:BOSS ";
    p.Notify()

十一、抽象工廠模式

模式特點:提供一個創建一系列相關或相互依賴對象的接口,而無需指定它們的類。

程序實例:提供對不同的數據庫訪問的支持。

     IUser和IDepartment是兩種不同的抽象產品,它們都有Access和SQL Server這兩種不同的實現;IFactory是產生IUser和IDepartment的抽象工廠,根據具體實現(AccessFactory和SqlFactory)產生對應的具體的對象(CAccessUser與CAccessDepartment,或者CSqlUser與CSqlDepartment)。

代碼特點:無

抽象工廠模式
class IUser:
    def GetUser(self):
        pass
    def InsertUser(self):
        pass

class IDepartment:
    def GetDepartment(self):
        pass
    def InsertDepartment(self):
        pass

class CAccessUser(IUser):
    def GetUser(self):
        print "Access GetUser"
    def InsertUser(self):
        print "Access InsertUser"


class CAccessDepartment(IDepartment):
    def GetDepartment(self):
        print "Access GetDepartment"
    def InsertDepartment(self):
        print "Access InsertDepartment"

class CSqlUser(IUser):
    def GetUser(self):
        print "Sql GetUser"
    def InsertUser(self):
        print "Sql InsertUser"


class CSqlDepartment(IDepartment):
    def GetDepartment(self):
        print "Sql GetDepartment"
    def InsertDepartment(self):
        print "Sql InsertDepartment"

class IFactory:
    def CreateUser(self):
        pass
    def CreateDepartment(self):
        pass

class AccessFactory(IFactory):
    def CreateUser(self):
        temp=CAccessUser()
        return temp
    def CreateDepartment(self):
        temp = CAccessDepartment()
        return temp

class SqlFactory(IFactory):
    def CreateUser(self):
        temp = CSqlUser()
        return temp
    def CreateDepartment(self):
        temp = CSqlDepartment()
        return temp

if __name__ == "__main__":
    factory = SqlFactory()
    user=factory.CreateUser()
    depart=factory.CreateDepartment()
    user.GetUser()
    depart.GetDepartment()

十二、狀態模式

 

模式特點:當一個對象的內在狀態改變時允許改變其行為,這個對象看起來像是改變了其類。

程序實例:描述一個程序員的工作狀態,當需要改變狀態時發生改變,不同狀態下的方法實現不同

代碼特點:無

狀態模式
class State:
    def WirteProgram(self):
        pass

class Work:
    def __init__(self):
        self.hour = 9
        self.current = ForenoonState()
    def SetState(self,temp):
        self.current = temp
    def WriteProgram(self):
        self.current.WriteProgram(self)

class NoonState(State):
    def WriteProgram(self,w):
        print "noon working"
        if (w.hour<13):
            print "fun."
        else:
            print "need to rest."

class ForenoonState(State):
    def WriteProgram(self,w):
        if (w.hour<12):
            print "morning working"
            print "energetic"
        else:
            w.SetState(NoonState())        
            w.WriteProgram()

if __name__ == "__main__":
    mywork = Work()
    mywork.hour = 9
    mywork.WriteProgram()
    mywork.hour =14
    mywork.WriteProgram()

十三、適配器模式

 

模式特點:將一個類的接口轉換成為客戶希望的另外一個接口。

程序實例:用戶通過適配器使用一個類的方法。

代碼特點:無

適配器模式
class Target:
    def Request():
        print "common request."

class Adaptee(Target):
    def SpecificRequest(self):
        print "specific request."

class Adapter(Target):
    def __init__(self,ada):
        self.adaptee = ada
    def Request(self):
        self.adaptee.SpecificRequest()

if __name__ == "__main__":
    adaptee = Adaptee()
    adapter = Adapter(adaptee)
    adapter.Request()

十四、備忘錄模式

模式特點:在不破壞封裝性的前提下捕獲一個對象的內部狀態,並在該對象之外保存這個狀態,以后可以將對象恢復到這個狀態。

程序實例:將Originator對象的狀態封裝成Memo對象保存在Caretaker內

代碼特點:無

備忘錄模式
class Originator:
    def __init__(self):
        self.state = ""
    def Show(self):
        print self.state
    def CreateMemo(self):
        return Memo(self.state)
    def SetMemo(self,memo):
        self.state = memo.state

class Memo:
    state= ""
    def __init__(self,ts):
        self.state = ts

class Caretaker:
    memo = ""

if __name__ == "__main__":
    on = Originator()
    on.state = "on"
    on.Show()
    c = Caretaker()
    c.memo=on.CreateMemo()
    on.state="off"
    on.Show()
    on.SetMemo(c.memo)
    on.Show()

十五、組合模式

 

模式特點:將對象組合成樹形結構,以表示“部分-整體”的層次關系。整體和單個組件使用方式具有一致性。

程序實例:公司人員的組織結構(樹形)

代碼特點:無

組合模式
class Component:
    def __init__(self,strName):
        self.m_strName = strName
    def Add(self,com):
        pass
    def Display(self,nDepth):
        pass

class Leaf(Component):
    def Add(self,com):
        print "leaf can't add"
    def Display(self,nDepth):
        strtemp = ""
        for i in range(nDepth):
            strtemp=strtemp+"-"
        strtemp=strtemp+self.m_strName
        print strtemp

class Composite(Component):
    def __init__(self,strName):
        self.m_strName = strName
        self.c = []
    def Add(self,com):
        self.c.append(com)
    def Display(self,nDepth):
        strtemp=""
        for i in range(nDepth):
            strtemp=strtemp+"-"
        strtemp=strtemp+self.m_strName
        print strtemp
        for com in self.c:
            com.Display(nDepth+2)

if __name__ == "__main__":
    p = Composite("Wong")
    p.Add(Leaf("Lee"))
    p.Add(Leaf("Zhao"))
    p1 = Composite("Wu")
    p1.Add(Leaf("San"))
    p.Add(p1)
    p.Display(1);

 

十六、迭代器模式

模式特點:提供方法順序訪問一個聚合對象中各元素,而又不暴露該對象的內部表示

說明:這個模式沒有寫代碼實現,原因是使用Python的列表和for ... in list就能夠完成不同類型對象聚合的迭代功能了。

 

十七、單例模式

 

模式特點:保證類僅有一個實例,並提供一個訪問它的全局訪問點。

說明:     為了實現單例模式費了不少工夫,后來查到一篇博文對此有很詳細的介紹,而且實現方式也很豐富,通過對代碼的學習可以了解更多Python的用法。以下的代碼出自GhostFromHeaven的專欄,地址:http://blog.csdn.net/ghostfromheaven/article/details/7671853。不過正如其作者在Python單例模式終極版所說:

我要問的是,Python真的需要單例模式嗎?我指像其他編程語言中的單例模式。

答案是:不需要!

因為,Python有模塊(module),最pythonic的單例典范。

模塊在在一個應用程序中只有一份,它本身就是單例的,將你所需要的屬性和方法,直接暴露在模塊中變成模塊的全局變量和方法即可!

 

單例模式(四種方法)
#-*- encoding=utf-8 -*-
print '----------------------方法1--------------------------'
#方法1,實現__new__方法
#並在將一個類的實例綁定到類變量_instance上,
#如果cls._instance為None說明該類還沒有實例化過,實例化該類,並返回
#如果cls._instance不為None,直接返回cls._instance
class Singleton(object):
    def __new__(cls, *args, **kw):
        if not hasattr(cls, '_instance'):
            orig = super(Singleton, cls)
            cls._instance = orig.__new__(cls, *args, **kw)
        return cls._instance

class MyClass(Singleton):
    a = 1

one = MyClass()
two = MyClass()

two.a = 3
print one.a
#3
#one和two完全相同,可以用id(), ==, is檢測
print id(one)
#29097904
print id(two)
#29097904
print one == two
#True
print one is two
#True

print '----------------------方法2--------------------------'
#方法2,共享屬性;所謂單例就是所有引用(實例、對象)擁有相同的狀態(屬性)和行為(方法)
#同一個類的所有實例天然擁有相同的行為(方法),
#只需要保證同一個類的所有實例具有相同的狀態(屬性)即可
#所有實例共享屬性的最簡單最直接的方法就是__dict__屬性指向(引用)同一個字典(dict)
#可參看:http://code.activestate.com/recipes/66531/
class Borg(object):
    _state = {}
    def __new__(cls, *args, **kw):
        ob = super(Borg, cls).__new__(cls, *args, **kw)
        ob.__dict__ = cls._state
        return ob

class MyClass2(Borg):
    a = 1

one = MyClass2()
two = MyClass2()

#one和two是兩個不同的對象,id, ==, is對比結果可看出
two.a = 3
print one.a
#3
print id(one)
#28873680
print id(two)
#28873712
print one == two
#False
print one is two
#False
#但是one和two具有相同的(同一個__dict__屬性),見:
print id(one.__dict__)
#30104000
print id(two.__dict__)
#30104000

print '----------------------方法3--------------------------'
#方法3:本質上是方法1的升級(或者說高級)版
#使用__metaclass__(元類)的高級python用法
class Singleton2(type):
    def __init__(cls, name, bases, dict):
        super(Singleton2, cls).__init__(name, bases, dict)
        cls._instance = None
    def __call__(cls, *args, **kw):
        if cls._instance is None:
            cls._instance = super(Singleton2, cls).__call__(*args, **kw)
        return cls._instance

class MyClass3(object):
    __metaclass__ = Singleton2

one = MyClass3()
two = MyClass3()

two.a = 3
print one.a
#3
print id(one)
#31495472
print id(two)
#31495472
print one == two
#True
print one is two
#True

print '----------------------方法4--------------------------'
#方法4:也是方法1的升級(高級)版本,
#使用裝飾器(decorator),
#這是一種更pythonic,更elegant的方法,
#單例類本身根本不知道自己是單例的,因為他本身(自己的代碼)並不是單例的
def singleton(cls, *args, **kw):
    instances = {}
    def _singleton():
        if cls not in instances:
            instances[cls] = cls(*args, **kw)
        return instances[cls]
    return _singleton

@singleton
class MyClass4(object):
    a = 1
    def __init__(self, x=0):
        self.x = x

one = MyClass4()
two = MyClass4()

two.a = 3
print one.a
#3
print id(one)
#29660784
print id(two)
#29660784
print one == two
#True
print one is two
#True
one.x = 1
print one.x
#1
print two.x
#1

 

十八、橋接模式

 

模式特點:將抽象部分與它的實現部分分離,使它們都可以獨立地變化。

程序實例:兩種品牌的手機,要求它們都可以運行游戲和通訊錄兩個軟件,而不是為每個品牌的手機都獨立編寫不同的軟件。

代碼特點:雖然使用了object的新型類,不過在這里不是必須的,是對在Python2.2之后“盡量使用新型類”的建議的遵從示范。

橋接模式
class HandsetSoft(object):
    def Run(self):
        pass

class HandsetGame(HandsetSoft):
    def Run(self):
        print "Game"

class HandsetAddressList(HandsetSoft):
    def Run(self):
        print "Address List"

class HandsetBrand(object):
    def __init__(self):
        self.m_soft = None
    def SetHandsetSoft(self,temp):
        self.m_soft= temp
    def Run(self):
        pass

class HandsetBrandM(HandsetBrand):
    def Run(self):
        if not (self.m_soft == None):
            print "BrandM"
            self.m_soft.Run()

class HandsetBrandN(HandsetBrand):
    def Run(self):
        if not (self.m_soft == None):
            print "BrandN"
            self.m_soft.Run()

if __name__ == "__main__":
    brand = HandsetBrandM()
    brand.SetHandsetSoft(HandsetGame())
    brand.Run()
    brand.SetHandsetSoft(HandsetAddressList())
    brand.Run()    

 

十九、命令模式

模式特點:將請求封裝成對象,從而使可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日志,以及支持可撤消的操作。

程序實例:燒烤店有兩種食物,羊肉串和雞翅。客戶向服務員點單,服務員將點好的單告訴大廚,由大廚進行烹飪。

代碼特點:注意在遍歷列表時不要用注釋的方式刪除,否則會出現bug。bug示例程序附在后面,我認為這是因為remove打亂了for迭代查詢列表的順序導致的。

命令模式
class Barbucer:
    def MakeMutton(self):
        print "Mutton"
    def MakeChickenWing(self):
        print "Chicken Wing"

class Command:
    def __init__(self,temp):
        self.receiver=temp
    def ExecuteCmd(self):
        pass

class BakeMuttonCmd(Command):
    def ExecuteCmd(self):
        self.receiver.MakeMutton()

class ChickenWingCmd(Command):
    def ExecuteCmd(self):
        self.receiver.MakeChickenWing()

class Waiter:
    def __init__(self):
        self.order =[]
    def SetCmd(self,command):
        self.order.append(command)
        print "Add Order"
    def Notify(self):
        for cmd in self.order:
            #self.order.remove(cmd)
            #lead to a bug
            cmd.ExecuteCmd()
            

if __name__ == "__main__":
    barbucer=Barbucer()
    cmd=BakeMuttonCmd(barbucer)
    cmd2=ChickenWingCmd(barbucer)
    girl=Waiter()
    girl.SetCmd(cmd)
    girl.SetCmd(cmd2)
    girl.Notify()

在for中remove會導致bug的展示代碼:

bug
c=[0,1,2,3]
for i in c:
    print i
    c.remove(i)

#output:
#0
#2

 

二十、職責鏈模式

模式特點:使多個對象都有機會處理請求,從而避免發送者和接收者的耦合關系。將對象連成鏈並沿着這條鏈傳遞請求直到被處理。

程序實例:請假和加薪等請求發給上級,如果上級無權決定,那么遞交給上級的上級。

代碼特點:無

職責鏈模式
class Request:
    def __init__(self,tcontent,tnum):
        self.content = tcontent
        self.num = tnum

class Manager:
    def __init__(self,temp):
        self.name = temp
    def SetSuccessor(self,temp):
        self.manager = temp
    def GetRequest(self,req):
        pass

class CommonManager(Manager):
    def GetRequest(self,req):
        if(req.num>=0 and req.num<10):
            print "%s handled %d request." %(self.name,req.num)
        else:
            self.manager.GetRequest(req)

class MajorDomo(Manager):
    def GetRequest(self,req):
        if(req.num>=10):
            print "%s handled %d request." %(self.name,req.num)

if __name__ == "__main__":
    common = CommonManager("Zhang")
    major = MajorDomo("Lee")
    common.SetSuccessor(major)
    req = Request("rest",33)
    common.GetRequest(req)
    req2 = Request("salary",3)
    common.GetRequest(req2)

 

二十一、中介者模式

 

 (圖源:https://zh.wikipedia.org/zh-hans/%E4%B8%AD%E4%BB%8B%E8%80%85%E6%A8%A1%E5%BC%8F)


模式特點:用一個對象來封裝一系列的對象交互,中介者使各對象不需要顯示地相互引用,從而使耦合松散,而且可以獨立地改變它們之間的交互。

程序實例:兩個對象通過中介者相互通信

代碼特點:無

中介者模式
class Mediator:
    def Send(self,message,col):
        pass

class Colleague:
    def __init__(self,temp):
        self.mediator = temp

class Colleague1(Colleague):
    def Send(self,message):
        self.mediator.Send(message,self)
    def Notify(self,message):
        print "Colleague1 get a message:%s" %message

class Colleague2(Colleague):
    def Send(self,message):
        self.mediator.Send(message,self)
    def Notify(self,message):
        print "Colleague2 get a message:%s" %message

class ConcreteMediator(Mediator):
    def Send(self,message,col):
        if(col==col1):
            col2.Notify(message)
        else:
            col1.Notify(message)

if __name__ == "__main__":
    m =ConcreteMediator()
    col1 = Colleague1(m)
    col2 = Colleague1(m)
    m.col1=col1
    m.col2=col2
    col1.Send("How are you?");
    col2.Send("Fine.");

 

二十二、享元模式

 

模式特點:運用共享技術有效地支持大量細粒度的對象。

程序實例:一個網站工廠,根據用戶請求的類別返回相應類別的網站。如果這種類別的網站已經在服務器上,那么返回這種網站並加上不同用戶的獨特的數據;如果沒有,那么生成一個。

代碼特點:為了展示每種網站的由用戶請求的次數,這里為它們建立了一個引用次數的字典。

      之所以不用Python的sys模塊中的sys.getrefcount()方法統計引用計數是因為有的對象可能在別處被隱式的引用,從而增加了引用計數。 

享元模式
import sys

class WebSite:
    def Use(self):
        pass

class ConcreteWebSite(WebSite):
    def __init__(self,strName):
        self.name = strName
    def Use(self,user):
        print "Website type:%s,user:%s" %(self.name,user)

class UnShareWebSite(WebSite):
    def __init__(self,strName):
        self.name = strName
    def Use(self,user):
        print "UnShare Website type:%s,user:%s" %(self.name, user)

class WebFactory:
    def __init__(self):
        test = ConcreteWebSite("test")
        self.webtype ={"test":test}
        self.count = {"test":0}
    def GetWeb(self,webtype):
        if webtype not in self.webtype:
            temp = ConcreteWebSite(webtype)
            self.webtype[webtype] = temp
            self.count[webtype] =1
        else:
            temp = self.webtype[webtype]
            self.count[webtype] = self.count[webtype]+1
        return temp
    def GetCount(self):
        for key in self.webtype:
            #print "type: %s, count:%d" %(key,sys.getrefcount(self.webtype[key]))
            print "type: %s, count:%d " %(key,self.count[key])

if __name__ == "__main__":
    f = WebFactory()
    ws=f.GetWeb("blog")
    ws.Use("Lee")
    ws2=f.GetWeb("show")
    ws2.Use("Jack")
    ws3=f.GetWeb("blog")
    ws3.Use("Chen")
    ws4=UnShareWebSite("TEST")
    ws4.Use("Mr.Q")
    print f.webtype
    f.GetCount()
    

 

二十三、解釋器模式

 

模式特點:給定一個語言,定義它的文法的一種表示,並定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。

程序實例:(只是模式特點的最簡單示范)

代碼特點:無

解釋器模式
class Context:
    def __init__(self):
        self.input=""
        self.output=""

class AbstractExpression:
    def Interpret(self,context):
        pass

class Expression(AbstractExpression):
    def Interpret(self,context):
        print "terminal interpret"

class NonterminalExpression(AbstractExpression):
    def Interpret(self,context):
        print "Nonterminal interpret"

if __name__ == "__main__":
    context= ""
    c = []
    c = c + [Expression()]
    c = c + [NonterminalExpression()]
    c = c + [Expression()]
    c = c + [Expression()]
    for a in c:
        a.Interpret(context)

 

二十四、訪問者模式

 

模式特點:表示一個作用於某對象結構中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用於這些元素的新操作。

程序實例:對於男人和女人(接受訪問者的元素,ObjectStructure用於窮舉這些元素),不同的遭遇(具體的訪問者)引發兩種對象的不同行為。

代碼特點:無

訪問者模式
# -*- coding: UTF-8 -*-
class Person:
    def Accept(self,visitor):
        pass

class Man(Person):
    def Accept(self,visitor):
        visitor.GetManConclusion(self)

class Woman(Person):
    def Accept(self,visitor):
        visitor.GetWomanConclusion(self)

class Action:
    def GetManConclusion(self,concreteElementA):
        pass
    def GetWomanConclusion(self,concreteElementB):
        pass

class Success(Action):
    def GetManConclusion(self,concreteElementA):
        print "男人成功時,背后有個偉大的女人"
    def GetWomanConclusion(self,concreteElementB):
        print "女人成功時,背后有個不成功的男人"

class Failure(Action):
    def GetManConclusion(self,concreteElementA):
        print "男人失敗時,悶頭喝酒,誰也不用勸"
    def GetWomanConclusion(self,concreteElementB):
        print "女人失敗時,眼淚汪汪,誰也勸不了"


class ObjectStructure:
    def __init__(self):
        self.plist=[]
    def Add(self,p):
        self.plist=self.plist+[p]
    def Display(self,act):
        for p in self.plist:
            p.Accept(act)

if __name__ == "__main__":
    os = ObjectStructure()
    os.Add(Man())
    os.Add(Woman())
    sc = Success()
    os.Display(sc)
    fl = Failure()
    os.Display(fl)

 

附:多年實踐的一點心得

  距離最初完成該文已經6年多了,工作中主要還是用的Java,也沒有刻意用各種設計模式。在重讀本文時回憶了一下平時編碼的過程,還是用到了一些。脫離了應用場景的設計模式只能是泛泛而談,因此稍微做一下總結:

1. 簡單工廠模式,替換復雜switch—— 用於生成一次性對象
2. 策略模式,替換復雜switch—— 用於關聯固定的過程、handler的bean
3. 代理模式,各種遠端調用服務的facade封裝而成的client
4. 模版方法模式,serviceTemplate封裝固定步驟:參數校驗、遠端調用、更新、回滾、打日志。本文的例子中沒有體現“固定步驟”
5. 外觀模式,集中管理多個bean並按業務流程組合調用順序
6. 建造者模式,沒有明確這樣寫但有點味道:用一個對象編排另一個對象的方法調用順序
7. 觀察者模式,消息訂閱和監聽
8. 狀態模式,自己寫的狀態機有類似的地方,每個狀態維護到下一個狀態的跳轉
9. 適配器模式,和代理模式有點像。不同點是,適配器包裝的類的方法和對外的名稱、參數不一致。實踐中的integration層的client,更像是代理模式+適配器模式+外觀模式(不組合不同服務)的混合體。
10. 迭代器模式,Java自帶的Iterator接口,不過不常用
11. 單例模式,各種工具類(校驗器、填充器)、spring的bean的默認使用方式等。單例本身也分懶漢模式、餓漢模式、雙重鎖模式、靜態內部類單例模式、枚舉單例模式等。詳細討論可見:https://www.jianshu.com/p/3bfd916f2bb2,對於雙重鎖模式的分析可以看:https://blog.csdn.net/chenchaofuck1/article/details/51702129
12. 職責鏈模式,沒有直接用過,JVM的雙親委派應該是類似的


免責聲明!

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



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