مقارنة المصانع.
توضح هذه المقالة الفرق بين:
- المصنع (Factory)
- دالة الإنشاء (Creation method)
- دالة الإنشاء الساكنة (Static creation method) أو (static factory method)
- المصنع البسيط (Simple factory)
- نمط دالة المصنع (Factory Method)
- نمط المصنع المجرد (Abstract Factory)
يمكنك العثور على مراجع لهذه المصطلحات في جميع أنحاء الويب. على الرغم من أنها قد تبدو متشابهة، إلا أن لكل منها معنى مختلفاً. ولا يدرك الكثير من الناس ذلك، مما يؤدي إلى الارتباك وسوء الفهم.
لذا دعونا نحاول معرفة الفرق وحل هذه المشكلة مرة واحدة وإلى الأبد.
1. المصنع (Factory)
المصنع (Factory) هو مصطلح غامض يرمز إلى وظيفة أو دالة أو فئة من المفترض أن تنتج شيئاً ما. والأكثر شيوعاً هو أن المصانع تنتج كائنات. ولكنها قد تنتج أيضاً ملفات، أو سجلات في قواعد البيانات، وما إلى ذلك.
على سبيل المثال، يمكن الإشارة عفوياً إلى أي من هذه الأشياء على أنها “مصنع”:
- وظيفة أو دالة تقوم بإنشاء واجهة المستخدم الرسومية (GUI) للبرنامج.
- فئة تقوم بإنشاء مستخدمين.
- دالة ساكنة تستدعي منشئ الفئة (constructor) بطريقة معينة.
- أحد أنماط التصميم الإنشائية (creational design patterns).
عادةً، عندما يقول شخص ما كلمة “مصنع”، فمن المفترض أن يكون المعنى الدقيق واضحاً من السياق. ولكن إذا كان لديك شك، فما عليك سوى الاستفسار. فهناك احتمال أن يكون الكاتب نفسه غير مدرك للفارق.
2. دالة الإنشاء (Creation method)
تُعرّف دالة الإنشاء (Creation method) في كتاب Refactoring To Patterns بأنها “الدالة التي تقوم بإنشاء الكائنات”. هذا يعني أن كل نتيجة لنمط دالة المصنع هي “دالة إنشاء” ولكن العكس ليس صحيحاً بالضرورة. ويعني هذا أيضاً أنه يمكنك استبدال مصطلح “دالة الإنشاء” بأي مكان يستخدم فيه مارتن فاولر مصطلح “دالة المصنع (factory method)” في كتاب Refactoring وحيثما يستخدم جوشوا بلوخ مصطلح “دالة المصنع الساكنة (static factory method)” في كتاب Effective Java.
في الواقع، دالة الإنشاء هي مجرد غلاف حول استدعاء المنشئ (constructor). وقد يكون لها اسم يعبر بشكل أفضل عن نواياك. من ناحية أخرى، قد تساعد في عزل الكود الخاص بك عن التغييرات التي تطرأ على المنشئ. ويمكن أن تحتوي حتى على منطق معين يعيد الكائنات الموجودة بالفعل بدلاً من إنشاء كائنات جديدة.
يسمي الكثير من الأشخاص مثل هذه الدوال بـ “دالة المصنع” لمجرد أنها تنتج كائنات جديدة: المنطق هنا مباشر؛ الدالة تنشئ كائنات وبما أن جميع المصانع تنشئ كائنات، فيجب أن تكون هذه الدالة بوضوح دالة مصنع. وبطبيعة الحال، هناك الكثير من الارتباك عندما يتعلق الأمر بنمط دالة المصنع (Factory Method) الحقيقي.
في المثال التالي، تعتبر next دالة إنشاء:
class Number {
private $value;
public function __construct($value) {
$this->value = $value;
}
public function next() {
return new Number ($this->value + 1);
}
}
3. دالة الإنشاء الساكنة (Static creation method)
Static creation method هي دالة إنشاء يتم التصريح عنها كـ static. وعبارة أخرى، يمكن استدعاؤها مباشرة على الفئة (class) ولا تتطلب إنشاء كائن منها.
لا ترتبك عندما يسمي شخص ما مثل هذه الدوال بـ “دالة المصنع الساكنة (static factory method)”. هذه مجرد عادة سيئة. فنمط دالة المصنع (Factory Method) هو نمط تصميم يعتمد على الوراثة (inheritance). وإذا جعلته static، فلن تتمكن بعد الآن من توسيعه في الفئات الفرعية (subclasses)، وهو ما يتعارض مع الغرض من النمط.
عندما تعيد دالة الإنشاء الساكنة كائنات جديدة، فإنها تصبح منشئاً بديلاً (alternative constructor).
قد تكون مفيدة عندما:
-
تحتاج إلى وجود عدة منشئات (constructors) مختلفة لأغراض مختلفة ولكن تواقيعها (signatures) متطابقة. على سبيل المثال، وجود كل من
Random(int max)وRandom(int min)أمر مستحيل في Java و C++ و C# والعديد من اللغات الأخرى. والحل الأكثر شيوعاً هو إنشاء عدة دوال ساكنة تستدعي المنشئ الافتراضي وتعيين القيم المناسبة بعد ذلك. -
تريد إعادة استخدام كائنات موجودة بالفعل، بدلاً من إنشاء كائنات جديدة (انظر نمط المفرد (Singleton)). يجب على المنشئات في معظم لغات البرمجة إرجاع نسخ كائنات (instances) جديدة. دالة الإنشاء الساكنة هي حل بديل لهذا القيد. داخل الدالة الساكنة، يمكن للكود الخاص بك تحديد ما إذا كان سيتم إنشاء نسخة جديدة عن طريق استدعاء المنشئ أو إرجاع كائن موجود بالفعل من ذاكرة تخزين مؤقت (cache) ما.
في المثال التالي، تعتبر الدالة load دالة إنشاء ساكنة. فهي توفر طريقة ملائمة لاسترجاع المستخدمين من قاعدة البيانات.
class User {
private $id, $name, $email, $phone;
public function __construct($id, $name, $email, $phone) {
$this->id = $id;
$this->name = $name;
$this->email = $email;
$this->phone = $phone;
}
public static function load($id) {
list($id, $name, $email, $phone) = DB::load_data('users', 'id', 'name', 'email', 'phone');
$user = new User($id, $name, $email, $phone);
return $user;
}
}
4. نمط المصنع البسيط (Simple factory)
يصف نمط المصنع البسيط (Simple factory) فئة تحتوي على دالة إنشاء واحدة مع جملة شرطية كبيرة تختار الفئة التي سيتم إنشاء نسخة منها وإرجاعها بناءً على معاملات الدالة.
يخلط الناس عادةً بين المصانع البسيطة وبين المصانع العامة أو أحد أنماط التصميم الإنشائية. في معظم الحالات، يعتبر المصنع البسيط خطوة وسيطة لتقديم نمط دالة المصنع (Factory Method) أو نمط المصنع المجرد (Abstract Factory).
يتم تمثيل المصنع البسيط عادةً بدالة واحدة في فئة واحدة. بمرور الوقت، قد تصبح هذه الدالة كبيرة جداً، لذا قد تقرر استخراج أجزاء منها إلى فئات فرعية. وبمجرد القيام بذلك عدة مرات، قد تكتشف أن الأمر برمته تحول إلى نمط دالة المصنع الكلاسيكي.
بالمناسبة، إذا قمت بالتصريح عن مصنع بسيط على أنه abstract، فلن يتحول هذا سحرياً إلى نمط المصنع المجرد.
فيما يلي مثال على المصنع البسيط:
class UserFactory {
public static function create($type) {
switch ($type) {
case 'user': return new User();
case 'customer': return new Customer();
case 'admin': return new Admin();
default:
throw new Exception('Wrong user type passed.');
}
}
}
5. نمط دالة المصنع (Factory Method)
نمط دالة المصنع (Factory Method) هو نمط تصميم إنشائي يوفر واجهة لإنشاء الكائنات ولكنه يسمح للفئات الفرعية بتعديل نوع الكائن الذي سيتم إنشاؤه.
إذا كان لديك دالة إنشاء في الفئة الأساسية (base class) وفئات فرعية تقوم بتوسيعها، فمن المحتمل أنك تبحث في نمط دالة المصنع.
abstract class Department {
public abstract function createEmployee($id);
public function fire($id) {
$employee = $this->createEmployee($id);
$employee->paySalary();
$employee->dismiss();
}
}
class ITDepartment extends Department {
public function createEmployee($id) {
return new Programmer($id);
}
}
class AccountingDepartment extends Department {
public function createEmployee($id) {
return new Accountant($id);
}
}
6. نمط المصنع المجرد (Abstract Factory)
نمط المصنع المجرد (Abstract Factory) هو نمط تصميم إنشائي يسمح بإنتاج عائلات من الكائنات المرتبطة أو المعتمدة على بعضها البعض دون تحديد فئاتها الملموسة (concrete classes).
ما هي “عائلات الكائنات”؟ على سبيل المثال، خذ مجموعة الفئات هذه: Transport + Engine + Controls. قد يكون هناك عدة أشكال مختلفة لهذه:
Car+CombustionEngine+SteeringWheelPlane+JetEngine+Yoke
إذا كان برنامجك لا يتعامل مع عائلات المنتجات، فلن تحتاج إلى مصنع مجرد.
ومرة أخرى، يخلط الكثير من الناس بين نمط المصنع المجرد وفئة المصنع البسيط المصرح عنها كـ abstract. لا تفعل ذلك!
خاتمة
الآن بعد أن عرفت الفرق، ألقِ نظرة جديدة على أنماط التصميم: