一、设计模式分类
1.创建型模式(Creational Patterns)
主要关注对象的创建,隐藏对象创建的复杂性,提高程序的可扩展性。
常见的创建型模式有:单例模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式。
2.结构型模式(Structural Patterns)
主要关注对象的组合,通过对象的组合提高程序的模块化。
常见的结构型模式有:适配器模式、桥接模式、组合模式、装饰器模式、外观模式、享元模式和代理模式。
3.行为型模式(Behavioral Patterns)
主要关注对象之间的交互,描述对象如何协作以完成某种任务。
常见的行为型模式有:责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式和访问者模式。
二、使用场景
设计模式 | 目的 | 使用场景示例 |
---|---|---|
单例模式 | 保证一个类仅有一个实例,并提供一个访问它的全局访问点 | - 日志记录器 -线程池 -缓存 |
工厂方法模式 | 定义一个创建对象的接口,让子类决定实例化哪个类 | - 各种工厂类(如视频游戏工厂模式创建不同类型的角色) |
抽象工厂模式 | 解决一个系列的工厂,用于创建一组相关或依赖的对象 | - GUI组件库 - 汽车组装线 |
建造者模式 | 分离对象的构建过程和表示,允许通过指定复杂对象类型和内容逐步构造一个复杂对象 | - 构建复杂对象,如SQL语句构建器 |
原型模式 | 通过复制现有的实例来创建新的实例 | - 需要频繁创建开销较大的对象时 |
适配器模式 | 允许将不兼容的接口转换为一个可以使用的兼容接口 | - 兼容旧的类库 - 第三方库的集成 |
桥接模式 | 分离抽象部分和实现部分,使它们可以独立地变化 | - 当一个类存在多个变化维度时 |
组合模式 | 允许将对象组合成树形结构以表示“部分-整体”的层次结构 | - 处理类似文件系统的层次结构 |
装饰器模式 | 动态地添加额外的功能到一个对象上,而不是通过继承 | - 扩展对象功能,而不改变其类 |
外观模式 | 为子系统中的一组接口提供一个统一的接口 | - 简化复杂的系统接口 |
享元模式 | 运用共享技术有效地支持大量细粒度的对象 | - 当系统中存在大量相似对象时 |
代理模式 | 为其他对象提供一个代理或占位符,以控制对这个对象的访问 | - 访问控制 - 延迟初始化 |
责任链模式 | 使多个对象都有机会处理请求,避免请求的发送者和接收者之间的耦合 | - 审批流程 - 错误处理 |
命令模式 | 将一个请求封装为一个对象,从而允许用户使用不同的请求来参数化其他对象 | - 宏系统 - 事务系统 |
解释器模式 | 定义一个语言的文法,并且建立一个解释器来解释该语言中的句子 | - 解析表达式或指令 |
迭代器模式 | 提供一种顺序访问一个聚合对象元素的方法,而不暴露其内部的表示 | - 需要遍历聚合对象,而不关心其内部结构 |
中介者模式 | 用一个中介对象来封装一系列对象之间的交互 | - 集中管理对象间的通信 |
备忘录模式 | 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态 | - 提供对象状态的快照,用于撤销操作 |
观察者模式 | 当对象间存在一对多关系时,则使用观察者模式 | - 事件多级触发 - 发布/订阅系统 |
状态模式 | 允许对象在其内部状态改变时改变它的行为 | - 行为随状态改变而改变的对象 |
策略模式 | 定义一系列算法,把它们一个个封装起来,并使它们可以互换 | - 需要动态地在运行时选择算法 |
访问者模式 | 表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作 | - 数据结构相对稳定,但经常需要在此结构上定义新的操作 |
三、 Demo
1.1 单例模式
优点:
- 全局访问:提供了一个全局访问点,便于控制实例数量。
- 资源节约:避免了创建多个对象时的资源浪费。
- 线程安全:在多线程环境中,可以保证只创建一个实例。
- 控制实例化:可以控制对象的创建过程。
缺点:
- 代码耦合:单例模式可能会隐藏一些依赖关系,导致代码耦合。
- 可测试性差:由于单例模式是全局的,这使得单元测试变得困难。
- 内存浪费:单例对象在程序的整个生命周期内都占用内存。
- 滥用:单例模式有时会被滥用,导致程序设计不灵活。
示例:
"""可以使用模块级别的变量、__new__方法重写或者借助元类来实现单例模式。"""
#示例1:
class Singleton:
_instance = None
@classmethod
def get_instance(cls):
if not cls._instance:
cls._instance = cls()
return cls._instance
# 构造函数被保护起来,防止外部直接实例化
def __init__(self):
if Singleton._instance is not None:
raise Exception("This class is a singleton!")
#示例2:
class Singleton2:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super(Singleton2, cls).__new__(cls)
return cls._instance
# 使用单例模式
singleton1 = Singleton2()
singleton2 = Singleton2()
print(singleton1 is singleton2) # 输出True,两个变量引用同一个实例
1.2 工厂模式
优点:
- 代码解耦:将对象的创建与使用分离,使得代码更加灵活,易于扩展。
- 提高可维护性:当需要添加新的产品时,只需要添加一个具体的产品类和相应的具体工厂类即可,无需修改已有的工厂类。
- 封装性:隐藏了对象创建的细节,调用者只需要知道类型,不需要知道具体的实现。
缺点:
- 每增加一个产品类别,都需要增加一个产品类和一个工厂类,这可能导致类的数量成倍增加。
- 系统的抽象程度变得更高,对于简单的情况,可能会增加系统的复杂性。
示例:
"""例如,可以使用工厂函数或抽象基类(Abstract Base Classes, ABCs)来实现工厂模式"""
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def sound(self):
pass
class Dog(Animal):
def sound(self):
return "Woof! "
class Cat(Animal):
def sound(self):
return "Meow! "
class AnimalFactory:
@staticmethod
def get_animal(animal_type):
if animal_type == "dog":
return Dog()
elif animal_type == "cat":
return Cat()
else:
raise ValueError("Invalid animal type")
# 使用工厂模式
factory = AnimalFactory()
dog = factory.create_animal("dog")
cat = factory.create_animal("cat")
print(dog.sound()) # 输出 "Woof!"
print(cat.sound()) # 输出 "Meow!"
1.3 原型模式
优点:
- 减少对象初始化成本。
- 简化对象创建过程。
- 保持对象属性一致性。
- 提供更快的对象创建速度。
缺点:
- 对于复杂的原型对象,克隆过程可能增加复杂性;
- 对象创建方式不易理解
示例:
"""在Python中实现原型模式,可以通过定义一个包含clone方法的类来实现。"""
import copy
class Prototype:
def clone(self):
return copy.deepcopy(self)
class Circle(Prototype):
def __init__(self, radius):
self.radius = radius
# 使用示例
circle1 = Circle(5)
circle2 = circle1.clone() # 通过原型模式的clone方法创建新对象
2.1.适配器模式(Adapter Pattern)
将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。适配器模式提供了一种灵活的方式来适应不同的接口需求。
优点:
- 兼容性:使得不兼容的接口可以协同工作。
- 解耦:将客户端与需要适配的类解耦,客户端不需要知道适配的具体细节。
- 灵活性:可以设计一个类来适配多种不同的接口。
缺点:
- 增加系统的复杂性:过多使用适配器可能会使系统变得复杂。
- 性能损失:可能存在轻微的性能损失,因为多了一层间接调用。
示例:
class OldSystem:
def legacy_method(self):
return "Legacy Method"
class NewSystem:
def modern_method(self):
return "Modern Method"
class Adapter:
def __init__(self, old_system):
self.old_system = old_system
def modern_method(self):
return self.old_system.legacy_method()
# 使用适配器模式
old_system = OldSystem()
adapter = Adapter(old_system)
print(adapter.modern_method()) # 输出 "Legacy Method"
2.2.装饰器模式(Decorator Pattern)
动态地将责任附加到对象上,提供了一种灵活的替代继承的方式。装饰器模式使得用户可以在运行时向对象添加新的功能,而不需要修改其源代码。
优点:
- 灵活性:通过使用装饰器,可以在运行时给对象添加功能。
- 扩展性:可以为老系统添加装饰器,以提高其性能。
- 代码复用:装饰器可以被多个类重用。
缺点:
- 增加系统的复杂性:过度使用装饰器模式可能会使系统变得复杂。
- 可能会引起性能问题:在对象周围过度包装装饰器可能会影响性能。
示例:
from functools import wraps
def log_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with args: {args}, kwargs: {kwargs}")
result = func(*args, **kwargs)
print(f"{func.__name__} returned: {result}")
return result
return wrapper
@log_decorator
def add(a, b):
return a + b
result = add(3, 5)
2.3.外观模式(Facade Pattern)
为子系统中的一组接口提供一个一致的界面,使得子系统更容易使用。外观模式简化了对复杂子系统的使用,通过提供一个简单的接口来访问复杂的系统功能。
优点:
简化接口:客户端通过一个接口就能与子系统交互,无需了解子系统内部的复杂性。
解耦:减少了客户端与子系统组件的依赖,提高了子系统的独立性。
层次结构:客户端只需要关注外观对象,不需要了解子系统内部的实现细节。
缺点:
理解困难:对于不熟悉系统的新开发者,外观模式可能会隐藏内部功能,导致理解上的困难。
灵活性降低:使用外观模式可能会限制子系统的部分功能,因为外观对象可能只提供了有限的接口。
3.1.策略模式(Strategy Pattern)
优点:
- 解耦:策略模式将算法的使用从算法的实现中分离出来。
- 可扩展性:新的算法可以很容易地添加到系统中。
- 可替换:可以很容易地替换或更新现有的算法。
缺点:
- 增加复杂性:可能会增加系统中策略类的数量。
- 性能考虑:由于策略模式使用多态,可能会有一些性能开销。
示例:
class PaymentStrategy:
def pay(self, amount):
pass
class CreditCardPayment(PaymentStrategy):
def pay(self, amount):
print(f"Paid ${amount} with credit card")
class PayPalPayment(PaymentStrategy):
def pay(self, amount):
print(f"Paid ${amount} with PayPal")
class ShoppingCart:
def __init__(self, payment_strategy):
self._items = []
self._payment_strategy = payment_strategy
def add_item(self, item):
self._items.append(item)
def checkout(self):
total_amount = sum(item['price'] for item in self._items)
self._payment_strategy.pay(total_amount)
# 使用策略模式
credit_card_payment = CreditCardPayment()
shopping_cart1 = ShoppingCart(credit_card_payment)
shopping_cart1.add_item({'item': 'Laptop', 'price': 1000})
shopping_cart1.add_item({'item': 'Mouse', 'price': 20})
shopping_cart1.checkout() # 输出 "Paid $1020 with credit card"
paypal_payment = PayPalPayment()
shopping_cart2 = ShoppingCart(paypal_payment)
shopping_cart2.add_item({'item': 'Headphones', 'price': 50})
shopping_cart2.checkout() # 输出 "Paid $50 with PayPal"
3.2.命令模式(Command Pattern)
优点:
- 解耦:命令模式将调用操作的对象与知道如何实现该操作的对象解耦。
- 扩展性:可以容易地扩展新的命令。
- 宏命令:可以组合多个命令到一个宏命令中。
缺点:
- 增加系统复杂性:可能会增加系统中对象的数量。
- 命令过多:如果系统中命令对象太多,可能会导致管理上的复杂性。
示例:
from abc import ABC, abstractmethod
class Command(ABC):
@abstractmethod
def execute(self):
pass
class Light:
def on(self):
print("Light is on")
def off(self):
print("Light is off")
class LightOnCommand(Command):
def __init__(self, light):
self.light = light
def execute(self):
self.light.on()
class LightOffCommand(Command):
def __init__(self, light):
self.light = light
def execute(self):
self.light.off()
class RemoteControl:
def __init__(self):
self.command = None
def set_command(self, command):
self.command = command
def press_button(self):
self.command.execute()
# 使用命令模式
light = Light()
light_on = LightOnCommand(light)
light_off = LightOffCommand(light)
remote = RemoteControl()
remote.set_command(light_on)
remote.press_button() # 输出 "Light is on"
remote.set_command(light_off)
remote.press_button() # 输出 "Light is off"