Menu
Coddy logo textTech

תבנית 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

הפכו את המפעל לגמיש יותר באמצעות *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 - מחלקת מפעל ליצירת צורות

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