结构性模式

一、适配器模式

1.1内容

将一个类的接口转换成客户希望的另一个接口。
#插头德国的和中国的不一样,去德国旅游的时候就需要买一个装接头,转换成我们需要的接头就可以给手机充电了
#解决的问题:适配器模式使得原来由于接口不兼容而不能一起工作的那些类可以一起工作。就上个例子而言没有适配器,手机和德国的插头时没有办法一起工作的,有了适配器,手机就可以充电了。

1.2角色

目标接口(Target)
待适配的类(Adaptee)
适配器(Adapter)

1.3两种实现方式

类适配器:使用多继承(类的适配器模式是把适配的类的API转换成为目标类的API)
对象适配器:使用组合

1.4适用场景

想使用一个已经存在的类,而它的接口不符合你的要求
(对象适配器)想使用一些已经存在的子类,但不可能对每一个都进行子类化以匹配他们的接口。对象适配器可以适配它的接口

1.5图解

1.6代码示例

from  abc import abstractmethod,ABCMeta
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self,money):
        raise NotImplementedError
class Alipay(Payment):
    def pay(self, money):
        print("支付宝支付%s元"%money)


class ApplePay(Payment):
    def pay(self, money):
        print("苹果支付%s元"%money)

# =========待适配器==========
class WechatPay:
    def huaqian(self,a,b):
        print("微信支付%s元" % (a + b))

# ==========类适配器===========
class RealWeChatPay(Payment,WechatPay):
    def pay(self,money):
        return self.huaqian(money,0)


#===========对象适配器===========
class PavAdepter(Payment):
    def __init__(self,payment):
        self.payment = payment
        
    def pay(self,money):
        return self.payment.huaqian(money,0)

######使用=============
PavAdepter(WechatPay()).pay(100)

二、组合模式

2.1内容

将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性
本质:统一叶子对象和组合对象
组合模式的目的:让客户端不再区分操作的是组合对象还是叶子对象,而是以一个统一的方式来操作

2.2 角色

抽象组件
叶子组件
复合组件
客户端

2.3优点

定义了包含基本对象和组合的类层次结构
简化客户端代码,即客户端可以一致地使用组合对象和单个对象
更容易增加新类型的组件

2.4缺点

很难限制组合中的组件

2.5适用场景

表示对象的‘部分-整体’层次结构(特别是结构是递归的)
希望用户忽略组合对象与单个对象的不同,用户统一的使用组合结构中的所有对象

2.6图解

2.7代码实现

from abc import abstractmethod,ABCMeta
class Graphic(metaclass=ABCMeta):
    '''图形类'''
    @abstractmethod
    def draw(self):
        pass

    @abstractmethod
    def add(self,graphic):
        pass

    @abstractmethod
    def getchildren(self,graphic):
        pass

class Point(Graphic):
    '''点'''
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def draw(self):
        print(self)

    def add(self,graphic):
        raise TypeError

    def getchildren(self,graphic):
        raise TypeError

    def __str__(self):
        return '点(%s,%s)' %(self.x,self.y)

class Line(Graphic):
    def __init__(self, p1, p2):
        self.p1 = p1
        self.p2 = p2

    def draw(self):
        print(self)

    def add(self, graphic):
        raise TypeError

    def getchildren(self):
        raise TypeError

    def __str__(self):
        return "线段[%s, %s]" % (self.p1, self.p2)

class Picture(Graphic):
    def __init__(self):
        self.children = []

    def add(self,graphic):
        self.children.append(graphic)

    def getchildren(self, graphic):
        '''返回列表里面的孩子'''
        return self.children

    def draw(self):
        print('======复合图形======')
        for i in self.children:
            print('所有的孩子们',i)
            i.draw()
        print('======end=========')


pic1 = Picture()
pic1.add(Point(2,3))
pic1.add(Line(Point(1,2), Point(4,5)))
pic1.add(Line(Point(0,1), Point(2,1)))


pic2 = Picture()
pic2.add(Point(-2,-1))
pic2.add(Line(Point(0,0), Point(1,1)))

pic = Picture()
pic.add(pic1)
pic.add(pic2)

pic.draw()
.draw这个函数对外表现一致,所有的都调用这个方法、

三、代理模式

3.1内容

为其他对象提供一种代理以控制对这个对象的访问。简单的说就是我们生活中常见的中介

3.2角色

抽象实体
实体
代理
#抽象实体定义一个接口q,实例A和代理B全部实现这个接口,代理中对实例A进行了实例化,调用B的q相当于调用了A的q,白话一点就是原来实例化A,现在实例化B,使用相同的方法就是得到同样的东西。
#代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则(结合linux举例)

3.3使用场景

远程代理:为远程的对象提供代理
虚代理:根据需求创建很大的对象
保护代理:控制对原始对象的访问,用于对象有不同访问权限时,比如只读不能写  #一旦调用修改的操作就会报错

3.4为什么要使用代理

1、中介隔离作用

在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口

2、开发封闭原则

代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类

3.5注意事项

和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。

3.6图解结构

3.7代码事项

from abc import abstractmethod,ABCMeta

class Subject(metaclass=ABCMeta):
    @abstractmethod
    def get_content(self):
        pass

class RealSubject(Subject):
    def __init__(self,filename):
        self.filename = filename
        print("读取%s文件内容" % filename)
        f = open(filename)
        self.content = f.read()
        f.close()

    def get_content(self):
        return self.content

    def set_content(self, content):
        f = open(self.filename, 'w')
        f.write(content)
        f.close()


class ProxyA(Subject):
    def __init__(self, filename):
        self.subj = RealSubject(filename)

    def get_content(self):
        return self.subj.get_content()

class ProxyB(Subject):
    '''虚代理'''
    def __init__(self, filename):
        self.filename = filename
        self.subj = None

    def get_content(self):
        if not self.subj:  #if True 如果为空的时候,就去读取文本
            self.subj = RealSubject(self.filename)
        return self.subj.get_content()


class ProxyC(Subject):
    '''保护代理'''
    def __init__(self, filename):
        self.subj = RealSubject(filename)

    def get_content(self):
        return self.get_content()

    def set_content(self):
        raise PermissionError

    # 写一个set_content

b = ProxyB("abc.txt")
print(b.get_content())
posted @ 2019-08-24 16:34  与凯学习  阅读(167)  评论(0)    收藏  举报