首页 > 代码库 > Python设计模式
Python设计模式
一.简单工厂模式
首先来看下工厂模式的原理图:
模式特点:工厂根据条件产生不同功能的类。
程序实例:四则运算计算器,根据用户的输入产生相应的运算类,用这个运算类处理具体的运算。
代码特点:C/C++中的switch...case...分支使用字典的方式代替。
使用异常机制对除数为0的情况进行处理。
Python实现代码如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: Jason Wang
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 = input("operator: ")
opa = input("a: ")
opb = input("b: ")
factory = OperationFactory()
cal = factory.createOperation(op)
cal.op1 = int(opa)
cal.op2 = int(opb)
print(cal.GetResult())
二.单例模式
原理图:
模式特点:保证类仅有一个实例,并提供一个访问它的全局访问点。
说明: 为了实现单例模式费了不少工夫,后来查到一篇博文对此有很详细的介绍,而且实现方式也很丰富,通过对代码的学习可以了解更多Python的用法。
我要问的是,Python真的需要单例模式吗?我指像其他编程语言中的单例模式。
答案是:不需要!
因为,Python有模块(module),最pythonic的单例典范。
模块在在一个应用程序中只有一份,它本身就是单例的,将你所需要的属性和方法,直接暴露在模块中变成模块的全局变量和方法即可!
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: Jason Wang
#-*- 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--------------------------‘)
##通过类的静态字段构造类
class CP:
__instance = None
def __init__(self):
self.ip = "1.1.1.1"
self.port = 3306
self.pwd = "123123"
self.user = "xxx"
self.conn_list = [1,2,3,4,5,6]
@staticmethod
def get_instance():
if CP.__instance:
return CP.__instance
else:
# 创建一个对象,并将对象赋值给静态字段__instance
CP.__instance = CP() #执行init方且创建对象,并赋值给私有静态字段
return CP.__instance #将赋值的返回给私有静态字段
obj1 = CP.get_instance() # 静态字段类调用
print(obj1)
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
三.策略模式
原理图:
模式特点:定义算法家族并且分别封装,它们之间可以相互替换而不影响客户端。
程序实例:商场收银软件,需要根据不同的销售策略方式进行收费
代码特点:不同于同例1,这里使用字典是为了避免关键字不在字典导致bug的陷阱。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: Jason Wang
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.")
print()
print(strategy.keys())
if ctype in strategy.keys():
cc = strategy[ctype]
else:
print("Undefine type.Use normal mode.")
cc = strategy[1]
print("you will pay:%d" %(cc.GetResult(int(money))))
四.装饰模式
原理图:
模式特点:动态地为对象增加额外的职责
程序实例:展示一个人一件一件穿衣服的过程。
代码特点:无
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: Jason Wang
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()
五、工厂方法模式
原理图:
模式特点:定义一个用于创建对象的接口,让子类决定实例化哪一个类。这使得一个类的实例化延迟到其子类。
程序实例:基类雷锋类,派生出学生类和志愿者类,由这两种子类完成“学雷锋”工作。子类的创建由雷锋工厂的对应的子类完成。
代码特点:无
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: Jason Wang
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方法已经实现了原型模式,但由于例子的层次较浅,二者看不出区别。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: Jason Wang
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()
print(‘a id is %s‘ %id(a))
print(‘b id is %s‘ %id(b))
print(‘c id is %s‘ %id(c))
print(‘d id is %s‘ %id(d))
###运行结果
"""
12
MidSchool
2001
12
MidSchool
2001
15
HighSchool
2004
18
University
2007
a id is 4323180160
b id is 4323180160
c id is 4323180216
d id is 4323180384
"""
七、模板方法模式
原理图:
Python设计模式