python设计模式

为什么要有设计模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class DatabaseConnection:
def __init__(self, host, port, username, password):
self.host = host
self.port = port
self.username = username
self.password = password

def connect(self):
return f"Connecting to database at {self.host}:{self.port} with username '{self.username}'"


def client():
main_db = DatabaseConnection('localhost', 3306, 'root', 'password123')
analytics_db = DatabaseConnection('192.168.1.1', 5432, 'admin', 'securepass')
cache_db = DatabaseConnection('10.0.0.1', 27017, 'cacheuser', 'cachepass')

print(main_db.connect())
print(analytics_db.connect())
print(cache_db.connect())


client()

这是数据库连接类的范例,其存在以下问题

  1. 数据库连接信息(主机、端口、用户名、密码)直接写在代码中,缺乏配置管理,难以在不同环境间切换,如果要更改数据库的信息,就要更改项目中每一处的连接数据库的参数,难以维护
  2. 每次都需要手动传入相同类型的参数,增加出错的风险

工厂模式(Factory 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
def connection_factory(db_type):
db_configs = {
'main': {
'host': 'localhost',
'port': 3306,
'username': 'root',
'password': 'password123'
},
'analytics': {
'host': '192.168.1.1',
'port': 5432,
'username': 'admin',
'password': 'securepass'
},
'cache': {
'host': '10.0.0.1',
'port': 27017,
'username': 'cacheuser',
'password': 'cachepass'
}
}

return DatabaseConnection(**db_configs[db_type])


# 测试工厂模式
if __name__ == "__main__":
# 使用工厂函数创建不同类型的数据库连接
main_db = connection_factory('main')
analytics_db = connection_factory('analytics')
cache_db = connection_factory('cache')

# 测试连接
print(main_db.connect())
print(analytics_db.connect())
print(cache_db.connect())

将数据库的配置信息提取到config.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#factory_pattern.py
def connection_factory(db_type):
"""
工厂函数:根据数据库类型创建相应的数据库连接

Args:
db_type (str): 数据库类型 ('main', 'analytics', 'cache')

Returns:
DatabaseConnection: 数据库连接实例

Raises:
KeyError: 当提供的数据库类型不存在时
"""
from config import DATABASE_CONFIGS
if db_type not in DATABASE_CONFIGS:
raise ValueError(f"Unknown database type: {db_type}. Available types: {list(DATABASE_CONFIGS.keys())}")

return DatabaseConnection(**DATABASE_CONFIGS[db_type])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#config.py
# 数据库配置字典
DATABASE_CONFIGS = {
'main': {
'host': 'localhost',
'port': 3306,
'username': 'root',
'password': 'password123'
},
'analytics': {
'host': '192.168.1.1',
'port': 5432,
'username': 'admin',
'password': 'securepass'
},
'cache': {
'host': '10.0.0.1',
'port': 27017,
'username': 'cacheuser',
'password': 'cachepass'
}
}

为什么要这么做

  • 所有配置信息都在一个地方,便于统一管理和维护
  • 易于修改 :配置变更不需要修改业务逻辑代码

工厂模式的核心就是工厂函数

工厂函数是一个返回对象的函数(而不是类),它封装了对象的创建逻辑,根据输入参数决定返回哪种具体对象。

建造者模式(Builder Pattern)

当你需要创建一个有很多属性、配置步骤繁多的对象时(比如一辆汽车、一个 HTTP 请求、一个数据库连接配置),直接用构造函数会非常混乱。 建造者模式通过“分步构建 + 最终组装”的方式,让创建过程清晰、灵活、可读性强。

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
class DatabaseConnectionBuilder:
"""数据库连接建造者类"""

def __init__(self,host,port,username,password):
self._config = {
'host': host,
'port': port,
'username': username,
'password': password,
}

def set_max_connections(self, max_connections):
"""设置最大连接数"""
if max_connections is not None and max_connections <= 0:
raise ValueError("Max connections must be positive")
self._config['max_connections'] = max_connections
return self

def set_timeout(self, timeout):
"""设置超时时间"""
if timeout is not None and timeout <= 0:
raise ValueError("Connect timeout must be positive")
self._config['timeout'] = timeout
return self

def build(self):
"""构建最终的数据库连接对象"""
return DatabaseConnection(**self._config)


# 演示建造者模式的使用
if __name__ == "__main__":
# 创建一个数据库连接建造者
builder = DatabaseConnectionBuilder(
host='localhost',
port=3306,
username='root',
password='password123'
)

# 使用建造者模式构建数据库连接
connection = builder.set_max_connections(100) \
.set_timeout(30) \
.enable_ssl() \
.set_connection_pool('my_pool') \
.set_retry_attempts(3) \
.enable_compression() \
.set_read_preference('secondaryPreferred') \
.build()

单例模式(Singleton 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
class DatabaseConnection:
"""数据库连接单例类"""

_instance = None
_lock = threading.Lock() # 线程锁,确保线程安全

def __new__(cls, *args, **kwargs):
"""重写__new__方法实现单例模式"""
if cls._instance is None:
with cls._lock: # 使用双重检查锁定
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance

def __init__(self, host, port, username, password):
"""初始化数据库连接参数"""
# 防止重复初始化
if hasattr(self, '_initialized'):
return

self.host = host
self.port = port
self.username = username
self.password = password
self._initialized = True

def connect(self):
"""连接数据库"""
return f"Connecting to database at {self.host}:{self.port} with username '{self.username}'"

def client():
db1 = DatabaseConnection(host='localhost', port=3306, username='root', password='password')
db2 = DatabaseConnection(host='localhost', port=3306, username='root', password='password')
print(db1 is db2)

client()

参考资料

【设计模式 inPy】一个视频搞懂三种设计模式:工厂、建造者和单例_哔哩哔哩_bilibili

为什么你应该忘掉设计模式?_哔哩哔哩_bilibili

【设计模式inPython】策略模式:不要再用一个类装所有方法啦!_哔哩哔哩_bilibili