نمط Factory
جزء من قسم Object Oriented Programming في رحلة Python على Coddy — الدرس 46 من 64.
يقوم نمط المصنع (Factory Pattern) بإنشاء الكائنات دون تحديد فئتها (class) الدقيقة. فبدلاً من استدعاء المنشئات (constructors) مباشرة، تستخدم طريقة مصنع (factory method) تقرر أي فئة سيتم إنشاؤها (instantiate).
إليك فئات منتجات بسيطة:
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}")استخدم المصنع بدلاً من استدعاء المنشئات (constructors) مباشرةً:
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]) # Just brand
elif vehicle_type == "truck":
return Truck(args[0], args[1]) # Brand and capacity
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)نقطة رئيسية: يتيح لك نمط المصنع (Factory Pattern) إنشاء كائنات دون معرفة فئتها (class) المحددة. تحدد طريقة المصنع (factory method) الفئة التي سيتم إنشاؤها بناءً على المعاملات (parameters). استخدم *args للتعامل مع المنتجات التي تحتوي على معاملات منشئ (constructor parameters) مختلفة. هذا يجعل الكود الخاص بك أكثر مرونة وأسهل في التوسع مع أنواع منتجات جديدة.
التحدي
متوسطفي هذا التحدي، ستقوم بتنفيذ نظام مصنع أشكال باستخدام تصميم كائني التوجه سليم مع الوراثة وتعدد الأشكال.
أكمل التنفيذ في الملفات التالية:
shape.py- فئة Shape الأساسيةcircle.py- تنفيذ Circlerectangle.py- تنفيذ Rectangletriangle.py- تنفيذ Triangleshapefactory.py- فئة Factory لإنشاء الأشكال
يحتوي كل ملف على تعليقات TODO مفصلة لتوجيهك في التنفيذ. اتبع هذه التعليقات بعناية للتأكد من أن الكود الخاص بك يلبي جميع المتطلبات.
ورقة مرجعية
يقوم نمط المصنع (Factory Pattern) بإنشاء الكائنات دون تحديد فئتها (class) الدقيقة. فبدلاً من استدعاء المنشئات (constructors) مباشرة، تستخدم طريقة مصنع (factory method) تقرر أي فئة سيتم إنشاؤها.
تنفيذ أساسي للمصنع:
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")مصنع مرن يستخدم *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}")
# الاستخدام
flexible = FlexibleFactory()
car = flexible.create_vehicle("car", "Ford")
truck = flexible.create_vehicle("truck", "Volvo", "20")الفوائد الرئيسية: يجعل نمط المصنع الكود أكثر مرونة وأسهل في التوسع مع أنواع منتجات جديدة دون تعديل كود العميل الحالي.
جرّب بنفسك
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")يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات OOP
الملفات الخارجيةمقدمة في OOPClasses مقابل Objectsمعامل selfMethodsAttributesدالة البناء (__init__)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسيةدالة ()superإعادة تعريف الدوال (Method Overriding)الوراثة المتعددةترتيب استدعاء الدوال (Method Resolution Order)مراجعة - هيكلية الموظفين5تعدد الأشكال
مراجعة إعادة تعريف الدوالمفهوم Duck Typingالأصناف والدوال المجردةتصميم الواجهاتملخص - حاسبة الأشكال