Mẫu Factory
Thuộc phần Lập trình hướng đối tượng trong hành trình Python của Coddy. Bài học 46 trên 64.
Mẫu Factory (Factory Pattern) tạo đối tượng (object) mà không cần chỉ định lớp (class) cụ thể. Thay vì gọi trực tiếp các hàm khởi tạo (constructor), bạn dùng phương thức factory (factory method) để quyết định cần khởi tạo lớp nào.
Đây là các lớp sản phẩm đơn giản:
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}"Tạo một lớp factory để tạo ra các đối tượng này:
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}")Code cần các đối tượng được gọi là code phía client. Code này yêu cầu factory thay vì gọi trực tiếp các hàm khởi tạo:
factory = VehicleFactory()
my_car = factory.create_vehicle("car", "Toyota")
my_bike = factory.create_vehicle("bike", "Honda")
print(my_car.info()) # Ô tô: Toyota
print(my_bike.info()) # Xe máy: HondaLàm cho factory linh hoạt hơn bằng cách dùng *args:
class FlexibleFactory:
def create_vehicle(self, vehicle_type, *args):
if vehicle_type == "car":
return Car(args[0]) # Chỉ có thương hiệu
elif vehicle_type == "truck":
return Truck(args[0], args[1]) # Thương hiệu và tải trọng
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)"Sử dụng nhà máy linh hoạt:
flexible = FlexibleFactory()
car = flexible.create_vehicle("car", "Ford")
truck = flexible.create_vehicle("truck", "Volvo", "20")
print(car.info()) # Xe con: Ford
print(truck.info()) # Xe tải: Volvo (20t)Đầu ra:
Car: Toyota
Bike: Honda
Car: Ford
Truck: Volvo (20t)Điểm chính: Mẫu nhà máy cho phép bạn tạo đối tượng mà không cần biết chính xác lớp của chúng. Phương thức nhà máy quyết định sẽ khởi tạo lớp nào dựa trên các tham số. Dùng *args để xử lý các sản phẩm có tham số hàm khởi tạo khác nhau. Nhờ vậy, code của bạn linh hoạt hơn và dễ mở rộng với các loại sản phẩm mới.
Thử thách
Trung bìnhTrong thử thách này, bạn sẽ triển khai một hệ thống factory hình dạng bằng cách áp dụng thiết kế hướng đối tượng phù hợp với kế thừa và đa hình.
Hoàn thành phần triển khai trong các tệp sau:
shape.py- Lớp Shape cơ sởcircle.py- Phần triển khai Circlerectangle.py- Phần triển khai Rectangletriangle.py- Phần triển khai Triangleshapefactory.py- Lớp factory để tạo hình dạng
Mỗi tệp đều có các chú thích TODO chi tiết để hướng dẫn bạn triển khai. Hãy đọc kỹ các chú thích này để đảm bảo code đáp ứng mọi yêu cầu.
Tự làm thử
from shapefactory import ShapeFactory
from shape import Shape
from circle import Circle
from rectangle import Rectangle
from triangle import Triangle
import sys
# Chạy test case
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)
# Lấy các đối tượng phương thức (method) để so sánh cách triển khai
circle_area = Circle.area
rectangle_area = Rectangle.area
triangle_area = Triangle.area
circle_perimeter = Circle.perimeter
rectangle_perimeter = Rectangle.perimeter
triangle_perimeter = Triangle.perimeter
# Kiểm tra xem mỗi cách triển khai có khác nhau không
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")Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Nền tảng về lập trình hướng đối tượng
Tệp bên ngoàiGiới thiệu về lập trình hướng đối tượngLớp và đối tượngTham số selfPhương thứcThuộc tínhPhương thức khởi tạo (__init__)Ôn tập: máy tính đơn giản4Kế thừa
Kế thừa cơ bảnHàm super()Ghi đè phương thứcKế thừa đa lớpThứ tự phân giải phương thứcÔn tập: hệ thống phân cấp nhân viên2Decorator
Giới thiệu về decoratorDecorator thuộc tínhDecorator phương thức tĩnhDecorator phương thức lớp5Tính đa hình
Xem lại cách ghi đè phương thứcKiểu gõ vịtLớp và phương thức trừu tượngThiết kế giao diệnÔn tập: máy tính hình học8Các khái niệm OOP nâng cao
Kết hợp và kế thừaMixinPhương thức tĩnh và phương thức lớpDecorator lớpTrình quản lý ngữ cảnhTự luyện tập: Trình biên dịch Python online