结构型模式

结构型模式用于设计对象和类的结构,从而使它们之间可以互相协作以获取更大的结构。

  • 结构型模式描述如何将对象和类组合成更大的结构
  • 结构型模式是一种能够简化设计工作的模式,因为它能够找出更简单的方法来认识或表示实体之间的关系。在面向对象世界中,实体指的是对象或类
  • 类模式可以通过继承来描述对象,从而提供更有用的程序接口,而对象模式则描述了如何将对象联系起来从而组合成更大的对象。结构型模式是类和对象模式的综合体

门面设计模式

  • 它为子系统的一组接口提供一个统一的接口,并定义一个高级接口来帮助客户端通过更加简单的方式使用子系统
  • 门面模式解决的问题是,如何用的单个接口对象来表示复杂的子系统。实际上它并不是封装子系统,而是对底层子系统进行组合
  • 它促进了实现与多个客户端的解耦

UML图

image-20210225222333048

代码实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/usr/bin/env python
# -*- coding: utf-8 -*-

class EventManager(object):

    def __init__(self):
        print("Event Manager:: Let me talk to the folks\\n")

    def arrange(self):
        self.hotelier = Hotelier()
        self.hotelier.bookHotel()

        self.florist = Florist()
        self.florist.setFlowerRequirements()

        self.caterer = Caterer()
        self.caterer.setCuisine()

        self.musiccian = Musician()
        self.musiccian.setMusicType()

class Hotelier(object):
    def __init__(self):
        print("Arranging the hotel for Marriage ?")

    def __isAvailable(self):
        print("Is the Hotel free for the event on given day?")
        return True

    def bookHotel(self):
        if self.__isAvailable():
            print("Register the Booking \\n\\n")

class Florist(object):
    def __init__(self):
        print("Flower Decorations for the Event ? --")

    def setFlowerRequirements(self):
        print("Carnations, Rose and Lilies would be used for Decorations\\n\\n")

class Caterer(object):
    def __init__(self):
        print("Food Arrangements for the Event --")

    def setCuisine(self):
        print("Chinese & Continental Cuisine to be served \\n\\n")

class Musician(object):
    def __init__(self):
        print("Musical Arrangements for the Marriage --")

    def setMusicType(self):
        print()

class You(object):
    def __init__(self):
        print("you::whoa Marriage Arrangements !")

    def askEventManager(self):
        print("you:: Let is Contact the Event Manager\\n\\n")
        em = EventManager()
        em.arrange()

    def __del__(self):
        print("All preparations done!")

if __name__ == '__main__':
    you = You()
    you.askEventManager()

out
you::whoa Marriage Arrangements !
you:: Let is Contact the Event Manager

Event Manager:: Let me talk to the folks

Arranging the hotel for Marriage ?
Is the Hotel free for the event on given day?
Register the Booking 

Flower Decorations for the Event ? --
Carnations, Rose and Lilies would be used for Decorations

Food Arrangements for the Event --
Chinese & Continental Cuisine to be served 

Musical Arrangements for the Marriage --

All preparations done!

小结

  • EventManager类是简化接口的门面
  • EventManager 通过组合创建子系统对象,如Hotelier,Florist等。

补充:(最少知识原则)

最少知识原则指导我们减少对象之间的交互,就像跟你亲近的只有某几个朋友那样。

  • 在设计系统时,对于创建的每个对象,都应该考察与之交互的类的数量,以及交互的方式
  • 遵循这个原则,就能够避免创建许多彼此紧密耦合的类的情况
  • 如果类之间存在大量的依赖关系,那么系统就会变得难以维护。如果对系统中的任何一部分进行修改,都可能导致系统的其他部分被无意改变,这意味着系统会退化,是应该坚决避免的

代理模式—控制对象的访问

代理通常就是一个介于寻求方和提供方之间的中介系统

代理模式优势

在设计模式中,代理是充当实际对象接口的类

  • 它能够以更简单的方式表示一个复杂的接口
  • 它提高了现有对象的安全性。
  • 它为不同服务器上的远程对象提供了本地接口
  • 它为消耗大量内存的对象提供了一个轻量级的句柄

UML图

image-20210225222800147

  • 代理:它是一个控制对RealSubject类访问的类。它处理客户端的请求,负责创建或删除RealSubject
  • 主题/真实主题:主题是定义真实主题(RealSubject)和代理(Proxy)相类似的接口。RealSubject是Subject接口的实际实现。它提供了真正的功能,然后由客户端使用。
  • 客户端:它访问要完成工作的Proxy类。Proxy类在内部控制对RealSubject的访问,并引导客户端(Client)所请求的工作

代码实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/bin/env python
# -*- coding: utf-8 -*-

class Actor(object):
    def __init__(self):
        self.isBusy = False

    def occupied(self):
        self.isBusy = True
        print(f"{type(self).__name__} is occupied with current movie")

    def available(self):
        self.isBusy = False
        print(f"{type(self).__name__} is free for the movie")

    def getStatus(self):
        return self.isBusy

class Agent(object):
    def __init__(self):
        self.principal = None

    def work(self):
        self.actor = Actor()
        if self.actor.getStatus():
            self.actor.occupied()
        else:
            self.actor.available()

if __name__ == '__main__':
    r = Agent()
    r.work()

