Menu
CoddyTech
flag Ar iconالعربيةdown icon

نمط 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())    # 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 عبر الإنترنت