创建型设计模式 - 工厂模式

工厂模式通过将对象的创建封装在工厂类中,体现了开闭原则。在工厂模式中,已有的核心源码(工厂类)不需要修改,而是通过扩展工厂类或添加新的具体工厂类来引入新的产品类。这样做既对修改关闭,又对扩展开放。

下面是一个简单的例子,演示了使用工厂模式体现开闭原则的情况:

from abc import ABC, abstractmethod

# 抽象产品类
class Animal(ABC):
    @abstractmethod
    def speak(self):
        pass

# 具体产品类 - Dog
class Dog(Animal):
    def speak(self):
        return "Woof!"

# 具体产品类 - Cat
class Cat(Animal):
    def speak(self):
        return "Meow!"

# 抽象工厂类
class AnimalFactory(ABC):
    @abstractmethod
    def create_animal(self):
        pass

# 具体工厂类 - DogFactory
class DogFactory(AnimalFactory):
    def create_animal(self):
        return Dog()

# 具体工厂类 - CatFactory
class CatFactory(AnimalFactory):
    def create_animal(self):
        return Cat()

# 客户端代码
def get_animal_sound(animal_factory):
    animal = animal_factory.create_animal()
    return animal.speak()

# 使用工厂模式获取 Dog 的声音
dog_sound = get_animal_sound(DogFactory())
print(dog_sound)  # 输出: Woof!

# 使用工厂模式获取 Cat 的声音
cat_sound = get_animal_sound(CatFactory())
print(cat_sound)  # 输出: Meow!

在这个例子中,开闭原则的体现如下:

  • 对扩展开放: 可以轻松地通过添加新的具体产品类(例如,添加一个新的具体动物类)来扩展系统,无需修改已有的核心源码。

  • 对修改关闭: 客户端代码通过调用抽象工厂类和抽象产品类来获取具体的产品,而无需关心具体产品的实现细节。已有的核心源码(AnimalFactoryAnimal 及其子类)无需修改,即可引入新的产品。

通过这种方式,工厂模式帮助确保系统在引入新的产品类时保持稳定,同时保持了系统的可扩展性。客户端代码不依赖于具体产品类的实现,而是依赖于抽象工厂和抽象产品,从而降低了耦合度。

让我们更详细地解释一下工厂模式如何体现开闭原则,使用上述 Python 示例。

首先,我们有两个抽象类:

  1. Animal 抽象产品类: 定义了动物对象的接口,其中有一个抽象方法 speak

  2. AnimalFactory 抽象工厂类: 定义了创建动物对象的接口,其中有一个抽象方法 create_animal

这两个抽象类构成了工厂模式的基础,它们是系统的核心源码。

现在,我们有两个具体产品类:

  1. Dog 具体产品类: 实现了 Animal 接口,提供了狗的具体实现,包括 speak 方法返回 “Woof!”。

  2. Cat 具体产品类: 同样实现了 Animal 接口,提供了猫的具体实现,包括 speak 方法返回 “Meow!”。

接下来,我们有两个具体工厂类:

  1. DogFactory 具体工厂类: 实现了 AnimalFactory 接口,负责创建 Dog 对象。

  2. CatFactory 具体工厂类: 实现了 AnimalFactory 接口,负责创建 Cat 对象。

这两个具体工厂类是用于创建具体产品的工厂,它们可以被扩展以创建新的产品类,同时无需修改已有的核心源码。

最后,客户端代码使用工厂模式获取具体产品的实例:

def get_animal_sound(animal_factory):
    animal = animal_factory.create_animal()
    return animal.speak()

# 使用工厂模式获取 Dog 的声音
dog_sound = get_animal_sound(DogFactory())
print(dog_sound)  # 输出: Woof!

# 使用工厂模式获取 Cat 的声音
cat_sound = get_animal_sound(CatFactory())
print(cat_sound)  # 输出: Meow!

这里的关键是客户端代码通过工厂接口(AnimalFactory)和产品接口(Animal)与具体实现解耦合。客户端不需要知道具体产品的实现,只需要通过工厂接口获取产品,然后调用产品的方法。

我们只需要创建一个新的具体产品类和一个对应的具体工厂类,而无需修改已有的核心源码。这就是对修改关闭、对扩展开放的体现,符合开闭原则现在,如果我们要引入一个新的动物类(例如,Lion),我们只需要创建一个新的具体产品类和一个对应的具体工厂类,而无需修改已有的核心源码。这就是对修改关闭、对扩展开放的体现,符合开闭原则。

总结一下上述工厂模式的例子和开闭原则的体现:

  1. 抽象产品类 (Animal): 定义了产品的接口,包含了产品的通用方法。

  2. 具体产品类 (Dog, Cat): 分别实现了抽象产品类,提供了具体的产品实现。

  3. 抽象工厂类 (AnimalFactory): 定义了创建产品的接口,包含了创建产品的方法。

  4. 具体工厂类 (DogFactory, CatFactory): 分别实现了抽象工厂类,负责创建具体的产品。

  5. 客户端代码 (get_animal_sound): 使用工厂模式获取具体产品的实例,并调用产品的方法,而不需要直接实例化具体产品类。

通过这种设计,实现了开闭原则:

  • 对修改关闭: 核心源码(抽象产品类和抽象工厂类)不需要修改,即使引入新的产品类,也不会影响已有的代码。

  • 对扩展开放: 可以轻松地引入新的产品类(例如,Lion),只需创建新的具体产品类和对应的具体工厂类,而无需修改已有的核心源码。

这种设计方式提高了系统的可维护性和可扩展性,使得系统更容易适应变化,符合开闭原则的设计理念。

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 1

上面的文章通过问chatGPT3.5 来得到答案的 一开始不知道什么是 对修改关闭,对扩展开放。现在明白了 原来 对修改关闭 是只 抽象出来核心代码 动物类, 再想加一个其他的动物是不涉及到修改核心代码,就是所说的 对扩展开放。这里也没有 if else , 以前所学的都是 传入动物类型来区分不同的动物,这里感觉很加好。

3个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
77
粉丝
8
喜欢
43
收藏
49
排名:84
访问:10.4 万
私信
所有博文
社区赞助商