Python设计模式
学完编程语言的语法和函数库,只是程序设计学习的第一步,这并不意味着就能够动手写出好程序了。就像我们学习写文章一样,认识所有的语法知识,认识所有的汉字,但是不一定能够写出词藻华丽的文章。所以编程语言只是础知识,想要更进一步,还得学会设计和分析。下面将使用Python语言去练习24个经典的设计模式,从中体会编程的艺术。主要参考资料为:《大话设计模式》Python版代码实现
一、简单工厂模式
简单工厂模式就是定义一个简单工厂类,由工厂类向调用者client提供不同的产品类,也就是说client只需要提供自己的需要,工厂类提供产品,具体的实现位于产品类当中。
考虑用一个四则运算的例子,用简单工厂模式来实现。
简单工厂模式#!/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()
二、策略模式
我们都知道诸葛亮三个锦囊帮助刘备抱得美人归的故事。所谓的锦囊妙计,就是依据不同的情况选择不同的计策去执行,执行的过程是固定的,变化的是计策的内容。也就是说由client刘备去负责执行策略的流程,但是具体的计策,由每个具体的策略来实现。
类图如下所示:
策略模式#!/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()
四、工厂方法模式
工厂方法就是指一个工厂类负责一个产品类的生产。定义一个用于创建对象的接口,让子类决定实例化哪一个类。这使得一个类的实例化延迟到其子类。
工厂方法模式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()
五、原型模式
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式Python为对象提供的copy模块中的copy方法和deepcopy方法已经实现了原型模式。
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']]
六、模板方法模式
定义一个操作中的算法骨架,将一些步骤延迟至子类中。
模板方法模式举个例子,考试时使用同一种考卷(父类),不同学生上交自己填写的试卷(子类方法的实现)
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()
p = ThinPerson()
d = Director(p)
d.Create()
九、观察者模式
定义了一种一对多的关系,让多个观察对象同时监听一个主题对象,当主题对象状态发生变化时会通知所有观察者。
观察者模式程序实例:公司里有两种上班时趁老板不在时偷懒的员工:看NBA的和看股票行情的,并且事先让老板秘书当老板出现时通知他们继续做手头上的工作。
#!/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()
十、状态模式
当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
程序实例:描述一个程序员的工作状态,当需要改变状态时发生改变,不同状态下的方法实现不同
``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()
# 十一、适配器模式
将一个类的接口转换成为客户希望的另外一个接口。
比如说我们现在已经有了一个类,但是使用是这个类可能会有不同的预处理,那么可以添加一个适配器来做预处理并负责访问现有的类。
![适配器模式](https://img.haomeiwen.com/i648342/31a36aac2da073c3.png)
```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()
十二、备忘录模式
不破坏封装性的前提下捕获一个对象的内部状态,并在该对象之外保存这个状态,以后可以将对象恢复到这个状态。
备忘录模式程序实例:将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真的需要单例模式吗?我指像其他编程语言中的单例模式。
答案是:不需要!
因为,Python有模块(module),最pythonic的单例典范。
模块在在一个应用程序中只有一份,它本身就是单例的,将你所需要的属性和方法,直接暴露在模块中变成模块的全局变量和方法即可!
十八、桥接模式
模式特点:将抽象部分与它的实现部分分离,使它们都可以独立地变化。
桥接模式程序实例:两种品牌的手机,要求它们都可以运行游戏和通讯录两个软件,而不是为每个品牌的手机都独立编写不同的软件。
代码特点:虽然使用了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()
十七、命令模式
模式特点:将请求封装成对象,从而使可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。
程序实例:烧烤店有两种食物,羊肉串和鸡翅。客户向服务员点单,服务员将点好的单告诉大厨,由大厨进行烹饪。
#!/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用于穷举这些元素),不同的遭遇(具体的访问者)引发两种对象的不同行为。
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)
二十、装饰模式
模式特点:动态地为对象增加额外的职责
装饰模式程序实例:展示一个人一件一件穿衣服的过程。
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()