设计模式

三种最基本的设计模式:

  1. 创建模式,提供实例化的方法,为适合的状况提供相应的对象创建方法。
  2. 结构化模式,通常用来处理实体之间的关系,使得这些实体能够更好地协同工作。
  3. 行为模式,用于在不同的实体建进行通信,为实体之间的通信提供更容易,更灵活的通信方法。

设计模式的六大原则

  1. 开闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
  2. 里氏(Liskov)替换原则:所有引用基类(父类)的地方必须能透明地使用其子类的对象。
  3. 依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程。
  4. 接口隔离原则:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
  5. 迪米特法则:一个软件实体应当尽可能少地与其他实体发生相互作用。
  6. 单一职责原则:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。

创建型模式

  1. 单例模式
    单例模式(Singleton Pattern)目的是确保某一个类只有一个实例存在。
    实现单例有多种方法:装饰器,new, metaClass, import
    每一个 python 模块都是天生的单例模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
### 单例模式
class Singleton(object):
def __init__(self):
pass

def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = object.__new__(cls)
return cls._instance


ob_1 = Singleton()
ob_2 = Singleton()
print(id(ob_1), id(ob_2))
  1. 工厂模式
    当以下情形可以使用工厂模式:
    \1. 不知道用户想要创建什么样的对象
    \2. 当你想要创建一个可扩展的关联在创建类与支持创建对象的类之间。
    工厂模式有很多种实现类型,下面只介绍一种工厂方法模式
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
### 工厂模式
class Person:
def __init__(self):
self.name = None
self.gender = None

def getName(self):
return self.name

def getGender(self):
return self.gender


class Male(Person):
def __init__(self, name):
super().__init__()
print(f'Mr.{name}')


class Female(Person):
def __init__(self, name):
super().__init__()
print(f"Miss.{name}")


class PersonFactory:
@staticmethod
def getPerson(name, gender):
if gender == "M":
return Male(name)
if gender == "F":
return Female(name)


ob_1 = PersonFactory.getPerson("big", "M")
ob_2 = PersonFactory.getPerson("bigTwo", "F")
  1. 原型模式
    用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
    浅拷贝(Shallow Copy): 指对象的字段被拷贝,而字段引用的对象不会被拷贝,拷贝的对象和源对象只是名称相同,但是他们共用一个实体。
    深拷贝(deep copy): 对对象实例中字段引用的对象也进行拷贝。
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
### 原型模式
import copy


class Book:
def __init__(self, *args, **kwargs):
self.__dict__.update(kwargs)

def __str__(self):
return str(sorted(self.__dict__.items()))


class ProtoType:
def __init__(self):
self.objects = dict()

def register(self, nid, obj):
self.objects[nid] = obj

def unregister(self, nid):
del self.objects[nid]

def clone(self, nid, **attr):
found = self.objects.get(nid)
if not found:
raise ValueError(f"{nid} No exist")
obj = copy.deepcopy(found)
obj.__dict__.update(attr)
return obj


b_1 = Book("aaa", k="kkk", b="bbb")
prototype = ProtoType()
prototype.register("b_1", b_1)
b_2 = prototype.clone("b_1", e="eee", d="ddd")
print(b_1)
print(b_2)
print(id(b_1))
print(id(b_2))
  1. 建造者模式
    包括一个限定方法抽象类,多个实际建造者类,一个指挥者类
    以下情况适用:
    \1. 当创建复杂对象的算法(Director)应该独立于该对象的组成部分以及它们的装配方式(Builder)时
    \2. 当构造过程允许被构造的对象有不同的表示时(不同 Builder)。
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
### 建造者模式
from abc import ABCMeta, abstractmethod

class Builder:
_metaClass_ = ABCMeta

@abstractmethod
def draw_body(self):
pass


class FatCreator(Builder):
def __init__(self):
...

def draw_body(self):
print(f'画胖子')


class ThinCreator(Builder):
def __init__(self):
pass

def draw_body(self):
print(f'画瘦子')


class Director:
def __init__(self, obj):
self.obj = obj

def draw(self):
self.obj.draw_body()


fat = FatCreator()
Director(fat).draw()

结构型模式

  1. 适配器模式
    所谓适配器模式是指是一种接口适配技术,它可通过某个类来使用另一个接口与之不兼容的类,运用此模式,两个类的接口都无需改动。

适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况,比如在需要对早期代码复用一些功能等应用上很有实际价值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
### 适配器模式
class Target:
def request(self):
print("普通请求")


class Adaptee:
def special_request(self):
print("特殊请求")


class Adapter(Target):
def __init__(self):
self.adaptee = Adaptee()

def request(self):
self.adaptee.special_request()

target= Adapter()
target.request()
  1. 修饰器模式
    Python 种经典的模式,用来拓展类的功能
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
### 装饰器模式
import functools


def memoize(fn):
know = dict()
@functools.wraps(fn)
def memoizer(*args):
if args not in know:
know[args] = fn(*args)
return know[args]
return memoizer

@memoize
def nsum(n):
"""
返回前那个数的和
:param n:
:return:
"""
assert (n >= 0), 'n must be >= 0'
return 0 if n == 0 else n + nsum(n-1)

