Menu
CoddyTech

תבנית Factory

חלק מהיחידה תכנות מונחה עצמים במסלול ה-Python של Coddy. שיעור 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

הפכו את ה־factory לגמיש יותר באמצעות *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())    # מכונית: Ford
print(truck.info())  # משאית: 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 - מחלקת Factory ליצירת צורות

כל קובץ מכיל הערות 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 אונליין