python面向对象编程-设计模式(部分)
面向对象编程(OOP)中的设计模式是一些经过验证的、常见的解决特定问题的方案
目录
文章目录
- python面向对象编程-设计模式(部分)
- 目录
- 简述
- 一、单例模式 (Singleton)
- 单例模式的特点
- 如何实现单例模式
- 方法 1:使用类变量
- 方法 2:使用装饰器
- 方法 3:元类
- 使用要点
- 适用场景
- 二、工厂模式 (Factory)
- 工厂模式的特点
- 如何实现工厂模式
- 方法 1:简单工厂
- 方法 2:工厂方法
- 方法 3:抽象工厂
- 使用要点
- 适用场景
- 三、观察者模式 (Observer)
- 观察者模式的特点
- 如何实现观察者模式
- 方法 1:基本实现
- 方法 2:使用属性变化的观察者
- 使用要点
- 适用场景
- 四、策略模式 (Strategy)
- 策略模式的特点
- 如何实现策略模式
- 方法 1:使用接口
- 使用要点
- 适用场景
- 五、原型模式 (Prototype)
- 原型模式的特点
- 如何实现原型模式
- 方法 1:使用 copy 模块
- 方法 2:重写 clone 方法
- 使用要点
- 适用场景
- 六、建造者模式 (Builder)
- 建造者模式的特点
- 如何实现建造者模式
- 示例:简单的建造者模式
- 使用要点
- 适用场景
简述
设计模式 | 定义 | 特点 | 示例 |
---|---|---|---|
单例模式 (Singleton) | 确保一个类只有一个实例,并提供全局访问点。 适用于需要控制对共享资源的访问场景。 | - 唯一性和全局访问 - 懒加载(可选) - 适用于全局状态管理或共享资源 | 数据库连接、日志管理等。 |
工厂模式 (Factory) | 提供创建对象的接口,允许子类决定实例化哪个类。 适用于需要对对象创建进行封装的场景。 | - 与单例模式不同,它不限制实例的数量。 - 提供了灵活的对象创建方式,便于扩展。 | 使用工厂模式创建不同类型的图形(如圆形、方形)。 |
观察者模式 (Observer) | 定义了一种一对多的依赖关系,使得当一个对象改变状态时, 所有依赖于它的对象都会得到通知并自动更新。 | - 适用于事件驱动的应用程序。 - 允许松耦合的设计。 | GUI系统中的事件监听(如按钮点击)。 |
策略模式 (Strategy) | 定义一系列算法,并将每个算法封装起来, 使它们可以互相替换。策略模式使算法的变化独立于使用算法的客户。 | - 将算法与使用算法的代码分开,以便于灵活变化和扩展。 - 客户可以在运行时选择不同的策略。 | 支付方式(如信用卡、支付宝)的选择。 |
原型模式 (Prototype) | 通过复制现有实例来创建新对象, 而不是通过构造函数直接创建。这在需要多个相似对象时非常有效。 | - 适合创建复杂的对象,且初始化时不需要重复配置属性。 - 使用克隆来创建新实例。 | 图形设计软件中的图形复制功能。 |
建造者模式 (Builder) | 使用多个简单的对象一步一步构建一个复杂的对象。 尤其适合创建需要多个步骤的对象。 | - 提供了更大的灵活性,尤其在对象构建复杂时。 - 可以独立于其他部分构建并实现更精细的控制。 | 构建一个复杂的产品(如多种配件的汽车)。 |
一、单例模式 (Singleton)
单例模式旨在确保一个类只有一个实例,并提供全局访问点。它在需要控制对共享资源(如数据库连接、线程池、配置对象等)的访问时非常有用。以下是单例模式的详细介绍、实现方式和使用要点。
单例模式的特点
- 唯一性:单例模式确保类只有一个实例。
- 全局访问:提供对该实例的全局访问。
- 懒加载:实例在第一次需要时创建,而不是在程序启动时就创建。
如何实现单例模式
以下是单例模式的一些常见实现方式,包括Python中的实现示例。
方法 1:使用类变量
最基本的实现方式,通过一个类变量来存储实例。
class Singleton:_instance = Nonedef __new__(cls, *args, **kwargs):if not cls._instance:cls._instance = super(Singleton, cls).__new__(cls)return cls._instance
# 使用示例
singleton1 = Singleton()
singleton2 = Singleton()
print(singleton1 is singleton2) # 输出: True
方法 2:使用装饰器
可以使用装饰器来简化单例的实现。
def singleton(cls):instances = {}def get_instance(*args, **kwargs):if cls not in instances:instances[cls] = cls(*args, **kwargs)return instances[cls]return get_instance
@singleton
class MyClass:pass
# 使用示例
instance1 = MyClass()
instance2 = MyClass()
print(instance1 is instance2) # 输出: True
方法 3:元类
通过元类定义单例,这是比较高级和灵活的实现。
class SingletonMeta(type):_instances = {}def __call__(cls, *args, **kwargs):if cls not in cls._instances:instance = super().__call__(*args, **kwargs)cls._instances[cls] = instancereturn cls._instances[cls]
class Singleton(metaclass=SingletonMeta):pass
# 使用示例
singleton1 = Singleton()
singleton2 = Singleton()
print(singleton1 is singleton2) # 输出: True
使用要点
- 线程安全:实现单例模式时,特别是在多线程环境下,需确保线程安全。可以使用锁或其他同步机制。
- 惰性初始化:建议在使用时才初始化单例对象,以减少资源占用。
- 不允许子类化:如果单例类被继承,可能会产生多个实例,推荐禁用子类化。
- 行文清晰:确保代码易于理解,文档中注明该类为单例,以免其他开发者误用。
- 资源管理:如果单例对象涉及资源(如数据库连接),确保提供适当的关闭或释放方法。
适用场景
- 配置管理:应用程序的配置信息需要共享。
- 数据库连接池:避免频繁创建和销毁数据库连接。
- 日志管理:确保日志写入是线程安全的,并从一个实例写入日志。
- 全局状态管理:在应用程序中管理状态或上下文信息。 通过单例模式,你可以规范对象的共享使用,提高性能和可维护性。在实际开发中,需根据项目具体需求灵活使用该模式。
二、工厂模式 (Factory)
工厂模式用于定义一个接口用于创建对象,但让子类决定实例化哪个类。工厂模式将对象的创建过程封装起来,使得系统与具体产品的耦合度降低。工厂模式适用于需要大量创建相似对象的情况。
工厂模式的特点
- 解耦:客户代码与具体产品解耦,降低了系统耦合度。
- 灵活性:可以动态决定创建哪一个类的实例,方便扩展。
- 集中管理:对象的创建逻辑集中在一个地方,便于维护。
如何实现工厂模式
以下是工厂模式的一些常见实现方式,包括Python中的实现示例。
方法 1:简单工厂
简单工厂是一个静态方法,根据传入参数返回不同的产品对象。
class ProductA:def operation(self):return "Product A"
class ProductB:def operation(self):return "Product B"
class SimpleFactory:@staticmethoddef create_product(product_type):if product_type == 'A':return ProductA()elif product_type == 'B':return ProductB()else:raise ValueError("Unknown product type")# 使用示例
product = SimpleFactory.create_product('A')
print(product.operation()) # 输出: Product A
方法 2:工厂方法
工厂方法允许子类决定要实例化的具体产品,具备更好的扩展性。
class Creator:def factory_method(self):raise NotImplementedError
class ConcreteCreatorA(Creator):def factory_method(self):return ProductA()
class ConcreteCreatorB(Creator):def factory_method(self):return ProductB()# 使用示例
creator = ConcreteCreatorA()
product = creator.factory_method()
print(product.operation()) # 输出: Product A
方法 3:抽象工厂
抽象工厂提供一个接口,用于创建一系列相关或相互依赖的对象,避免了依赖于具体类。
class AbstractFactory:def create_product_a(self):raise NotImplementedErrordef create_product_b(self):raise NotImplementedError
class ConcreteFactory1(AbstractFactory):def create_product_a(self):return ProductA()def create_product_b(self):return ProductB()
# 使用示例
factory = ConcreteFactory1()
product_a = factory.create_product_a()
product_b = factory.create_product_b()
print(product_a.operation()) # 输出: Product A
print(product_b.operation()) # 输出: Product B
使用要点
- 接口优先:使用接口或者抽象类定义产品的行为,以便于扩展和替换。
- 单一职责:工厂类负责对象的创建,其他类应关注其业务逻辑,确保代码的清晰和可维护。
- 提高可扩展性:新增产品只需新增工厂和产品类,不影响现有代码。
适用场景
- 产品系列管理:需要创建多种相关产品时。
- 复杂对象需求:创建复杂对象时,可以通过工厂模式分离创建逻辑。
- 对象状态管理:根据输入参数动态选择创建对象,有利于调整业务逻辑。
通过工厂模式,你可以提高对象创建的灵活性和可维护性,使得系统具有更高的扩展能力。
三、观察者模式 (Observer)
观察者模式它定义了一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这个模式广泛应用于需要实时更新的场景,如用户界面、事件处理和消息推送等。
观察者模式的特点
- 一对多:一个被观察者(主题)可以有多个观察者(订阅者),它们会在被观察者状态变化时得到通知。
- 解耦合:观察者与被观察者之间是松耦合的,观察者不需要知道被观察者的具体细节。
- 动态性:观察者可以在运行时添加或移除,这种灵活性使得系统可以随时调整监控的对象。
如何实现观察者模式
以下是观察者模式的常见实现方式,包括Python中的实现示例。
方法 1:基本实现
我们可以通过定义一个主题(被观察者)和观察者类来实现。
class Subject:def __init__(self):self._observers = []def attach(self, observer):self._observers.append(observer)def detach(self, observer):self._observers.remove(observer)def notify(self):for observer in self._observers:observer.update(self)
class Observer:def update(self, subject):raise NotImplementedError("Subclass must implement abstract method")
class ConcreteObserver(Observer):def update(self, subject):print("Observer: Subject's state has changed!")
# 使用示例
subject = Subject()
observer = ConcreteObserver()
subject.attach(observer)
subject.notify() # 输出: Observer: Subject's state has changed!
方法 2:使用属性变化的观察者
我们可以在主题中包含状态,并在状态发生变化时通知观察者。
class Subject:def __init__(self):self._observers = []self._state = None@propertydef state(self):return self._state@state.setterdef state(self, value):self._state = valueself.notify()def attach(self, observer):self._observers.append(observer)def detach(self, observer):self._observers.remove(observer)def notify(self):for observer in self._observers:observer.update(self)
class ConcreteObserver(Observer):def update(self, subject):print(f"Observer: Subject's state is now {subject.state}")
# 使用示例
subject = Subject()
observer = ConcreteObserver()
subject.attach(observer)
subject.state = "New State" # 输出: Observer: Subject's state is now New State
使用要点
- 避免过度通知:要确保只在必要时通知观察者,避免给系统带来性能负担。
- 处理异常:在通知观察者时,需妥善处理可能发生的异常,以免影响主题。
- 管理依赖关系:在观察者不再需要时,及时将其从主题中移除,以避免可能的内存泄露。
- 线程安全:若在多线程环境中使用,确保调整观察者列表和通知过程是线程安全的。
适用场景
- 事件处理系统:如UI组件与数据模型之间的交互。
- 消息推送:如RSS订阅者接收新消息的场景。
- 状态监控:如监测系统状态变化,并通知相关组件更新。 通过观察者模式,可以有效地管理对象之间的状态依赖关系,提高系统的灵活性和扩展性。它在许多实时应用和事件驱动系统中是不可或缺的设计模式。
四、策略模式 (Strategy)
策略模式是一种行为型设计模式,旨在定义一系列的算法或操作,并将它们封装在各自的类中,使得它们可以相互替换,能够独立于使用它们的客户端变化。策略模式提供了更好的灵活性和可扩展性,特别是在需要选择不同算法或行为的情况下。
策略模式的特点
- 算法封装:每个算法被封装成一个独立的类,保证了算法的独立性。
- 可替换性:客户端可以根据需要自由替换具体策略,而不需要修改客户端的代码。
- 开闭原则:可以在不修改现有代码的情况下添加新的策略,符合开放-关闭原则。
如何实现策略模式
以下是策略模式的一些常见实现方式,包括 Python 中的实现示例。
方法 1:使用接口
首先定义一个策略接口,然后创建多个具体的策略类实现该接口。
from abc import ABC, abstractmethod
# 策略接口
class Strategy(ABC):@abstractmethoddef execute(self, data):pass
# 具体策略 A
class ConcreteStrategyA(Strategy):def execute(self, data):return f"Strategy A processing {data}"
# 具体策略 B
class ConcreteStrategyB(Strategy):def execute(self, data):return f"Strategy B processing {data}"
# 上下文类
class Context:def __init__(self, strategy: Strategy):self._strategy = strategydef set_strategy(self, strategy: Strategy):self._strategy = strategydef execute_strategy(self, data):return self._strategy.execute(data)
# 使用示例
context = Context(ConcreteStrategyA())
print(context.execute_strategy("some data")) # 输出: Strategy A processing some data
context.set_strategy(ConcreteStrategyB())
print(context.execute_strategy("some other data")) # 输出: Strategy B processing some other data
使用要点
- 选择合适的策略:在选择策略时需要考虑性能和内存占用,避免过多将不同策略过度功能化。
- 简化上下文:上下文类应尽量保持简单,仅用于选择和执行策略,减少与具体策略的依赖。
- 灵活应变:策略类应设计为可以扩展,以适应未来可能会增加的新策略。
适用场景
- 排序算法选择:根据数据特点选择不同的排序算法。
- 支付方式:电商系统中根据用户选择使用不同的支付策略(如信用卡、微信支付等)。
- 数据处理:根据不同的数据类型选择不同的数据处理方法。 通过策略模式,可以让算法的选择更具灵活性,提高代码的可维护性和可扩展性,适应不断变化的需求。
五、原型模式 (Prototype)
原型模式是通过复制一个已有的对象来创建新的对象,而不是通过构造函数进行初始化。这种模式适用于需要创建重复的对象时,尤其是在创建成本较高或复杂的对象时。原型模式提供了一种简单、高效的对象创建方式。
原型模式的特点
- 克隆机制:通过克隆现有对象以创建新对象,避免了昂贵的初始化成本。
- 灵活性:可以通过修改原型对象的状态,快速生成多种不同的对象。
- 简化对象创建:当对象的创建过程复杂时,使用原型模式可以简化流程。
如何实现原型模式
以下是原型模式的一些常见实现方式,包括 Python 中的实现示例。
方法 1:使用 copy 模块
通过 Python 的 copy
模块中的 copy()
或 deepcopy()
方法来实现对象的克隆。
import copy
class Prototype:def __init__(self):self._objects = {}def register_object(self, name, obj):self._objects[name] = objdef unregister_object(self, name):del self._objects[name]def clone(self, name, **attrs):obj = copy.deepcopy(self._objects.get(name))obj.__dict__.update(attrs)return obj
# 使用示例
class ConcretePrototype:def __init__(self):self.attribute = "原始"
prototype_manager = Prototype()
prototype_manager.register_object("对象1", ConcretePrototype())
cloned_obj = prototype_manager.clone("对象1", attribute="克隆")
print(cloned_obj.attribute) # 输出: 克隆
方法 2:重写 clone 方法
在类中定义一个 clone
方法,用于返回自身的深拷贝。
class Prototype:def clone(self):return self.__class__()
class ConcretePrototype(Prototype):def __init__(self, attribute):self.attribute = attribute
# 使用示例
original = ConcretePrototype(attribute="原始")
cloned = original.clone()
cloned.attribute = "克隆"
print(original.attribute) # 输出: 原始
print(cloned.attribute) # 输出: 克隆
使用要点
- 深拷贝与浅拷贝:根据需要选择使用深拷贝(复制对象及其引用的对象)或浅拷贝(只复制对象本身)。
- 克隆方法的实现:确保原型类实现适当的克隆方法,以保证对象状态的完整复制。
- 性能考虑:在对象创建成本较高时,原型模式能显著提高性能。
适用场景
- 复杂对象的创建:当新对象的初始化过程复杂且需要大量的数据时,原型模式可以提升效率。
- 需要动态创建对象时:在运行时动态改变创建的对象类型,以满足多变的需求。
- 对象状态的共享:当多个对象之间具有相同的初始状态时,通过克隆原型对象可以快速生成。
- 减少创建成本:在大量相似对象的创建场景中,通过原型模式避免了重复初始化的成本,提高了性能。 通过原型模式,你可以有效管理对象的创建过程,同时减少内存和计算开销,在特定场景下提升应用程序的性能和灵活性。
六、建造者模式 (Builder)
建造者模式是旨在将一个复杂对象的构建过程与其表示分离,以便使用相同的构建过程创建不同的对象。该模式在需要构建具有多个可选属性或复杂结构的对象时非常有用。以下是建造者模式的详细介绍、实现方式和使用要点。
建造者模式的特点
- 分离过程和表示:构建一个对象的过程与展示分开,使得同一个构建过程可以创建不同的表示。
- 灵活性:可以使用同一个建造者类创建不同类型和构造的对象。
- 可读性:构建过程清晰,易于理解和维护,特别是在参数较多时。
如何实现建造者模式
以下是建造者模式的一些常见实现方式,包括Python中的实现示例。
示例:简单的建造者模式
class Product:def __init__(self):self.parts = []def add(self, part):self.parts.append(part)def show(self):return f"Product parts: {', '.join(self.parts)}"
class Builder:def __init__(self):self.product = Product()def build_part_a(self):self.product.add("Part A")def build_part_b(self):self.product.add("Part B")def build_part_c(self):self.product.add("Part C")def get_result(self):return self.product
# 使用示例
builder = Builder()
builder.build_part_a()
builder.build_part_b()
product = builder.get_result()
print(product.show()) # 输出: Product parts: Part A, Part B
使用要点
- 避免构造器复杂性:当一个对象的构建复杂时,使用建造者模式来简化构造过程,以提高代码可读性。
- 需要清晰的构建步骤:在使用建造者模式时,确保构建步骤明确,方便其他开发者理解整个构建流程。
- 链式调用:可以通过链式调用来简化建造者的接口,增强流畅性和可读性。
- 避免过度设计:对于简单的对象构建,使用建造者模式可能会导致不必要的复杂性,应根据实际需求灵活选择。
适用场景
- 复杂对象创建:当一个对象需要多个参数或配置且构建过程高度依赖于这些参数。
- 需要多个变体的对象:例如,构建不同配置的产品,或多个不同显示风格的用户界面。
- 动态创建对象:在某些情况下,对象的创建步骤可能是在运行时决定的,而不是在编译时固定的。 通过建造者模式,可以提高对象构建的灵活性和可维护性,使代码更易于理解和使用。在实际开发中,需根据具体需求选择合理的设计模式。