@memoize
def fibonacci(n):
"""
返回斐波那契数列的第n个数
:param n:
:return:
"""
assert n >= 0 and isinstance(n, int), 'n must be int and >= 0'
return n if n in (0, 1) else fibonacci(n-1) + fibonacci(n-2)


from timeit import Timer
measure = [{'exec': 'fibonacci(100)', 'import': 'fibonacci', 'func': fibonacci},
{'exec': 'nsum(10)', 'import': 'nsum', 'func': nsum}]
for m in measure:
t = Timer(f'{m["exec"]}', f'from __main__ import {m["import"]}')
print('name: {} \ndoc: {} \nexecuting: {} \n time:{}'.format(m['func'].__name__, m['func'].__doc__, m['exec'], t.timeit()))
  1. 享元模式
    运用共享技术有效地支持大量细粒度的对象。
    内部状态:享元对象中不会随环境改变而改变的共享部分。比如围棋棋子的颜色。
    外部状态:随环境改变而改变、不可以共享的状态就是外部状态。比如围棋棋子的位置。

应用场景:程序中使用了大量的对象,如果删除对象的外部状态,可以用相对较少的共享对象取代很多组对象,就可以考虑使用享元模式。

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
### 享元模式
class Tree(object):
obj_pool = {}

def __new__(cls, tree_type):
if tree_type not in cls.obj_pool:
obj = object.__new__(cls)
cls.obj_pool[tree_type] = obj
obj.tree_type = tree_type
return cls.obj_pool[tree_type]

def render(self, age):
print(f'{self.tree_type}: age: {age}')

# obj_list = []

# def __init__(self, tree_type):
# self.tree_type = tree_type
# self.get_obj()

# @classmethod
# def get_obj(cls):
# cls.obj_list.append(cls.__new__(cls))

from random import randint
for _ in range(10):
a = "apple"
t1 = Tree(a)
t1.render(randint(10, 50))
for _ in range(5):
t2 = Tree("cherry")
t2.render(randint(10, 50))

for _ in range(3):
t3 = Tree("peach")
t3.render(randint(10, 50))

print(len(Tree.obj_pool))
  1. 外观模式
    外观模式又叫做门面模式。在面向对象程序设计中,解耦是一种推崇的理念。但事实上由于某些系统中过于复杂,从而增加了客户端与子系统之间的耦合度。例如:在家观看多媒体影院时,更希望按下一个按钮就能实现影碟机,电视,音响的协同工作,而不是说每个机器都要操作一遍。这种情况下可以采用外观模式,即引入一个类对子系统进行包装,让客户端与其进行交互。

外观模式 (Facade 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
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
from enum import Enum
from abc import ABCMeta, abstractmethod

State = Enum('State', 'new running sleeping restart zombie')


class User:
pass


class Process:
pass


class File:
pass


class Server(metaclass=ABCMeta):
@abstractmethod
def __init__(self):
pass

def __str__(self):
return self.name

@abstractmethod
def boot(self):
pass

@abstractmethod
def kill(self, restart=True):
pass


class FileServer(Server):
def __init__(self):
'''初始化文件服务进程要求的操作'''
self.name = 'FileServer'
self.state = State.new

def boot(self):
print('booting the {}'.format(self))
'''启动文件服务进程要求的操作'''
self.state = State.running

def kill(self, restart=True):
print('Killing {}'.format(self))
'''终止文件服务进程要求的操作'''
self.state = State.restart if restart else State.zombie

def create_file(self, user, name, permissions):
'''检查访问权限的有效性、用户权限等'''
print("trying to create the file '{}' for user '{}' with permissions{}".format(name, user, permissions))


class ProcessServer(Server):
def __init__(self):
'''初始化进程服务进程要求的操作'''
self.name = 'ProcessServer'
self.state = State.new

def boot(self):
print('booting the {}'.format(self))
'''启动进程服务进程要求的操作'''
self.state = State.running

def kill(self, restart=True):
print('Killing {}'.format(self))
'''终止进程服务进程要求的操作'''
self.state = State.restart if restart else State.zombie

def create_process(self, user, name):
'''检查用户权限和生成PID等'''
print("trying to create the process '{}' for user '{}'".format(name, user))


class WindowServer:
pass


class NetworkServer:
pass


class OperatingSystem:
'''外观'''

def __init__(self):
self.fs = FileServer()
self.ps = ProcessServer()

def start(self):
[i.boot() for i in (self.fs, self.ps)]

def create_file(self, user, name, permissions):
return self.fs.create_file(user, name, permissions)

def create_process(self, user, name):
return self.ps.create_process(user, name)


def main():
os = OperatingSystem()
os.start()
os.create_file('foo', 'hello', '-rw-r-r')
os.create_process('bar', 'ls /tmp')

全文完

本文由 简悦 SimpRead 优化,用以提升阅读体验

使用了 全新的简悦词法分析引擎 beta,点击查看详细说明

创建型模式结构型模式

如果文章有帮到您,很开心得到您的支持!