Python设计模式-结构型:适配器模式,装饰者模式,代理模式,组合模式,外观模式
作者:互联网
Python设计模式-结构型:适配器模式,装饰者模式,代理模式,组合模式,外观模式
- 适配器模式定义及简单实现案例
- 装饰者模式定义及简单实现案例
- 代理模式定义及简单实现案例
- 组合模式定义及简单实现案例
- 外观模式定义及简单实现案例
适配器模式 adapter
电子产品的电源插头插在转换插头上,然后转换插头插上电源,电子产品就能正常工作了。这就是适配器模式
# -*- coding: utf-8 -*-
class OldCourse(object):
"""
老的课程类
"""
def show(self):
"""
显示关于本课程的所有信息
"""
print("show description")
print("show teacher of course")
print("show labs")
class Page(object):
"""
使用课程对象的客户端
"""
def __init__(self, course):
self.course = course
def render(self):
self.course.show()
class NewCourse(object):
"""
新的课程类, 为了模块化显示课程信息,实现了新的课程类
"""
def show_desc(self):
"""
显示描述信息
"""
print("show description")
def show_teacher(self):
"""
显示老师信息
"""
print("show teacher of course")
def show_labs(self):
"""
显示实验
"""
print("show labs")
class Adapter(object):
"""
适配器, 尽管实现了新的课程类,但是在很多代码中还是需要使用 OldCourse.show() 方法
"""
def __init__(self, course):
self.course = course
def show(self):
"""
适配方法,调用真正的操作
"""
self.course.show_desc()
self.course.show_teacher()
self.course.show_labs()
if __name__ == '__main__':
old_course = OldCourse()
page = Page(old_course)
page.render()
print("")
new_course = NewCourse()
# 新课程类没有 show 方法,我们需要使用适配器进行适配
adapter = Adapter(new_course)
page = Page(adapter)
page.render()
适配器模式就是把一个类的接口变换成客户端所期待的另一种接口,使原本因接口不兼容而无法在一起工作的两个类能够在一起工作。
装饰者模式 Decorator
装饰者模式能动态的给对象添加行为。如果你对 Flask 比较熟悉的话,应该知道在使用 Flask-Login 的时候可以使用 login_required 装饰器包装一个需要用户登录访问的view
# -*- coding: utf-8 -*-
from functools import wraps
HOST_DOCKER = 0
def docker_host_required(f):
"""
装饰器,必须要求 host 类型是 HOST_DOCKER
"""
@wraps(f)
def wrapper(*args, **kwargs):
if args[0].type != HOST_DOCKER:
raise Exception("Not docker host")
else:
return f(*args, **kwargs)
return wrapper
class Host(object):
"""
host 类
"""
def __init__(self, type):
self.type = type
# 装饰这一方法
@docker_host_required
def create_container(self):
print("create container")
if __name__ == '__main__':
# 初始化 Host
host = Host(HOST_DOCKER)
host.create_container()
print("")
# 再次初始化 Host
host = Host(1)
host.create_container()
在上面的代码中,Host有一个方法Host.create_container,只有当Host实例的类型是DOCKER_HOST的时候才能执行该方法。为了加上这一行为,我们使用了装饰者模式。可以看出使用装饰者模式,我们可以动态改变类的行为,同时能提高代码复用性,因为任何类型为HOST_DOCKER的Host都可以使用该装饰器。另外要说明下:为了更好的实现装饰器,我们使用functools.wrap函数。
代理模式 proxy
所谓代理模式就是给一个对象提供一个代理,并由代理对象控制对原对象的访问。通过代理,我们可以对访问做一些控制。在开发网站的过程中,针对一些频繁访问的资源,我们会使用缓存。
# -*- coding: utf-8 -*-
from time import sleep
class Redis(object):
"""
用于模拟 redis 服务
"""
def __init__(self):
"""
使用字典存储数据
"""
self.cache = dict()
def get(self, key):
"""
获取数据
"""
return self.cache.get(key)
def set(self, key, value):
"""
设置数据
"""
self.cache[key] = value
class Image(object):
"""
图片对象,图片存在七牛云存储中,我们只保存了一个地址
"""
def __init__(self, name):
self.name = name
@property
def url(self):
sleep(2)
return "https://dn-syl-static.qbox.me/img/logo-transparent.png"
class Page(object):
"""
用于显示图片
"""
def __init__(self, image):
"""
需要图片进行初始化
"""
self.image = image
def render(self):
"""
显示图片
"""
print(self.image.url)
redis = Redis()
class ImageProxy(object):
"""
图片代理,首次访问会从真正的图片对象中获取地址,以后都从 Redis 缓存中获取
"""
def __init__(self, image):
self.image = image
@property
def url(self):
addr = redis.get(self.image.name)
if not addr:
addr = self.image.url
print("Set url in redis cache!")
redis.set(self.image.name, addr)
else:
print("Get url from redis cache!")
return addr
if __name__ == '__main__':
img = Image(name="logo")
proxy = ImageProxy(img)
page = Page(proxy)
# 首次访问
page.render()
print("")
# 第二次访问
page.render()
代理对象和真实的对象之间都实现了共同的接口,这使我们可以在不改变原接口情况下,使用真实对象的地方都可以使用代理对象。其次,代理对象在客户端和真实对象之间直接起到了中介作用,同时通过代理对象,我们可以在将客户请求传递给真实对象之前做一些必要的预处理。
组合模式 composite
什么是组合模式?按照定义来说,组合模式是将对象组合成树形结构表示,使得客户端对单个对象和组合对象的使用具有一致性。组合模式的使用通常会生成一棵对象树,对象树中的叶子结点代表单个对象,其他节点代表组合对象。调用某一组合对象的方法,其实会迭代调用所有其叶子对象的方法。
使用组合模式的经典例子是 Linux 系统内的树形菜单和文件系统。在树形菜单中,每一项菜单可能是一个组合对象,其包含了菜单项和子菜单,这样就形成了一棵对象树。在文件系统中,叶子对象就是文件,而文件夹就是组合对象,文件夹可以包含文件夹和文件,同样又形成了一棵对象树。同样的例子还有员工和领导之间的关系
# -*- coding: utf-8 -*-
import abc
class Worker(object):
"""
员工抽象类
"""
__metaclass__ = abc.ABCMeta
def __init__(self, name):
self.name = name
@abc.abstractmethod
def work(self):
pass
class Employe(Worker):
"""
员工类
"""
__metaclass__ = abc.ABCMeta
def work(self):
print("Employ: %s start to work " % self.name)
class Leader(Worker):
"""
领导类
"""
def __init__(self, name):
self.members = []
super(Leader, self).__init__(name)
def add_member(self, employe):
if employe not in self.members:
self.members.append(employe)
def remove_member(self, employe):
if employe in self.members:
self.members.remove(employe)
def work(self):
print("Leader: %s start to work" % self.name)
for employe in self.members:
employe.work()
if __name__ == '__main__':
employe_1 = Employe("employe_1")
employe_2 = Employe("employe_2")
leader_1 = Leader("leader_1")
leader_1.add_member(employe_1)
leader_1.add_member(employe_2)
employe_3 = Employe("employe_3")
leader_2 = Leader("leader_2")
leader_2.add_member(employe_3)
leader_2.add_member(leader_1)
leader_2.work()
外观模式 facade
所谓外观模式,就是将各种子系统的复杂操作通过外观模式简化,让客户端使用起来更方便简洁。
- 比如你夏天晚上出门时,要关闭电灯,关闭电视机,关闭空调,如果有了一个总开关,通过它可以关闭电灯,电视机和空调,你出门的时候关闭总开关就行了。
- 在这个例子中,你就是客户端,总开关就是外观模式的化身
# -*- coding: utf-8 -*-
class User(object):
"""
用户类
"""
def is_login(self):
return True
def has_privilege(self, privilege):
return True
class Course(object):
"""
课程类
"""
def can_be_learned(self):
return True
class Lab(object):
"""
实验类
"""
def can_be_started(self):
return True
class Client(object):
"""
客户类,用于开始一个实验
"""
def __init__(self, user, course, lab):
self.user = user
self.course = course
self.lab = lab
def start_lab(self):
"""
开始实验,需要一系列的判断:用户是否登录,课程是否可以学习,实验是否可以开始。判断非常繁琐!
"""
if self.user.is_login() and self.course.can_be_learned() and self.lab.can_be_started():
print("start lab")
else:
print("can not start lab")
class FacadeLab(object):
"""
新的Lab类,应用了面向对象模式
"""
def __init__(self, user, course, lab):
self.user = user
self.course = course
self.lab = lab
def can_be_started(self):
if self.user.is_login() and self.course.can_be_learned() and self.lab.can_be_started():
return True
else:
return False
class NewClient(object):
"""
新的客户类,使用外观模式
"""
def __init__(self, facade_lab):
self.lab = facade_lab
def start_lab(self):
"""
开始实验,只需要判断 FacadeLab 是否可以开始
"""
if self.lab.can_be_started:
print("start lab")
else:
print("can not start lab")
if __name__ == '__main__':
user = User()
course = Course()
lab = Lab()
client = Client(user, course, lab)
client.start_lab()
print("Use Facade Pattern:")
facade_lab = FacadeLab(user, course, lab)
facade_client = NewClient(facade_lab)
facade_client.start_lab()
外观模式的主要目的在于降低系统的复杂程度,在面向对象软件系统中,类与类之间的关系越多,不能表示系统设计得越好,反而表示系统中类之间的耦合度太大,这样的系统在维护和修改时都缺乏灵活性,因为一个类的改动会导致多个类发生变化,而外观模式的引入在很大程度上降低了类与类之间的耦合关系。引入外观模式之后,增加新的子系统或者移除子系统都非常方便,客户类无须进行修改(或者极少的修改),只需要在外观类中增加或移除对子系统的引用即可。
标签:__,适配器,模式,course,lab,print,设计模式,self,def 来源: https://www.cnblogs.com/oceaneyes-gzy/p/16462979.html