虚拟代理

帮助我们控制访问创建开销大的资源

如果一个对象实例化后会占用大量内存的话,可以先利用占位符来表示,这就是所谓的虚拟代理。例如,假设你想在网站上加载大型图片,而这个请求需要很长时间才能加载完成。通常,开发人员将在网页上创建一个占位符图标,以提示这里有图像。但是,只有当用户实际点击图标时才会加载图像,从而节省了向存储器中加载大型图像的开销。因此,在虚拟代理中,当客户端请求或访间对象时,才会创建实际对象。

远程代理

远程代理可表述如下:它给位于远程服务器或不同地址空间上的实际对象提供了一个本地表示。例如,你希望为应用程序建立一个监控系统,而该应用涉及多个Web服务器、数据库服务器、芹菜(cery)任务服务器、缓存服务器,等等。如果我们要监视这些服务器的CPU和磁盘利用率,就需要建立一个对象,该对象能够用于监视应用程序运行的上下文中,同时还可以执行远程命令以获取实际的参数值。在这种情况下,建立一个作为远程对象的本地表示的远程代理对象将可以帮助我们实现这个目标。

保护代理

你可以通过以下几点加深对保护代理的理解。这种代理能够控制 Realsubject的敏感对象的访问。例如,在当今分布式系统的世界中,Web应用会提供多个服务,这些服务相互协作来提供各种功能。现在,在这样的系统中,认证服务充当负责认证和授权的保护性代理服务器。在这种情况下,代理自然有助于保护网站的核心功能,防止无法识别或未授权的代理访间它们。因此,代理对象会检查调用者是否具有转发请求所需的访间权限。

智能代理

智能代理在访问对象时插入其他操作。例如,假设在系统中有一个核心组件,它将状态信息集中保存在一个地点。通常情况下,这样的组件需要被多个不同的服务调用以完成它们的任务,并且可能导致共享资源的问题。与让服务直接调用核心组件不同,智能代理是内置的,并且会在访问之前检查实际对象是否被锁定,以确保没有其他对象可以更改它。

现实世界代理模式

下面通过现实世界的付款案例来展示代理模式的现实应用场景

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from abc import ABCMeta
import abc

class You(object):
    def __init__(self):
        print("you: buy the Denim shift")
        self.debitCard = DebitCard()
        self.isPurchased = None

    def make_payment(self):
        self.isPurchased = self.debitCard.do_pay()

    def __del__(self):
        if self.isPurchased:
            print("I buy it!!!")
        else:
            print("I have no money")

class Payment(metaclass=ABCMeta):
    @abc.abstractmethod
    def do_pay(self):
        pass

class Bank(Payment):
    def __init__(self):
        self.card = None
        self.account = None

    def __getAccount(self):
        # 假设card人员是账户成员
        self.account = self.card

        return self.account

    def __hasFunds(self):
        print(f"Bank: checking if Account {self.__getAccount()} has enough funds")
        return True

    def setCard(self, card):
        self.card = card

    def do_pay(self):
        if self.__hasFunds():
            print("Bank: Paying the merchant")
            return True
        else:
            print("Bank: Sorry, not enough funds")
            return False

class DebitCard(Payment):
    def __init__(self):
        self.bank = Bank()

    def do_pay(self):
        card = input("punch in card number:\\n")
        self.bank.setCard(card)
        return self.bank.do_pay()

if __name__ == '__main__':
    you = You()
    you.make_payment()

out
you: buy the Denim shift
punch in card number:
231468498
Bank: checking if Account 231468498 has enough funds
Bank: Paying the merchant
I buy it!!!

注解:

class You:

客户端

  • 你的行为由类You(即客户端)来表示
  • 为了购买衬衫,该类提供了**make_payment()**方法
  • make_payment()方法会在内部调用代理的方法进行付款
  • 如果付款成功最后会执行del()方法

class Payment:

主题是由代理和真实主题实现的接口

  • 在本例中,主题是Payment类。它是一个抽象基类,代表一个接口
  • 付款具有一个 do_pay() 方法,该方法需要借助代理和真实主题来实现

class Bank(Payment):

真实主题

  • Bank 实际完成从你账户向商家账户划账的功能
  • Bank 提供了多个方法来处理付款。代理使用setCard()方法将借记卡详细信息发送给银行
  • __getAccount()方法是Bank的私有方法,用于获取借记卡持有人的账户详细信息。为了简单起见,我们强制使用与账号相同的借记卡号。
  • Bank还有__hasFunds()方法,它用来查看账户持有人在账户中是否有足够的资金来为衬衫付款。
  • 由Bank类(通过Payment接口)实现的do_pay()方法实际上负责根据可用资金向商家付款

class DebitCard(Payment)

代理

  • DebitCard类是此处的代理。当你想要付款时,它会调用do_pay()方法。这是因为你不想跑去银行提款,然后再跑回商家完成支付。
  • DebitCard类充当真实主题(银行)的代理

代理模式的优点

  • 代理可以通过缓存笨重的对象或频繁访问的对象来提高应用程序的性能。
  • 代理还提供对于真实主题的访问授权。因此,只有提供合适权限的情况下,这个模式才会接受委派
  • 远程代理还便于与可作网络连接和数据库连接的远程服务器进行交互,并可用于监视系统