预备知识

@abstractmethod:抽象方法,含abstractmethod方法的类不能实例化,继承了含abstractmethod方法的子类必须复写所有abstractmethod装饰的方法,未被装饰的可以不重写

@ property:方法伪装属性,方法返回值及属性值,被装饰方法不能有参数,必须实例化后调用,类不能调用

@ classmethod:类方法,可以通过实例对象和类对象调用,被该函数修饰的方法第一个参数代表类本身常用cls,被修饰函数内可调用类属性,不能调用实例属性

@staticmethod:静态方法,可以通过实例对象和类对象调用,被装饰函数可无参数,被装饰函数内部通过类名.属性引用类属性或类方法,不能引用实例属性

创建型模式

创建型模式的工作原理是基于对象的创建机制的。由于这些模式隔离了对象的创建细节。所以使得代码能够与要创建的对象的类型互相独立。

  • 它们的运行机制基于对象的创建方式
  • 它们将对象创建的细节隔离开来
  • 代码与所创建的对象的类型无关

单例模式

单例模式提供了这样一种机制,即确保类有且只有一个特定类型的对象,并提供全局访问点

UML图

img

代码实现

 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
In [1]: class Singleton(object):
            """ 单例模式 """
   ...:     def __new__(cls):
   ...:         if not hasattr(cls, "instance"):
   ...:             cls.instance = super(Singleton, cls).__new__(cls)
   ...:         return cls.instance
   ...:

In [2]: s = Singleton()

In [3]: s
Out[3]: <__main__.Singleton at 0x7fc32793ed90>

In [4]: s2 = Singleton()

In [5]: s2
Out[5]: <__main__.Singleton at 0x7fc32793ed90>
In [21]: class Singletons(object):
            """ 懒汉式加载 """
    ...:     __instance = None
    ...:     def __init__(self):
    ...:         if not Singletons.__instance:
    ...:             print("__init__ method called..")
    ...:         else:
    ...:             print("Instance alreadly created:",self.getInstance())
    ...:     @classmethod
    ...:     def getInstance(cls):
    ...:         if not cls.__instance:
    ...:             cls.__instance = Singletons()
    ...:         return cls.__instance
    ...:

In [22]: a = Singletons()
__init__ method called..

In [23]: a1 = Singletons()
__init__ method called..

In [24]: a2 = Singletons()
__init__ method called..

In [25]: a.getInstance()
__init__ method called..
Out[25]: <__main__.Singletons at 0x7fc327b020d0>

In [26]: a
Out[26]: <__main__.Singletons at 0x7fc327e48ca0>

In [27]: a1
Out[27]: <__main__.Singletons at 0x7fc32763a250>
In [1]: class MyMetaClass(type):
				""" 元类实现单例模式 """
   ...:     _instances = {}
   ...:     def __call__(cls,*args,**kwargs):
   ...:         print("**** Here`s my MetaClass ****")
   ...:         if cls not in cls._instances:
   ...:             cls._instances[cls] = super(MyMetaClass,cls).__call__(*args,**kwargs)
   ...:         return cls._instances[cls]

In [2]: class test(metaclass=MyMetaClass):
   ...:     pass
   ...:

In [3]: a = test()
**** Here`s my MetaClass ****

In [4]: a2 = test()
**** Here`s my MetaClass ****

In [5]: id(a)
Out[5]: 139837183079520

In [6]: id(a2)
Out[6]: 139837183079520

虽然单例模式在许多情况下效果很好,但是由于单例模式具有全局访问权限,可能会存在一些问题

  • 全局变量可能在某处已经被更改,但是开发人员仍然认为它们没有发生变化,而改变量还在应用程序的其他位置被使用
  • 可能会对同一个对象创建多个应用(此单例类被多次实例化,实际只实例化一次就可以)
  • 所有依赖于全局变量的类都会由于一个类的改变而紧密耦合为全局数据,从而可能在无意中影响另一个类

工厂模式

工厂可以帮助开发人员创建不同类型的对象,而不是直接将对象实例化

优点如下:

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

简单工厂模式

UML图

image-20210216171700815

代码实现
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import adc
from abc import ABCMeta
In [10]: class Animal(metaclass=ABCMeta):
    ...:     @abc.abstractmethod
						# 抽象方法,子类必须实现(重写)此方法,不然子类实例化的时候会报错
    ...:     def do_say(self):
    ...:         pass

In [13]: class Cat(Animal):
    ...:     def do_say():
    ...:         print("喵喵喵")
    ...:

In [14]: class ForrestFactory(object):
    ...:     def make_sound(self,object_type):
    ...:         return eval(object_type)().do_say()
    ...:

工厂方法模式

  • 我们定义一个接口来创建对象,但是工厂本身并不负责创建对象,而是将这一人物交由子类来完成,即子类决定了要实例化那些类
  • Factory方法的创建是通过集成而不是通过实例化来完成的
  • 工厂方法使设计更加具有可定制性。它可以返回相同的实例或子类,而不是某种类型的对象
UML图

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/860f9022-e7dd-47de-84ec-3026f3377222/Untitled.png

代码示例
 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
from abc import ABCMeta
import abc

class Section(metaclass=ABCMeta):
    @abc.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()

    @abc.abstractmethod
    def createProfile(self):
        pass

    def getSection(self):
        return self.sections

    def addSection(self, section):
        self.sections.append(section)

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

class FaceBook(Profile):
    def createProfile(self):
        self.addSection(PersonalSection)
        self.addSection(AlbumSection)

if __name__ == '__main__':
    profie_type = input("Which Profile you choice ?")
    profie = eval(profie_type.lower().capitalize())()
    print("Create Profile", type(profie).__name__)
    print("Profile has Sections", profie.getSection())

out
Which Profile you choice ?Create Profile Linkedin
Profile has Sections [<class '__main__.PersonalSection'>, <class '__main__.PatentSection'>, <class '__main__.PublicationSection'>]
工厂方法的优点
  • 具有更大的灵活性,使代码更加通用,因为它不仅仅是单独的实例化某个类。这样实现哪些类取决于接口(Product),而不是 ConcreteProduct类
  • 它们之间是松耦合的,因为创建对象的代码与使用它的代码是分开的。客户端完全不需要关心要传递哪些参数以及需要实例化哪些类。由于添加新类更加容易,所以降低了维护成本。

抽象工厂模式

抽象工厂模式的主要目的是提供一个接口来创建一系列相关对象,而无需指定具体类

UML图

image-20210216171806106

代码实现
 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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import abc
from abc import ABCMeta

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

    @abc.abstractmethod
    def createNonVegPizza(self):
        pass

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

class NonVegPizza(metaclass=ABCMeta):
    @abc.abstractmethod
    def server(self, VegPizza):
        pass

class DeluxVeggiePizza(VegPizza):
    def prepare(self):
        print(f"perpare {type(self).__name__}")

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

class MexicanVegPizza(VegPizza):
    def prepare(self):
        print(f"perpare {type(self).__name__}")

class HamPizza(NonVegPizza):
    def server(self, VegPizza):
        print(f"{type(self).__name__} is served with Chicken on {type(VegPizza).__name__}")

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 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.server(self.VegPizza)

if __name__ == '__main__':
    pizza = PizzaStore()
    pizza.makePizzas()

out
perpare DeluxVeggiePizza
ChickenPizza is served with Chicken on DeluxVeggiePizza
perpare MexicanVegPizza
HamPizza is served with Chicken on MexicanVegPizza