Menu
CoddyTech

工厂模式

本课属于 Coddy Python 学习旅程的“面向对象编程”单元。第 46 课,共 64 课。

工厂模式可以在不指定对象具体类的情况下创建对象。你不直接调用构造函数,而是使用工厂方法来决定实例化哪个类。

以下是一些简单的产品类:

class Car:
    def __init__(self, brand):
        self.brand = brand
        self.type = "Car"
    
    def info(self):
        return f"{self.type}: {self.brand}"

class Bike:
    def __init__(self, brand):
        self.brand = brand
        self.type = "Bike"
    
    def info(self):
        return f"{self.type}: {self.brand}"

创建一个工厂类来生成这些对象:

class VehicleFactory:
    def create_vehicle(self, vehicle_type, brand):
        if vehicle_type == "car":
            return Car(brand)
        elif vehicle_type == "bike":
            return Bike(brand)
        else:
            raise ValueError(f"Unknown type: {vehicle_type}")

需要这些对象的代码称为客户端代码。它会向工厂请求对象,而不是直接调用构造函数:

factory = VehicleFactory()
my_car = factory.create_vehicle("car", "Toyota")
my_bike = factory.create_vehicle("bike", "Honda")

print(my_car.info())   # 汽车:Toyota
print(my_bike.info())  # 自行车:Honda

使用 *args 让工厂更加灵活:

class FlexibleFactory:
    def create_vehicle(self, vehicle_type, *args):
        if vehicle_type == "car":
            return Car(args[0])  # 只有品牌
        elif vehicle_type == "truck":
            return Truck(args[0], args[1])  # 品牌和载重能力
        else:
            raise ValueError(f"Unknown type: {vehicle_type}")

class Truck:
    def __init__(self, brand, capacity):
        self.brand = brand
        self.capacity = capacity
        self.type = "Truck"
    
    def info(self):
        return f"{self.type}: {self.brand} ({self.capacity}t)"

使用灵活工厂:

flexible = FlexibleFactory()
car = flexible.create_vehicle("car", "Ford")
truck = flexible.create_vehicle("truck", "Volvo", "20")

print(car.info())    # Car: Ford
print(truck.info())  # Truck: Volvo (20t)

输出:

Car: Toyota
Bike: Honda
Car: Ford
Truck: Volvo (20t)

要点:工厂模式让你无需知道对象的具体类,就能创建对象。工厂方法会根据参数决定实例化哪个类。使用 *args 来处理构造函数参数不同的产品。这样能让你的代码更加灵活,也更容易扩展新的产品类型。

challenge icon

挑战

中等

在这个挑战中,你将使用继承和多态,通过恰当的面向对象设计实现一个图形工厂系统。

请在以下文件中完成实现:

  • shape.py:基类 Shape
  • circle.py:Circle 的实现
  • rectangle.py:Rectangle 的实现
  • triangle.py:Triangle 的实现
  • shapefactory.py:用于创建图形的工厂类

每个文件都包含详细的 TODO 注释,用于指导你的实现。请仔细遵循这些注释,确保你的代码满足所有要求。

亲手试试

from shapefactory import ShapeFactory
from shape import Shape
from circle import Circle
from rectangle import Rectangle
from triangle import Triangle
import sys

# 测试用例执行器
test_case = input()

factory = ShapeFactory()

if test_case == "circle_area":
    circle = factory.create_shape("circle", 5)
    print(f"{circle.area():.2f}")

elif test_case == "rectangle_perimeter":
    rectangle = factory.create_shape("rectangle", 4, 6)
    print(f"{rectangle.perimeter()}")

elif test_case == "triangle_perimeter":
    triangle = factory.create_shape("triangle", 3, 4, 5)
    print(f"{triangle.perimeter()}")

elif test_case == "invalid_shape":
    try:
        factory.create_shape("hexagon", 6)
        print("No exception raised")
    except ValueError as e:
        print(str(e))

elif test_case == "case_insensitive":
    circle = factory.create_shape("CiRcLe", 3)
    print(f"{circle.area():.2f}")

elif test_case == "shape_inheritance":
    shapes = [
        factory.create_shape("circle", 2),
        factory.create_shape("rectangle", 2, 3),
        factory.create_shape("triangle", 3, 4, 5)
    ]
    all_shapes = all(isinstance(shape, Shape) for shape in shapes)
    print(all_shapes)

elif test_case == "zero_radius_circle":
    circle = factory.create_shape("circle", 0)
    print(f"{circle.area():.2f} {circle.perimeter():.2f}")

elif test_case == "negative_dimensions":
    rectangle = factory.create_shape("rectangle", -2, -3)
    print(f"{rectangle.area()}")

elif test_case == "large_values":
    circle = factory.create_shape("circle", 1000000)
    print(f"{circle.area():.2e}")

elif test_case == "polymorphism_test":
    shapes = [
        factory.create_shape("circle", 2),
        factory.create_shape("rectangle", 3, 4),
        factory.create_shape("triangle", 3, 4, 5)
    ]
    area_sum = sum(shape.area() for shape in shapes)
    perimeter_sum = sum(shape.perimeter() for shape in shapes)
    print(f"Area sum: {area_sum:.2f}, Perimeter sum: {perimeter_sum:.2f}")

elif test_case == "triangle_area":
    triangle = factory.create_shape("triangle", 3, 4, 5)
    print(f"{triangle.area():.2f}")

elif test_case == "method_override":
    circle = factory.create_shape("circle", 2)
    rectangle = factory.create_shape("rectangle", 3, 4)
    triangle = factory.create_shape("triangle", 3, 4, 5)
    
    # 获取方法对象,比较它们的实现
    circle_area = Circle.area
    rectangle_area = Rectangle.area
    triangle_area = Triangle.area
    
    circle_perimeter = Circle.perimeter
    rectangle_perimeter = Rectangle.perimeter
    triangle_perimeter = Triangle.perimeter
    
    # 检查所有实现是否各不相同
    unique_areas = len({circle_area, rectangle_area, triangle_area}) == 3
    unique_perimeters = len({circle_perimeter, rectangle_perimeter, triangle_perimeter}) == 3
    
    if unique_areas and unique_perimeters:
        print("All shapes correctly override methods")
    else:
        print("Some shapes share method implementations")
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Python 在线编译器