Python7 大原则与 24 种设计模式

fansichao 2021-10-23 16:16:35
Categories: > Tags:

TODO 需要补充 行为型模式 结构型模式 小结等

七大设计原则

24 种设计模式

创建型模式基于对象的创建机制,隔离了对象的创建细节,使代码能够与要创建的对象的类型相互独立

结构型模式用于设计对象和类的结构,使它们可以相互协作以获得更大的结构

行为型模式主要关注对象的责任,用来处理对象之间的交互,以实现更大的功能

创建型模式

结构型模式

行为型模式

设计模式参考链接:

设计模式-创建型

创建型-01 工厂模式

工厂模式:主要用于抽象对象的创建过程,让用户可以指定自己想要的对象而不必关心对象的实例化过程

用 Python 实现设计模式——工厂模式

创建型-02 抽象工厂模式

抽象工厂模式:提供一个接口, 用于创建相关或依赖对象的家族, 而不需要指定具体类
用 Python 实现设计模式——工厂模式

创建型-03 生成器模式

生成器模式:使用生成器模式封装一个产品的构造过程, 并允许按步骤构造. 将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示.

Python 设计模式生成器模式,建造,者
建造者模式 —— Python 描述

创建型-04 原型模式

原型模式:支持复制类中的对象,且更新其部分属性. 用于简化外部操作,提供简单接口等等

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
import copy
from collections import OrderedDict

class Book:
def __init__(self, name, authors, price, **rest):
'''rest的例子有:出版商、长度、标签、出版日期'''
self.name = name
self.authors = authors
self.price = price
self.__dict__.update(rest)   # 添加其他额外属性

def __str__(self):
mylist = []
ordered = OrderedDict(sorted(self.__dict__.items()))
for i in ordered.keys():
mylist.append('{}: {}'.format(i, ordered[i]))
if i == 'price':
mylist.append('$')
mylist.append('\n')
return ''.join(mylist)

class Prototype:
def __init__(self):
self.objects = dict() # 初始化一个原型列表

def register(self, identifier, obj):
# 在原型列表中注册原型对象
self.objects[identifier] = obj

def unregister(self, identifier):
# 从原型列表中删除原型对象
del self.objects[identifier]

def clone(self, identifier, **attr):
# 根据 identifier 在原型列表中查找原型对象并克隆
found = self.objects.get(identifier)
if not found:
raise ValueError('Incorrect object identifier: {}'.format(identifier))
obj = copy.deepcopy(found)
obj.__dict__.update(attr)  # 用新的属性值替换原型对象中的对应属性
return obj

def main():
b1 = Book('The C Programming Language', ('Brian W. Kernighan', 'Dennis M.Ritchie'),
price=118, publisher='Prentice Hall', length=228, publication_date='1978-02-22',
tags=('C', 'programming', 'algorithms', 'data structures'))

prototype = Prototype()
cid = 'k&r-first'
prototype.register(cid, b1)
b2 = prototype.clone(cid, name='The C Programming Language(ANSI)', price=48.99, length=274, publication_date='1988-04-01', edition=2)

for i in (b1, b2):
print(i)
print("ID b1 : {} != ID b2 : {}".format(id(b1), id(b2)))

if __name__ == '__main__':
main()

浅谈 Python 设计模式 - 原型模式

创建型-05 单例模式

单例模式:一个类只能被实例化一次,实例对象在第一次实例化时就已经固定,后续的实例化用的都是第一次实例化的对象

单例模式是一个经典设计模式,简要的说,一个类只能被实例化一次,实例对象在第一次实例化时就已经固定,从第二次以后其实一直都是用的第一次实例化的对象,相当于全局。

创建单例模式的方法:

创建单例模式方法-使用模块:

Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类

1
2
3
4
5
6
7
8
9
10
# mysingleton.py
class My_Singleton(object):
def foo(self):
pass

my_singleton = My_Singleton()

# demo.py
from mysingleton import my_singleton
my_singleton.foo()

创建单例模式方法-使用__new__:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Demo:
__isinstance = False
def __new__(cls, *args, **kwargs):
if not cls.__isinstance# 如果被实例化了
cls.__isinstance = object.__new__(cls)  # 否则实例化
# 或者
# cls._instance = super().__new__(cls)
return cls.__isinstance  # 返回实例化的对象

def __init__(self, name):
print('我是 %s'%(name))

d1 = Demo('小明')
d2 = Demo('小红')
print(d1)
print(d2)

创建单例模式方法-元类 metaclass:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class SigletonMetaClass(type):
_instance = None

def __new__(cls, *args, **kwargs):
return super().__new__(cls, *args, **kwargs)  # 断点1

def __call__(self, *args, **kwargs):
if self._instance is None:
self._instance = super().__call__(*args, **kwargs)
return self._instance  # 断点2

class Singleton(metaclass=SigletonMetaClass):
def __new__(cls, *args, **kwargs):
return super().__new__(cls)  # 断点3

# 元类 metaclass 通过 __call__ 拦截

创建单例模式方法-装饰器:

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
# 函数装饰器
def SingletonDecorator(cls):
_instance = None

