python设计模式(二)

工厂模式:建立创建对象的工厂

“工厂”表示一个负责创建其他类型对象的类。作为一个工厂的类有一个对象以及与它关联的多个方法。客户端使用某些参数调用此方法,之后工厂会据此创建所需类型的对象,然后将他们返回给客户端。

优点:

  • 松耦合性,对象的创建可以独立于类的实现
  • 客户端无需了解创建对象的类,但是照样可以使用它来创建对象,它只需要知道传递的接口、方法和参数,就能够创建所需类型的对象,简化了客户端的实现
  • 可以轻松地在工厂中添加其他类来创建其他类型的对象,而这无需更改客户端代码,最简单的情况下,客户端只需要传递另一个参数就可以了。
  • 工厂还可以重用现有对象。但是如果客户端直接创建对象的话,总是创建一个新的对象。

3种变体:

  • 简单工厂模式:允许接口创建对象,但不会暴露对象的创建逻辑
  • 工厂方法模式:允许接口创建对象,但使用哪个类来创建对象,则是交由子类决定的。
  • 抽象工厂模式:能够创建一系列相关的对象而无需指定/公开其具体类的接口。该模式能够提供其他工厂的对象,在其内部创建其他对象。

简单工厂模式

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
from abc import ABCMeta, abstractmethod

class Animal(metaclass=ABCMeta):
@abstractmethod
def do_say(self):
pass

class Dog(Animal):
def do_say(self):
print("Bhow Bhow")

class Cat(Animal):
def do_say(self):
print("Meow Meow")

## forest factory defined
class ForestFactory(object):
def make_sound(self, object_type):
return eval(object_type)().do_say()

## client code
if __name__ == '__main__':
ff = ForestFactory()
animal = input("Which animal should make_sound Dog or Cat?")
ff.make_sound(animal)

可以看到eval的妙用。以及简单工厂的妙用

工厂方式模式

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
from abc import ABCMeta, abstractmethod

class Section(metaclass=ABCMeta):
@abstractmethod
def describe(self):
pass

class PersonalSection(Section):
def describe(self):
print("Personal Section")

class AlbumSection(Section):
def describe(self):
print("Album Section")

class PatentSection(Section):
def describe(self):
print("Patent Section")

class PublicationSection(Section):
def describe(self):
print("Publication Section")

class Profile(metaclass=ABCMeta):
def __init__(self):
self.sections = []
self.createProfile()
@abstractmethod
def createProfile(self):
pass
def getSections(self):
return self.sections
def addSections(self, section):
self.sections.append(section)

class Linkedin(Profile):
def createProfile(self):
self.addSections(PersonalSection)
self.addSections(PatentSection)
self.addSections(PublicationSection)

class Facebook(Profile):
def createProfile(self):
self.addSections(PersonalSection)
self.addSections(AlbumSection)

if __name__ == '__main__':
profile_type = input("Which Profile you'd like to create?[Linkedin or Facebook]")
profile = eval(profile_type)()
print("Create Profile..", type(profile).__name__)
print("Profile has sections -- ", profile.getSections())

工厂方式的优点:

  • 它具有更大的灵活性,使得代码更加通用,因为它不是单纯的实例化某个类。实现哪些类取决于接口。
  • 松耦合的,创建对象的代码和使用它的代码是分开的,客户端完全不需要关心传递哪些参数以及需要实例化哪些类,降低维护成本。

抽象工厂

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
from abc import ABCMeta, abstractmethod

class PizzaFactory(metaclass=ABCMeta):
@abstractmethod
def createVegPizza(self):
pass

@abstractmethod
def createNonVegPizza(self):
pass

class IndianPizzaFactory(PizzaFactory):

def createVegPizza(self):
return DeluxVeggiePizza()

def createNonVegPizza(self):
return ChickenPizza()

class USPizzaFactory(PizzaFactory):
def createVegPizza(self):
return MexicanVegPizza()

def createNonVegPizza(self):
return HamPizza()

class VegPizza(metaclass=ABCMeta):
@abstractmethod
def prepare(self):
pass

class NonVegPizza(metaclass=ABCMeta):
@abstractmethod
def serve(self, VegPizza):
pass

class DeluxVeggiePizza(VegPizza):
def prepare(self):
print("Prepare ", type(self).__name__)

class ChickenPizza(NonVegPizza):
def serve(self, VegPizza):
print(type(self).__name__, " is served with Chicken on ", type(VegPizza).__name__)

class MexicanVegPizza(VegPizza):
def prepare(self):
print("Prepare ", type(self).__name__)

class HamPizza(NonVegPizza):
def serve(self, VegPizza):
print(type(self).__name__, " is served withe Ham on ", type(VegPizza).__name__)

class PizzaStore:
def __init__(self):
pass
def makePizzas(self):
for factory in [IndianPizzaFactory(), USPizzaFactory()]:
self.factory = factory
self.NonVegPizza = self.factory.createNonVegPizza()
self.VegPizza = self.factory.createVegPizza()
self.VegPizza.prepare()
self.NonVegPizza.serve(self.VegPizza)

pizza = PizzaStore()
pizza.makePizzas()
工厂方法抽象工厂方法
它向客户端开放了一个创建对象的方法抽象工厂方法包含一个或多个工厂方法来创建一个系列的相关对象
它使用继承和子类来决定要创建哪个对象它使用组合将创建对象的任务委托给其他类
工厂方法用于创建一个产品抽象工厂方法用于创建相关产品的系列

门面模式——与门相适应

结构型设计模式

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

例子:

  • 适配器模式:将一个接口转换成客户希望的另一个接口,它试图根据客户端的需求来匹配不同类的接口。
  • 桥接模式:该模式将对象的接口与其实现进行解耦,使得两者可以独立工作。
  • 装饰器模式:该模式允许在运行时动态的为对象填加职责,通过接口给对象添加某些属性。

