1.创建型模式
单例模式
单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象
class Singleton(object):
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
Singleton._instance = object.__new__(cls)
return Singleton._instance
obj1 = Singleton()
obj2 = Singleton()
print(obj1, obj2) # <__main__.Singleton object at 0x000001F2C74E4D08> <__main__.Singleton object at 0x000001F2C74E4D08>
工厂模式
工厂模式是一个在软件开发中用来创建对象的设计模式。
工厂模式包涵一个超类。这个超类提供一个抽象化的接口来创建一个特定类型的对象,而不是决定哪个对象可以被创建。
为了实现此方法,需要创建一个工厂类创建并返回。
当程序运行输入一个“类型”的时候,需要创建于此相应的对象。这就用到了工厂模式。在如此情形中,实现代码基于工厂模式,可以达到可扩展,可维护的代码。当增加一个新的类型,不在需要修改已存在的类,只增加能够产生新类型的子类。
简短的说,当以下情形可以使用工厂模式:
1.不知道用户想要创建什么样的对象
2.当你想要创建一个可扩展的关联在创建类与支持创建对象的类之间。
一个例子更能很好的理解以上的内容:
- 我们有一个基类Person ,包涵获取名字,性别的方法 。有两个子类male 和female,可以打招呼。还有一个工厂类。
- 工厂类有一个方法名getPerson有两个输入参数,名字和性别。
- 用户使用工厂类,通过调用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("zhangsan", "M")
print(person)
建造者模式
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
相关模式:思路和模板方法模式很像,模板方法是封装算法流程,对某些细节,提供接口由子类修改,建造者模式更为高层一点,将所有细节都交由子类实现。例如C++模板中可以定义一个类实现数字可以相加,字符串也可以相加的功能,模板中只要传入相应的类型底层就可以自动判断是字符串还是数字,并且返回指定的结果
一个例子更能很好的理解以上的内容:
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()
原型模式
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式本质就是克隆对象,所以在对象初始化操作比较复杂的情况下,很实用,能大大降低耗时,提高性能,因为“不用重新初始化对象,而是动态地获得对象运行时的状态”。
浅拷贝(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)
print(b1)
print(b2)
print("ID b1 : {} != ID b2 : {}".format(id(b1), id(b2)))
if __name__ =='__main__':
main()
'''
C:/Users/wangxianchao/PycharmProjects/PythonStudy/多线程.py
odict_keys(['authors', 'length', 'name', 'price', 'publication_date', 'publisher', 'tags'])
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')
odict_keys(['authors', 'edition', 'length', 'name', 'price', 'publication_date', 'publisher', 'tags'])
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 : 1922565623240 != ID b2 : 1922565694600
Process finished with exit code 0
'''
2.结构性模式
适配器模式
假设一个旧系统有一个类computer,后来丰富了该系统,又添加了两个新类,从上面代码可以看出: Synthesizer 类,主要动作由play()方法执行。Human类主要动作由speak()方法执行。而原来的类 Computer其动作由execute()方法执行。并且对于原来的老系统来说,所有动作函数均使用 Obj.execute() 来执行。即对于调用者来说,新系统的组件 Synthesizer.play() 和 Human.speak() 是不存在的,必须像调用 Computer.execute() 一样使用 Synthesizer.execute() 和 Human.execute() 来调用原系统中对象的执行函数。而这就是我们所说的常见,在无法修改 旧系统的调用方式和修改其源代码的请求下,为了让新组件去适应(兼容)旧系统的情况。所以这边我们可以使用适配器模式来解决。
class Computer(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'the {} computer'.format(self.name)
def execute(self):
return 'execute a program'
class Synthesizer:
def __init__(self, name):
self.name = name
def __str__(self):
return 'the {} synthesizer'.format(self.name)
def play(self):
return 'is playing an electronic song'
class Human:
def __init__(self, name):
self.name = name
def __str__(self):
return '{} the human'.format(self.name)
def speak(self):
return 'says hello'
class Adapter:
def __init__(self, obj, **kwargs):
self.obj = obj
self.__dict__.update(kwargs)
def __str__(self):
return str(self.obj)
def main():
objects = [Computer('apple')]
people = Human('Jact')
objects.append(Adapter(people, execute=people.speak))
synth = Synthesizer('moog')
objects.append((Adapter(synth, execute=synth.play)))
for x in objects:
print('{} {}'.format(str(x), x.execute()))
print('type is {}'.format(type(x)))
if __name__ == '__main__':
main()
'''
the apple computer execute a program
type is <class '__main__.Computer'>
Jact the human says hello
type is <class '__main__.Adapter'>
the moog synthesizer is playing an electronic song
type is <class '__main__.Adapter'>
Process finished with exit code 0
'''
修饰器模式
动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator 模式相比生成子类更为灵活。
适用性:
在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
处理那些可以撤消的职责。
当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
class foo(object):
def f1(self):
print('original f1')
def f2(self):
print('original f2')
class foo_decorator(object):
def __init__(self, decorator):
self._decotator = decorator
def f1(self):
print('decorator f1')
self._decotator.f1()
def __getattr__(self, name):
return getattr(self._decotator, name)
u = foo()
v = foo_decorator(u)
v.f1()
v.f2()
'''
decorator f1
original f1
original f2
'''
外观模式
享元模式
享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度的对象.
享元模式可以避免大量非常相似类的开销,在程序设计中,有时会生成大量细粒度的类实例来表示数据,如果这些实例除了几个参数外基本相同,就可以把参数已到实例外面,在方法调用时,把它们传进来,就可以通过共享大幅度减少单个实例的数目
class Website(object):
def use(self):
pass
class ConcreateWebsite(Website):
def __init__(self,name):
self.name = name
def use(self):
print('网站分类',self.name)
class UnshareConcreateWebsite(Website):
def __init__(self, name):
self.name = name
def use(self):
print("不共享网站分类", self.name)
class WebsiteFactory(object):
def __init__(self):
self.hashtable = dict()
def get_website(self,key):
if not key in self.hashtable:
self.hashtable[key] = ConcreateWebsite(key)
return self.hashtable[key]
def get_website_count(self):
return len(self.hashtable.keys())
if __name__ == '__main__':
factory = WebsiteFactory()
f1 = factory.get_website('blog')
f2 = factory.get_website('blog')
f3 = factory.get_website('blog')
f4 = factory.get_website('website')
f5 = factory.get_website('website')
f6 = factory.get_website('website')
f7 = UnshareConcreateWebsite('test')
f1.use()
f2.use()
f3.use()
f4.use()
f5.use()
f6.use()
f7.use()
num = factory.get_website_count()
print(num)
'''
打印结果:
网站分类 blog
网站分类 blog
网站分类 blog
网站分类 website
网站分类 website
网站分类 website
不共享网站分类 test
2
Process finished with exit code 0
'''
模型-视图-控制器模式
代理模式
代理模式的应用场景:
1.远程代理,也就是为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。
2.虚拟代理,是根据需要创建开销大的对象。通过它来存放实例化需要很长时间的真是对象,例如html中,图片需要load很久,所以通过虚拟代理来代替真实的图片
3.安全代理,用来控制真实对象访问时的权限
4.智能指引,是指当调用真实的对象时,代理处理另外一些事
from abc import ABCMeta, abstractmethod
class Female():
def __init__(self, name):
self.name = name
class Male():
__metaclass__ = ABCMeta
@abstractmethod
def send_flower(self):
pass
@abstractmethod
def send_chocolate(self):
pass
@abstractmethod
def send_book(self):
pass
class MaleA(Male):
def __init__(self, name, love_female):
self.name = name
self.love_female = Female(love_female)
def send_flower(self):
print('%s送花给%s' % (self.name, self.love_female.name))
def send_chocolate(self):
print('%s送巧克力给%s' % (self.name, self.love_female.name))
def send_book(self):
print('%s送书给%s' % (self.name, self.love_female.name))
class Proxy(Male):
def __init__(self, name, proxy_name, love_female):
self.name = name
self.proxyed = MaleA(proxy_name, love_female)
def send_flower(self):
self.proxyed.send_flower()
def send_chocolate(self):
self.proxyed.send_chocolate()
def send_book(self):
self.proxyed.send_book()
if __name__ == '__main__':
p = Proxy('男B', '男A', '女A')
p.send_chocolate()
p.send_book()
p.send_flower()
'''
男A送巧克力给女A
男A送书给女A
男A送花给女A
'''
组合模式
意图: 将对象组合成树形结构以表示“部分-整体”的层次结构。C o m p o s i t e 使得用户对单个对象和组合对象的使用具有一致性。
适用性:你想表示对象的部分-整体层次结构。
你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
class Component:
def __init__(self,strName):
self.m_strNmae = 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 = "-"*nDepth
strtemp = strtemp + self.m_strNmae
print(strtemp)
class Composite(Component):
def __init__(self,strName):
self.m_strNmae = strName
self.c = []
def Add(self,com):
self.c.append(com)
def Display(self,nDepth):
strtemp = "-"*nDepth
strtemp += self.m_strNmae
print(strtemp)
for com in self.c:
com.Display(nDepth+3)
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(3)
'''
---wong
------Lee
------zhao
------Wu
---------San
'''
3.行为模式
责任链模式
意图:
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
适用性:
有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
可处理一个请求的对象集合应被动态指定。
class BaseHandler(object):
'''处理基类'''
def __init__(self,successor):
self._successor = successor
class RequestHandlerL1(BaseHandler):
'''第一级别请求处理者'''
name = "TeamLeader"
def handle(self,request):
if request<500:
print('审批者[%s],请求金额[%s],审批结果[审批通过]' % (self.name,request))
else:
print("\033[31;1m[%s]无权审批,交给下一个审批者\033[0m" % self.name)
self._successor.handle(request)
class RequestHandlerL2(BaseHandler):
'''第二级请求处理者'''
name = "DeptManager"
def handle(self,request):
if request < 5000 :
print("审批者[%s],请求金额[%s],审批结果[审批通过]"%(self.name,request))
else:
print("\033[31;1m[%s]无权审批,交给下一个审批者\033[0m" %self.name)
self._successor.handle(request)
class RequestHandlerL3(BaseHandler):
'''第二级请求处理者'''
name = "CEO"
def handle(self,request):
if request < 10000 :
print("审批者[%s],请求金额[%s],审批结果[审批通过]"%(self.name,request))
else:
print("\033[31;1m[%s]无权审批,交给下一个审批者\033[0m" %self.name)
self._successor.handle(request)
class RequestAPI(object):
h3 = RequestHandlerL3(None)
h2 = RequestHandlerL2(h3)
h1 = RequestHandlerL1(h2)
def __init__(self,name,amount):
self.name = name
self.amount = amount
def handle(self):
self.h1.handle(self.amount)
if __name__=='__main__':
r1 = RequestAPI("Burgess", 8000)
r1.handle()
print(r1.__dict__)
'''
[TeamLeader]无权审批,交给下一个审批者
[DeptManager]无权审批,交给下一个审批者
审批者[CEO],请求金额[8000],审批结果[审批通过]
{'name': 'Burgess', 'amount': 8000}
'''
命令模式
解释器模式
意图:
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
适用性:
当有一个语言需要解释执行, 并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时该模式效果最好:
该文法简单对于复杂的文法, 文法的类层次变得庞大而无法管理。此时语法分析程序生成器这样的工具是更好的选择。它们无需构建抽象语法树即可解释表达式, 这样可以节省空间而且还可能节省时间。
效率不是一个关键问题最高效的解释器通常不是通过直接解释语法分析树实现的, 而是首先将它们转换成另一种形式。例如,正则表达式通常被转换成状态机。但即使在这种情况下, 转换器仍可用解释器模式实现, 该模式仍是有用的。
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)
'''
terminal interpret
Nonterminal interpret
terminal interpret
terminal interpret
'''
观察者模式
简单理解:观察者模式即为许多对象等待着某个主题对象的新消息,当主题对象有了新消息的时候,它就会通知所有的观察着它的对象,就像是很多的用户都订阅了一位新闻发布者,当新闻发布者发布了一个新的新闻后,他就会通知它的所有订阅者,就像是手机上一些应用的通知栏通知。
from abc import ABCMeta,abstractmethod
class NewsPublisher:
def __init__(self):
self.__subcribers = []
self.__latestNews = None
def attach(self,subscriber):
self.__subcribers.append(subscriber)
def detach(self):
return self.__subcribers.pop()
def notifySubscribers(self):
for sub in self.__subcribers:
sub.update()
def addNews(self,news):
self.__latestNews = news
def getNews(self):
return 'Got:' + self.__latestNews
class Subscriber(metaclass=ABCMeta):
@abstractmethod
def update(self):
pass
class ConcreteSubscriber1:
def __init__(self,publisher):
self.publisher = publisher
self.publisher.attach(self)
def update(self):
print(type(self).__name__,self.publisher.getNews())
class ConcreteSubscriber2:
def __init__(self,publisher):
self.publisher = publisher
self.publisher.attach(self)
def update(self):
print(type(self).__name__,self.publisher.getNews())
news_publisher = NewsPublisher()
for Subscriber in [ConcreteSubscriber1,ConcreteSubscriber1]:
Subscriber(news_publisher)
news_publisher.addNews("Hello World")
news_publisher.notifySubscribers()
news_publisher.detach()
news_publisher.addNews('SECOND NEWS')
news_publisher.notifySubscribers()
'''
ConcreteSubscriber1 Got:Hello World
ConcreteSubscriber1 Got:Hello World
ConcreteSubscriber1 Got:SECOND NEWS
Process finished with exit code 0
'''