创建型设计模式 - 工厂模式
工厂模式通过将对象的创建封装在工厂类中,体现了开闭原则。在工厂模式中,已有的核心源码(工厂类)不需要修改,而是通过扩展工厂类或添加新的具体工厂类来引入新的产品类。这样做既对修改关闭,又对扩展开放。
下面是一个简单的例子,演示了使用工厂模式体现开闭原则的情况:
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!
在这个例子中,开闭原则的体现如下:
对扩展开放: 可以轻松地通过添加新的具体产品类(例如,添加一个新的具体动物类)来扩展系统,无需修改已有的核心源码。
对修改关闭: 客户端代码通过调用抽象工厂类和抽象产品类来获取具体的产品,而无需关心具体产品的实现细节。已有的核心源码(
AnimalFactory
、Animal
及其子类)无需修改,即可引入新的产品。
通过这种方式,工厂模式帮助确保系统在引入新的产品类时保持稳定,同时保持了系统的可扩展性。客户端代码不依赖于具体产品类的实现,而是依赖于抽象工厂和抽象产品,从而降低了耦合度。
让我们更详细地解释一下工厂模式如何体现开闭原则,使用上述 Python 示例。
首先,我们有两个抽象类:
Animal
抽象产品类: 定义了动物对象的接口,其中有一个抽象方法speak
。AnimalFactory
抽象工厂类: 定义了创建动物对象的接口,其中有一个抽象方法create_animal
。
这两个抽象类构成了工厂模式的基础,它们是系统的核心源码。
现在,我们有两个具体产品类:
Dog
具体产品类: 实现了Animal
接口,提供了狗的具体实现,包括speak
方法返回 “Woof!”。Cat
具体产品类: 同样实现了Animal
接口,提供了猫的具体实现,包括speak
方法返回 “Meow!”。
接下来,我们有两个具体工厂类:
DogFactory
具体工厂类: 实现了AnimalFactory
接口,负责创建Dog
对象。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
),我们只需要创建一个新的具体产品类和一个对应的具体工厂类,而无需修改已有的核心源码。这就是对修改关闭、对扩展开放的体现,符合开闭原则。
总结一下上述工厂模式的例子和开闭原则的体现:
抽象产品类 (
Animal
): 定义了产品的接口,包含了产品的通用方法。具体产品类 (
Dog
,Cat
): 分别实现了抽象产品类,提供了具体的产品实现。抽象工厂类 (
AnimalFactory
): 定义了创建产品的接口,包含了创建产品的方法。具体工厂类 (
DogFactory
,CatFactory
): 分别实现了抽象工厂类,负责创建具体的产品。客户端代码 (
get_animal_sound
): 使用工厂模式获取具体产品的实例,并调用产品的方法,而不需要直接实例化具体产品类。
通过这种设计,实现了开闭原则:
对修改关闭: 核心源码(抽象产品类和抽象工厂类)不需要修改,即使引入新的产品类,也不会影响已有的代码。
对扩展开放: 可以轻松地引入新的产品类(例如,
Lion
),只需创建新的具体产品类和对应的具体工厂类,而无需修改已有的核心源码。
这种设计方式提高了系统的可维护性和可扩展性,使得系统更容易适应变化,符合开闭原则的设计理念。
本作品采用《CC 协议》,转载必须注明作者和本文链接
上面的文章通过问chatGPT3.5 来得到答案的 一开始不知道什么是 对修改关闭,对扩展开放。现在明白了 原来 对修改关闭 是只 抽象出来核心代码 动物类, 再想加一个其他的动物是不涉及到修改核心代码,就是所说的 对扩展开放。这里也没有 if else , 以前所学的都是 传入动物类型来区分不同的动物,这里感觉很加好。