门面设计模式实际上完成的事项:

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

这个模式一共有3个参与者

  • 门面:门面的主要责任是:将一组复杂导致系统封装起来,从而为外部世界提供一个舒适的外观。
  • 系统:这代表一组不同的子系统,使整个系统混合在一起,难以观察或使用
  • 客户端:客户端与门面进行交互,这样就可以轻松地与子系统进行通信并完成工作。

    门面

  • 它是一个接口,知道某个请求可以交由那个子系统进行处理

  • 它使用组合将客户端的请求委派给相应的子系统对象。

系统

  • 它实现子系统的功能,同时,系统由一个类表示。理想情况下,系统应该由一组负责不同人物的类来表示。
  • 处理门面对象分配的任务,不引用门面。

客户端

  • 实例化门面的类
  • 让子系统完成相应的工作,客户端要向门面提出请求

实现

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
class EventManager(object):

def __init__(self):
print("EventManager :: Let me talk to the folks")

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

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

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

self.musician = Musician()
self.musician.setMusicType()

class Hotelier(object):
def __init__(self):
print("Arranging thr 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("Registered the Booking\n")


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

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

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

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

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

def setMusicType(self):
print("Jazz and Classical will be played\n")


class You(object):
def __init__(self):
print("You:: Whoa! Marriage Arrangements??!!")

def askEventManager(self):
print("You:: Let's Contact the Event Manager\n")
em = EventManager()
em.arrange()
def __del__(self):
print("You:: Thanks to Event manager, all preparations done!")

you = You()
you.askEventManager()

显而易见EventManager就是一个简化接口的门面

最少知识原则

  • 设计系统时,对于创建的每一个对象都应该考察与之交互的类的数量以及交互的方式
  • 避免创建许多彼此紧密耦合的类的情况
  • 如果类之间存在大量依赖关系,那么系统就会变得难以维护。是应该坚决避免的

这与迪米特法则是一致的,都指向松耦合理论。

子系统可以拥有多个门面,客户端也可以直接访问子系统

缺点:可能会建立多个不必要的接口,增加了系统的复杂性降低了运行时的性能。

代理模式

代理:一个介于寻求方和提供方之间的中介系统。

寻求方:请求的一方,提供方:根据请求提供资源的一方。

代理模式的主要目的就是为其他对象提供一个代理者或占位符,从而控制对实际对象的访问。

常用场景:

  • 以简单方式表示一个复杂的系统。例如,涉及多个复杂计算或过程的系统应该提供一个更简单的接口,充当客户端的代理
  • 提高现有实际对象的安全性。
  • 为不同服务器上的远程对象提供本地接口。
  • 为消耗大量内存的对象提供了一个轻量级的句柄
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
class Actor(object):
def __init__(self):
self.isBusy = False

def occupied(self):
self.isBusy = True
print(type(self).__name__, "is occupied withe current movie")

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

def getStatus(self):
return self.isBusy

def change(self):
self.isBusy = ~self.isBusy

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

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

def change(self):
self.actor.change()

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

不同类型的代理

  • 虚拟代理:如果一个对象实例化会占用大量内存,可以利用占位符表示,即虚拟代理。只有在用户请求或访问时才会创建实际对象
  • 远程代理:给位于远程服务器或不同地址空间上的实际对象提供一个本地表示
  • 保护代理:控制对实际对象中的敏感对象的访问。
  • 智能代理:在访问对象时插入其他操作。
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
from abc import ABCMeta, abstractmethod

class Payment(metaclass=ABCMeta):

@abstractmethod
def doPay(self):
pass

class Bank(Payment):

def __init__(self):
self.card = None
self.account = None

def __getAccount(self):
self.account = self.card
return self.account

def __hasFunds(self):
print("Bank:: Checking if Account", self.__getAccount(),"has enough funds")
return True

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

def doPay(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 doPay(self):
card = input("Proxy:: Punch in Card Number: ")
self.bank.setCard(card)
return self.bank.doPay()

class You:
def __init__(self):
print("You:: lets buy the Denim shirt")
self.debitCard = DebitCard()
self.isPurchased = None

def makePayment(self):
self.isPurchased = self.debitCard.doPay()

def __del__(self):
if self.isPurchased:
print("You:: Wow! Denim shirt is Mine :-)")
else:
print("You:: I should earn more")

you = You()
you.makePayment()

优点

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

与门面模式的比较:

代理模式门面模式
为其他对象提供了代理或占位符,控制对原始对象的访问为类的大型子系统提供了接口
具有与其目标对象相同的接口,并保存有目标对象的引用实现子系统间通信与依赖性的最小化
充当客户端与被封装的对象之间的中介提供单一简单的接口

FAQ:

Q1: 装饰器模式与代理模式之间的区别:

装饰器向在运行时装饰对象添加行为,而代理则是控制对对象的访问。代理和真实主题之间的关联是在编译时完成的,不是动态的。

Q2:代理模式的缺点:

代理模式会增加响应时间。

客户端可以独立访问真实主题,代理也可以自己添加功能。

文章目录
  1. 1. 工厂模式:建立创建对象的工厂
    1. 1.1. 简单工厂模式
    2. 1.2. 工厂方式模式
    3. 1.3. 抽象工厂
  2. 2. 门面模式——与门相适应
    1. 2.1. 结构型设计模式
      1. 2.1.1. 门面
      2. 2.1.2. 系统
      3. 2.1.3. 客户端
    2. 2.2. 实现
    3. 2.3. 最少知识原则
  3. 3. 代理模式
    1. 3.1. 不同类型的代理
    2. 3.2. 优点
    3. 3.3. 与门面模式的比较:
    4. 3.4. FAQ:
|