跳到主要内容

工厂方法模式

工厂方法在一个特定的创建者(Creator)父类中提供了一个创建对象的接口,但是允许子类决定实例化的类。这种模式的目的是将实例化的过程推迟到子类中,以便在提供相同接口的情况下,允许子类选择实例化的类。

工厂方法将创建产品的代码实际使用产品的代码分离。

结构

工厂方法示意图工厂方法示意图

工厂方法通常包括以下二者:

  • 产品(Product):产品是工厂方法创建的对象的接口或抽象基类。
  • 创建者(Creator):创建者是一个类,其中包含一个工厂方法,该方法返回一个产品对象。创建者的子类可以实现工厂方法以更改产品的类型。

而二者又拥有相应的实现,分别代表具体产品和具体的创建者。

应用场景

  • 当构建一个类的对象却不知道对象的实际类型时
  • 当创建对象时需要特定的逻辑,而该逻辑需要多态性时
  • 当产品可能出现继承关系,而创建者希望通过同一接口创建所有产品时
    • 例如 UI 库(创建者)和按钮(产品)之间的关系

优缺点

优点

  • 避免创建者和具体产品之间的紧密耦合。
  • 单一职责原则。创建产品的逻辑被分离到一个单独的类中,这使得代码更容易维护。
  • 开闭原则。对扩展开放,对修改关闭。可以在不更改现有代码的情况下引入新的产品类型。

缺点

  • 可能会导致代码中的类数量激增,因为每个产品都需要一个具体的创建者类。这可能会使代码更难理解。

代码示例

下面的示例展示了一个简单的有关门的工厂方法。门有两种类型:铁门和木门。DoorFactory 是一个创建者,它有一个工厂方法 make_door,该方法返回一个门对象。IronDoorFactoryWoodenDoorFactory 是具体的创建者,它们分别返回铁门和木门。

用户可以通过调用 deliver_door 方法来获得一个门对象(无论是哪个工厂),并且可以使用该对象的继承方法 area 和多态方法 open

# [x] Pattern: Factory method
# A class that delegates the creation of objects to its subclasses,
# allowing each subclass to decide which object to create.

# Why we use it
# When constructing a class that does not know the type of the objects it will create
# In other words, we use a universal method interface to create objects, but the specific implementation is left to the subclasses

from abc import ABC, abstractmethod
from dataclasses import dataclass


@dataclass
class Door(ABC):
width: int
height: int

def area(self):
return self.width * self.height

@abstractmethod
def _cut_material(self):
raise NotImplementedError

@abstractmethod
def _install_components(self):
raise NotImplementedError

@abstractmethod
def open(self):
raise NotImplementedError


@dataclass
class IronDoor(Door):
def _cut_material(self):
print("Cutting iron sheets")

def _install_components(self):
print("Installing iron lock")

def open(self):
print("Opening iron door")


@dataclass
class WoodenDoor(Door):
def _cut_material(self):
print("Cutting raw timber")

def _install_components(self):
print("Installing wooden handle")

def open(self):
print("Opening wooden door")


class DoorFactory(ABC):
@abstractmethod
def make_door(self, width: int, height: int) -> Door:
raise NotImplementedError

def deliver_door(self, width: int, height: int) -> Door:
print("Manufacturing door")
door = self.make_door(width, height)
print("Testing door")
door.open()
return door


class IronDoorFactory(DoorFactory):
def make_door(self, width: int, height: int) -> IronDoor:
door = IronDoor(width, height)
door._cut_material()
door._install_components()
return door


class WoodenDoorFactory(DoorFactory):
def make_door(self, width: int, height: int) -> WoodenDoor:
door = WoodenDoor(width, height)
door._cut_material()
door._install_components()
return door


def main():
iron_factory = IronDoorFactory()
iron_door = iron_factory.deliver_door(100, 200)
print(f"Now we have an iron door with area {iron_door.area()}\n")
iron_door.open()

wooden_factory = WoodenDoorFactory()
wooden_door = wooden_factory.deliver_door(100, 200)
print(f"Now we have a wooden door with area {wooden_door.area()}")
wooden_door.open()


if __name__ == "__main__":
main()