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()
外观模式的主要目的在于降低系统的复杂程度,在面向对象软件系统中,类与类之间的关系越多,不能表示系统设计得越好,反而表示系统中类之间的耦合度太大,这样的系统在维护和修改时都缺乏灵活性,因为一个类的改动会导致多个类发生变化,而外观模式的引入在很大程度上降低了类与类之间的耦合关系。引入外观模式之后,增加新的子系统或者移除子系统都非常方便,客户类无须进行修改(或者极少的修改),只需要在外观类中增加或移除对子系统的引用即可。
当前题目:Python设计模式-结构型:适配器模式,装饰者模式,代理模式,组合模式,外观模式
路径分享:http://www.scyingshan.cn/article/dscgide.html

 建站
建站
 咨询
咨询 售后
售后
 建站咨询
建站咨询 
 