[Python设计模式] 第7章 找人帮忙追美眉——代理模式

github地址:https://github.com/cheesezh/python_design_patterns

题目1

Boy追求Girl,给Girl送鲜花,送巧克力,送洋娃娃。

class Boy():
    def __init__(self, girl):
        self.girl = girl
    
    def give_dolls(self):
        print("{}, 送你洋娃娃".format(self.girl.name))
    
    def give_flowers(self):
        print("{}, 送你鲜花".format(self.girl.name))

    def give_chocolate(self):
        print("{}, 送你巧克力".format(self.girl.name))
        
class Girl():
    def __init__(self, name):
        self.name = name
    
def main():
    mm = Girl("曼曼")
    gg = Boy(mm)
    
    gg.give_dolls()
    gg.give_chocolate()
    gg.give_flowers()

main()
曼曼, 送你洋娃娃
曼曼, 送你巧克力
曼曼, 送你鲜花

题目2

假设Boy并不认识Girl,Boy希望让Proxy帮他把鲜花,巧克力,洋娃娃转交给Girl。

class Proxy():
    def __init__(self, girl):
        self.girl = girl
    
    def give_dolls(self):
        print("{}, 送你洋娃娃".format(self.girl.name))
    
    def give_flowers(self):
        print("{}, 送你鲜花".format(self.girl.name))

    def give_chocolate(self):
        print("{}, 送你巧克力".format(self.girl.name))
        
class Girl():
    def __init__(self, name):
        self.name = name
    
def main():
    mm = Girl("曼曼")
    proxy = Proxy(mm)
    
    proxy.give_dolls()
    proxy.give_chocolate()
    proxy.give_flowers()

main()
曼曼, 送你洋娃娃
曼曼, 送你巧克力
曼曼, 送你鲜花

点评

这样看上去的确是Proxy送给Girl的各种礼物,但是这些礼物其实是Boy的,在代码中并没有体现这一点。在代码中如何体现表面上是Proxy送的礼物,实际上是Boy送的礼物呢?这需要用到代理模式,把送礼物封装成接口,然后让Boy和Proxy都去实现这个接口,Boy和Proxy的区别就是Proxy的接口实现要调用Boy的接口实现。

Python中没有明确的接口定义方法,抽象接口可以看作编程人员对自己编码行为的约束,让自己按照一定的规矩写代码。为了实现同样的目的,在Python中可以通过定义一个抽象类来达到相同的目的。

from abc import ABCMeta, abstractmethod


class IGiveGift():

    __metaclass__ = ABCMeta
    
    @abstractmethod
    def give_dolls(self):
        pass
    
    @abstractmethod
    def give_flowers(self):
        pass
    
    @abstractmethod
    def give_chocolate(self):
        pass
    
    
class Boy(IGiveGift):
    
    def __init__(self, girl):
        self.girl = girl
    
    def give_dolls(self):
        print("{}, 送你洋娃娃".format(self.girl.name))
    
    def give_flowers(self):
        print("{}, 送你鲜花".format(self.girl.name))

    def give_chocolate(self):
        print("{}, 送你巧克力".format(self.girl.name))
        
        
class Proxy(IGiveGift):
    
    def __init__(self, girl):
        self.gg = Boy(girl)
    
    def give_dolls(self):
        self.gg.give_dolls()
    
    def give_flowers(self):
        self.gg.give_flowers()

    def give_chocolate(self):
        self.gg.give_chocolate()
        
def main():
    mm = Girl("曼曼")
    proxy = Proxy(mm)
    
    proxy.give_dolls()
    proxy.give_chocolate()
    proxy.give_flowers()

main()
曼曼, 送你洋娃娃
曼曼, 送你巧克力
曼曼, 送你鲜花

点评

现在从代码中可以清晰的看出,表面上是proxy送给Girl mm的礼物,但是其实是Boy gg送的。

代理模式

代理模式,为其他对象提供一种代理以控制对这个对象的访问。在上述场景中,mm和gg并没有直接的联系,即mm和gg互相无法访问到,但是可以通过proxy来达到gg送mm礼物的效果。

代理模式主要包括三种类:

  • Subject类:例如IGiveGift类,定义了RealSubject和Proxy的功用接口,这样就在任何使用RealSubject的地方使用Proxy;
  • RealSubject类:例如Boy类,定义Proxy所代表的真实实体;
  • Proxy类:例如Porxy类,保存一个引用是的代理可以访问实体,并提供一个于Subject的接口相同的接口,这样代理就可以用来代替实体;

代理模式应用主要包括以下几种:

  • 远程代理,也就是为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实[DP]。
  • 虚拟代理,是根据需要创建开销很大的对象。通过它来存在实例化需要很长时间的真实对象[DP]。浏览器优化下载就是用的代理模式,例如打开一个很大的HTML网页时,里面可能由很多文字和图片,但是依然可以很快打开,优先看到文字,但是图片还在一张一张下载。哪些未打开的图片框,就是通过虚拟代理来替代真实图片,此时代理存储了真实图片的路径和尺寸。
  • 安全代理,用来控制真实对象访问时的权限[DP]。一般用于对象应该有不同的访问权限的时候。
  • 智能指引,是指当调用真实的对象时,代理处理另外一些事[DP]。例如计算真实对象的引用次数,这样当该对象没有引用时,可以自动释放它;或者当第一引用一个持久对象时,将它装入内存;或在访问一个实际对象前,检查是否已经锁定它,以确保其他对象不能改变它。这些都是通过代理在访问一个对象时附加一些内务处理。
posted @ 2018-07-29 08:25  ZH奶酪  阅读(274)  评论(0编辑  收藏  举报