學完編程語言的語法和函數(shù)庫恼蓬,只是程序設計學習的第一步,這并不意味著就能夠動手寫出好程序了僵芹。就像我們學習寫文章一樣处硬,認識所有的語法知識,認識所有的漢字拇派,但是不一定能夠寫出詞藻華麗的文章荷辕。所以編程語言只是礎知識,想要更進一步件豌,還得學會設計和分析疮方。下面將使用Python語言去練習24個經典的設計模式,從中體會編程的藝術茧彤。主要參考資料為:《大話設計模式》Python版代碼實現(xiàn)
一骡显、簡單工廠模式
簡單工廠模式就是定義一個簡單工廠類,由工廠類向調用者client提供不同的產品類曾掂,也就是說client只需要提供自己的需要惫谤,工廠類提供產品,具體的實現(xiàn)位于產品類當中遭殉。
考慮用一個四則運算的例子石挂,用簡單工廠模式來實現(xiàn)。
#!/usr/bin/env python
# coding=utf-8
class Operation:
def get_result(self):
pass
class OpetrationAdd(Operation):
def get_result(self):
return self.op1 + self.op2
class OpetrationSub(Operation):
def get_result(self):
return self.op1 - self.op2
class OperationMul(Operation):
def get_result(self):
return self.op1 * self.op2
class OperationDiv(Operation):
def get_result(self):
try:
result = self.op1 / self.op2
return result
except:
print "div error."
return 0
class OperationUndef(Operation):
def get_result(self):
print "undefine operation"
return 0
class OperationFactory:
operation = {}
operation["+"] = OpetrationAdd()
operation["-"] = OpetrationSub()
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.get_result()
二险污、策略模式
我們都知道諸葛亮三個錦囊?guī)椭鷦浔У妹廊藲w的故事痹愚。所謂的錦囊妙計,就是依據不同的情況選擇不同的計策去執(zhí)行蛔糯,執(zhí)行的過程是固定的拯腮,變化的是計策的內容。也就是說由client劉備去負責執(zhí)行策略的流程蚁飒,但是具體的計策动壤,由每個具體的策略來實現(xiàn)。
類圖如下所示:
#!/usr/bin/env python
# coding=utf-8
class CashSuper:
def accept_cash(self, money):
return 0
class CashNormal(CashSuper):
def accept_cash(self, money):
return money
class CashRebate(CashSuper):
discount = 0
def __init__(self, ds):
self.discount = ds
def accept_cash(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 accept_cash(self, money):
if(money >= self.total):
return (money - self.ret)
else:
return money
class CashContext:
def __init__(self, csuper):
self.cs = csuper
def get_result(self, money):
return self.cs.accept_cash(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-normal,2-80% discount,3-for 300 -100:")
if ctype in strategy:
cc = strategy[ctype]
else:
print "undefine type."
cc = strategy[1]
print "you will pay:{0}".format(cc.get_result(money))
三淮逻、代理模式
為了防止對一種資源類的直接訪問琼懊,可是使用代理模式來做訪問控制阁簸。
class Interface :
def Request(self):
return 0
class RealSubject(Interface):
def Request(self):
print "Real request."
class Proxy(Interface):
def __init__():
self.real = RealSubject()
def Request(self):
self.real.Request()
if __name__ == "__main__":
p = Proxy()
p.Request()
四、工廠方法模式
工廠方法就是指一個工廠類負責一個產品類的生產哼丈。定義一個用于創(chuàng)建對象的接口启妹,讓子類決定實例化哪一個類。這使得一個類的實例化延遲到其子類醉旦。
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()
五饶米、原型模式
用原型實例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象车胡。
Python為對象提供的copy模塊中的copy方法和deepcopy方法已經實現(xiàn)了原型模式檬输。
Python中的copy方法是淺拷貝,deepcopy是深拷貝匈棘。淺拷貝指的是丧慈,對于基本類型,拷貝時會是真的拷貝一份副本羹饰,但是對于內部的子對象伊滋,只是拷貝了對象的引用而已碳却。深拷貝就是完全拷貝了队秩。看個例子:
import copy
a = [1, 2, 3, 4, ['a', b']]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
a.append(5)
a[4].append('c')
print a
print b
print c
print d
輸出結果:
a = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
b = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
c = [1, 2, 3, 4, ['a', 'b', 'c']]
d = [1, 2, 3, 4, ['a', 'b']]
六昼浦、模板方法模式
定義一個操作中的算法骨架馍资,將一些步驟延遲至子類中。
舉個例子关噪,考試時使用同一種考卷(父類)鸟蟹,不同學生上交自己填寫的試卷(子類方法的實現(xiàn))
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()
七、外觀模式
其實就是講函數(shù)調用分層使兔。這是一個很有用的編程方式建钥,以金字塔形的結構來管理日益復雜的功能代碼。
程序實例:接口將幾種調用分別組合成為兩組虐沥,用戶通過接口調用其中的一組熊经。
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)分離欲险,使得同樣的構建過程可以創(chuàng)建不同的表示(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()
p = ThinPerson()
d = Director(p)
d.Create()
九、觀察者模式
定義了一種一對多的關系天试,讓多個觀察對象同時監(jiān)聽一個主題對象槐壳,當主題對象狀態(tài)發(fā)生變化時會通知所有觀察者。
程序實例:公司里有兩種上班時趁老板不在時偷懶的員工:看NBA的和看股票行情的喜每,并且事先讓老板秘書當老板出現(xiàn)時通知他們繼續(xù)做手頭上的工作务唐。
#!/usr/bin/env python
# coding=utf-8
class Observer:
def __init__(self, strname, strsub):
self.name = strname
self.sub = strsub
def update(self):
pass
class StockOberver(Observer):
def update(self):
print "{0}:{1},stop watching stock and go on work!".format(
self.name,
self.sub.aciton,
)
class NBAObserver(Observer):
def update(self):
print "{0}:{1},stop watching NBA and go on work.".format(
self.name,
self.sub.aciton,
)
class SecretaryBase:
def __init__(self):
self.obervers = []
def attach(self, new_obersver):
pass
def notify(self):
pass
class Secretary(SecretaryBase):
def attach(self, new_obersver):
self.obervers.append(new_obersver)
def notify(self):
for p in self.obervers:
p.update()
if __name__ == "__main__":
p = Secretary()
s1 = StockOberver("xh", p)
s2 = NBAObserver("wyt", p)
p.attach(s1)
p.attach(s2)
p.aciton = "WARNING:BOSS"
p.notify()
十雳攘、狀態(tài)模式
當一個對象的內在狀態(tài)改變時允許改變其行為,這個對象看起來像是改變了其類枫笛。
程序實例:描述一個程序員的工作狀態(tài)来农,當需要改變狀態(tài)時發(fā)生改變,不同狀態(tài)下的方法實現(xiàn)不同
``python
!/usr/bin/env python
coding=utf-8
class State:
def write_something(self):
pass
class Work:
def __init__(self):
self.hour = 9
self.current = ForenoonState()
def set_state(self, temp):
self.current = temp
def write_something(self):
self.current.write_something(self)
class NoonState(State):
def write_something(self, w):
print "noon Work."
if(w.hour < 13):
print "fun"
else:
print "need to rest"
class ForenoonState(State):
def write_something(self, w):
if (w.hour < 12):
print "morning working"
print "energetic"
else:
w.set_state(NoonState())
w.write_something()
if name == "main":
mywork = Work()
mywork.hour = 9
mywork.write_something()
mywork.hour = 14
mywork.write_something()
# 十一崇堰、適配器模式
將一個類的接口轉換成為客戶希望的另外一個接口沃于。
比如說我們現(xiàn)在已經有了一個類,但是使用是這個類可能會有不同的預處理海诲,那么可以添加一個適配器來做預處理并負責訪問現(xiàn)有的類繁莹。

```python
class Target:
def Request():
print "common request."
class Adaptee():
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()
十二、備忘錄模式
不破壞封裝性的前提下捕獲一個對象的內部狀態(tài)特幔,并在該對象之外保存這個狀態(tài)咨演,以后可以將對象恢復到這個狀態(tài)。
程序實例:將Originator對象的狀態(tài)封裝成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真的需要單例模式嗎撇他?我指像其他編程語言中的單例模式。
答案是:不需要狈蚤!
因為困肩,Python有模塊(module),最pythonic的單例典范脆侮。
模塊在在一個應用程序中只有一份锌畸,它本身就是單例的,將你所需要的屬性和方法靖避,直接暴露在模塊中變成模塊的全局變量和方法即可潭枣!
十八、橋接模式
模式特點:將抽象部分與它的實現(xiàn)部分分離筋蓖,使它們都可以獨立地變化卸耘。
程序實例:兩種品牌的手機,要求它們都可以運行游戲和通訊錄兩個軟件粘咖,而不是為每個品牌的手機都獨立編寫不同的軟件蚣抗。
代碼特點:雖然使用了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()
brand = HandsetBrandM()
brand.SetHandsetSoft(HandsetGame())
brand.Run()
brand.SetHandsetSoft(HandsetAddressList())
brand.Run()
十七钝域、命令模式
模式特點:將請求封裝成對象,從而使可用不同的請求對客戶進行參數(shù)化锭魔;對請求排隊或記錄請求日志例证,以及支持可撤消的操作。
程序實例:燒烤店有兩種食物迷捧,羊肉串和雞翅织咧。客戶向服務員點單漠秋,服務員將點好的單告訴大廚笙蒙,由大廚進行烹飪。
#!/usr/bin/env python
# coding=utf-8
class Barbucer:
def make_mutton(self):
print "mutton"
def make_chicken_wing(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.make_mutton()
class ChickenWingCmd(Command):
def executecmd(self):
self.receiver.make_chicken_wing()
class Waiter:
def __init__(self):
self.order = []
def set_cmd(self, command):
self.order.append(command)
def notify(self):
for cmd in self.order:
cmd.executecmd()
if __name__ == "__main__":
barbucer = Barbucer()
cmd = BakeMuttonCmd(barbucer)
cmd2 = ChickenWingCmd(barbucer)
girl = Waiter()
girl.set_cmd(cmd)
girl.set_cmd(cmd2)
girl.notify()
十八庆锦、中介者模式
模式特點:用一個對象來封裝一系列的對象交互捅位,中介者使各對象不需要顯示地相互引用,從而使耦合松散搂抒,而且可以獨立地改變它們之間的交互艇搀。
程序實例:兩個對象通過中介者相互通信
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.");
十九、訪問者模式
模式特點:表示一個作用于某對象結構中的各元素的操作求晶。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作焰雕。
程序實例:對于男人和女人(接受訪問者的元素,ObjectStructure用于窮舉這些元素)誉帅,不同的遭遇(具體的訪問者)引發(fā)兩種對象的不同行為淀散。
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)
二十晨抡、裝飾模式
模式特點:動態(tài)地為對象增加額外的職責
程序實例:展示一個人一件一件穿衣服的過程氛悬。
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()