def get_instance(*args, **kwargs):
nonlocal _instance
if _instance is None:
_instance = cls(*args, **kwargs)
return _instance
return get_instance

@SingletonDecorator
class Singleton(object):
pass

# 示例:
a = Singleton()
b = Singleton()
# id(a) == id(b)

# 类装饰器
class SingletonDecorator(object):
_instance = None

def __init__(self, cls):
self._cls = cls

def __call__(self, *args, **kwargs):
if self._instance is None:
self._instance = self._cls(*args, **kwargs)
return self._instance

@SingletonDecorator
class Singleton(object):
pass

# 示例:
a = Singleton()
b = Singleton()
# id(a) == id(b)

创建单例模式方法-静态方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Singleton(object):
_instance = None

@staticmethod
def get_instance():
cls = __class__

if cls._instance is None:
cls._instance = super(cls, cls).__new__(cls)
return cls._instance

# 示例:
a = Singleton.get_instance()
b = Singleton.get_instance()
# id(a) == id(b)

创建单例模式方法-类方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Singleton(object):
_instance = None

@classmethod
def get_instance(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance

# 示例:
a = Singleton.get_instance()
b = Singleton.get_instance()
# id(a) == id(b)

创建单例模式方法-名称覆盖:

用实例名覆盖类名后,执行 Singleton() 就是在调用 call() 函数,总是返回自身。

1
2
3
4
5
6
7
8
9
10
class Singleton(object):
def __call__(self):
return self

Singleton = Singleton()

# 示例:
a = Singleton()
b = Singleton()
# id(a) == id(b)

创建单例模式方法-属性共享:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Singleton(object):
_state = {}

def __new__(cls, *args, **kwargs):
obj = super().__new__(cls)
obj.__dict__ = cls._state
return obj

def __init__(self, name):
self.name = name

# 示例:
a = Singleton()
b = Singleton()
# id(a) != id(b)

实例对象的私有属性存放在 dict 中。因此,将所有对象指向同一个属性 Singleton._state,即便它们的 id 值 不同,由于共享属性仍实现了单例效果。

TODO 复杂情况下的单例模式

多线程下的单例模式应用:

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
def singleton(cls):
cls.__new_original__ = cls.__new__

@functools.wraps(cls.__new__)
def singleton_new(cls, *args, **kwargs):
it = cls.__dict__.get('__it__')
if it is not None:
return it

cls.__it__ = it = cls.__new_original__(cls, *args, **kwargs)
it.__init_original__(*args, **kwargs)
return it

cls.__new__ = singleton_new
cls.__init_original__ = cls.__init__
cls.__init__ = object.__init__
return cls

@singleton
class Foo(object):
def __new__(cls, *args, **kwargs):
cls.x = 10
return object.__new__(cls)

def __init__(self, x, y):
assert self.x == 10
self.x = x
self.y = y

上述代码中定义了 singleton 类装饰器,装饰器在预编译时就会执行,利用这个特性,singleton 类装饰器中替换了类原本的newinit方法,使用 singleton_new 方法进行类的实例化,在 singleton_new 方法中,先判断类的属性中是否存在it属性,以此来判断是否要创建新的实例,如果要创建,则调用类原本的new方法完成实例化并调用原本的init方法将参数传递给当前类,从而完成单例模式的目的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 加上线程锁
def singleton(cls):
cls.__new_original__ = cls.__new__
@functools.wraps(cls.__new__)
def singleton_new(cls, *args, **kwargs):
# 同步锁
with threading.Lock():
it = cls.__dict__.get('__it__')
if it is not None:
return it

cls.__it__ = it = cls.__new_original__(cls, *args, **kwargs)
it.__init_original__(*args, **kwargs)
return it

cls.__new__ = singleton_new
cls.__init_original__ = cls.__init__
cls.__init__ = object.__init__
return cls

参考链接:

创建型-06 多例模式

多例模式:多例模式允许存在有限个实例(多例模式又分为有上限模式和无上限模式,无上限模式和直接 new 一个对象差不多,此处不做讨论)

单例模式仅创建一个对象。多例模式可以创建 有限个对象

详情请参考 单例模式

设计模式-结构型

结构型-01 适配器模式

适配器可以理解为万能接口,各种类可以通过这个接口然后被调用,达到万能转换的效果。

他的实现是以我们定义的适配器函数来分类,将各种类的不同方法注册到对应的分类函数中,调用的时候只需要使用分类名,这样就达到了适配所有类不同方法的效果.

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
class A:
def a(self):
print("我是A类的a方法")

class B:
def b(self):
print("我是B类的b方法")

class C:
def c(self):
print("我是C类的c方法")

class Adapter(object):
""" 适配器

objects = []
AA = A()
objects.append(Adapter(AA, dict(test=AA.a)))
for obj in objects:
obj.test()

核心思想 创建一个适配器类,通过__dict__将需要转化的类的方法注册到适配器,
复写__getattr__使其在适配器函数查无方法的时候,执行getattr魔法方法

"""
def __init__(self, instance, method):
self.instance = instance
self.__dict__.update(method)

def __getattr__(self, attr):
return getattr(self.instance, attr)


def test():
objects = []
AA = A()
objects.append(Adapter(AA, dict(test=AA.a)))
BB = B()
objects.append(Adapter(BB, dict(test=BB.b)))
CC = C()
objects.append(Adapter(CC, dict(test=CC.c)))
for obj in objects:
print('>>> 11')
print(dir(obj))
obj.test()

test()

结构型-02 桥接模式

桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。

参考链接:

结构型-03 组合模式

参考链接:

结构型-04 装饰者模式

TODO 装饰器的缺点

装饰者模式:使用装饰器来动态的添加功能。例如日志记录、权限认证等等

当装饰器已经作用于某函数,而你想撤销它,那么可以访问 wrapped 属性来访问原始函数。 不建议使用,多装饰器时,不可控。

参考链接:

结构型-05 外观模式

外观模式(Facade Pattern):外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

1
2
3
4
5
6
# 简单的样例
def run_all():
run_a()
run_b()
run_c()
# 定义一个统一的外观 run_all 便于统一调用

参考链接:

结构型-06 亨元模式

亨元模式:用于解决资源和性能压力时会使用到的设计模式,它的核心思想是通过引入数据共享来提升性能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from enum import Enum

TreeType = Enum('TreeType','apple_tree cherry_tree peach_tree')

class Tree:
pool = dict()

def __new__(cls, tree_type, *args,**kwargs):
obj = cls.pool.get(tree_type,None)
if not obj:
obj = super().__new__(cls,*args, **kwargs)
cls.pool[tree_type] = obj
obj.tree_type = tree_type
return obj

def __init(self,size ):
self.size = size

def render(self,age,x,y):
print('render a tree of type {} and age {} at ({},{})'.format(self.tree_type,age,x,y))

该示例中,在new方法中实现类不可变数据的共享。在init方法中实现了可变数据的独立,即不共享。

参考链接:

结构型-07 代理模式

为其他对象提供一种代理以控制对这个对象的访问.通俗的来讲代理模式就是我们生活中常见的中介

参考链接:

设计模式-行为型

行为型-01 责任链模式

责任链模式(Chain of responsibility pattern): 通过责任链模式, 你可以为某个请求创建一个对象链. 每个对象依序检查此请求并对其进行处理或者将它传给链中的下一个对象.

参考链接:

行为型-02 命令模式

命令模式(Command pattern): 将”请求”封闭成对象, 以便使用不同的请求,队列或者日志来参数化其他对象. 命令模式也支持可撤销的操作.

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
# -*- coding: utf8 -*-
from abc import ABCMeta,abstractmethod

# 声明基类
class Command():
def __init__(self,recv):
self.recv = recv

def execute(self):
pass


# 接收对象和执行操作绑定
class ConcreteCommand(Command):
def __init__(self,recv):
self.recv = recv

def execute(self):
self.recv.action()


# 接收对象
class Receiver:
def action(self):
print ("Receiver Action")


# 执行请求
class Invoker:
def command(self, cmd):
self.cmd = cmd

def execute(self):
self.cmd.execute()


if __name__ == "__main__":
recv = Receiver()
cmd = ConcreteCommand(recv)
invoker = Invoker()
# 核心: 命令的生成 & 命令的执行
invoker.command(cmd)
invoker.execute()

参考链接

行为型-03 解释器模式

解释器模式(Interpreter pattern): 使用解释器模式为语言创建解释器.

行为型-04 迭代器模式

迭代器模式(iterator pattern): 提供一种方法顺序访问一个聚合对象中的各个元素, 而又不暴露其内部的表示.

行为型-05 中介者模式

中介者模式(Mediator pattern) : 使用中介者模式来集中相关对象之间复杂的沟通和控制方式.

行为型-06 备忘录模式

备忘录模式(Memento pattern): 当你需要让对象返回之前的状态时(例如, 你的用户请求”撤销”), 你使用备忘录模式。

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态

行为型-07 观察者模式

观察者模式(observer pattern): 在对象之间定义一对多的依赖, 这样一来, 当一个对象改变状态, 依赖它的对象都会收到通知, 并自动更新.

python 设计模式之观察者模式

行为型-08 状态模式

状态模式(State Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类.

应用场景:当控制一个对象的状态转换的条件表达式过于复杂时,把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化

行为型-09 策略模式

策略模式(strategy pattern): 定义了算法族, 分别封闭起来, 让它们之间可以互相替换, 此模式让算法的变化独立于使用算法的客户.

策略模式

行为型-10 模板方法模式

模板方法模式(Template pattern): 在一个方法中定义一个算法的骨架, 而将一些步骤延迟到子类中. 模板方法使得子类可以在不改变算法结构的情况下, 重新定义算法中的某些步骤.

Python 设计模式模板方法

行为型-11 访问者模式

访问者模式(visitor pattern): 当你想要为一个对象的组合增加新的能力, 且封装并不重要时, 就使用访问者模式.

Python 访问者模式

小结

例子

参考资料