Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

نمط Factory

جزء من قسم Object Oriented Programming في رحلة Dart على Coddy — الدرس 91 من 110.

يقوم نمط المصنع (Factory pattern) بتفويض إنشاء الكائنات إلى طريقة (method) أو فئة (class) منفصلة، مما يتيح لك إنشاء كائنات دون تحديد فئتها الدقيقة. يختلف هذا عن منشئ المصنع (factory constructor) الذي تعلمته سابقًا - فنمط المصنع هو نهج تصميم حيث يتم توحيد منطق الإنشاء في مكان مركزي ويمكنه إرجاع أنواع مختلفة بناءً على المدخلات.

فكر في سيناريو تحتاج فيه إلى إنشاء أنواع مختلفة من الإشعارات. فبدلاً من أن يقرر العميل أي فئة (class) سيقوم بإنشائها، يتولى المصنع (factory) معالجة هذا القرار:

abstract class Notification {
  void send(String message);
}

class EmailNotification implements Notification {
  @override
  void send(String message) => print('Email: $message');
}

class SMSNotification implements Notification {
  @override
  void send(String message) => print('SMS: $message');
}

class NotificationFactory {
  static Notification create(String type) {
    switch (type) {
      case 'email':
        return EmailNotification();
      case 'sms':
        return SMSNotification();
      default:
        return EmailNotification();
    }
  }
}

void main() {
  var notification = NotificationFactory.create('sms');
  notification.send('Hello!');  // SMS: Hello!
}

كود العميل لا يحتاج إلى معرفة EmailNotification أو SMSNotification - فهو يطلب فقط من المصنع (factory) إشعاراً من نوع معين. هذا يجعل إضافة أنواع إشعارات جديدة أمراً سهلاً: فأنت تقوم فقط بتعديل المصنع، وليس كل مكان يتم فيه إنشاء الإشعارات.

استخدم نمط Factory عندما يتضمن إنشاء الكائنات منطقاً معقداً، أو عندما تريد إخفاء فئات التنفيذ عن العملاء، أو عندما يعتمد النوع المحدد المراد إنشاؤه على ظروف وقت التشغيل.

challenge icon

التحدي

سهل

لنقم ببناء مولد مستندات باستخدام نمط المصنع (Factory pattern)! ستقوم بإنشاء نظام ينتج أنواعاً مختلفة من المستندات (التقارير، الفواتير، والرسائل) من خلال مصنع مركزي، بحيث لا يحتاج كود العميل إلى معرفة فئات المستندات المحددة.

ستقوم بتنظيم الكود الخاص بك في ملفين:

  • document_factory.dart: أنشئ نظام المستندات الخاص بك هنا:
    • فئة مجردة (abstract class) باسم Document مع طريقة generate(String content) تعيد String
    • ثلاث فئات ملموسة (concrete classes) تقوم بتنفيذ Document:
      • Report - تعيد طريقة generate الخاصة بها === REPORT ===\n[content]\n=============
      • Invoice - تعيد طريقة generate الخاصة بها INVOICE\n--------\n[content]\nTotal Due
      • Letter - تعيد طريقة generate الخاصة بها Dear Reader,\n[content]\nSincerely
    • فئة DocumentFactory مع طريقة ثابتة (static method) باسم create(String type) تعيد كائن Document المناسب بناءً على سلسلة النوع: "report"، أو "invoice"، أو "letter". لأي نوع غير معروف، قم بإعادة Letter كافتراضي
  • main.dart: قم باستيراد مصنع المستندات الخاص بك ووضح كيف يقوم المصنع بإنشاء أنواع مستندات مختلفة دون حاجة العميل لمعرفة الفئات الملموسة:
    • استخدم المصنع لإنشاء تقرير واطبع نتيجة توليده بالمحتوى Sales increased by 25%
    • اطبع سطراً فارغاً
    • استخدم المصنع لإنشاء فاتورة واطبع نتيجة توليدها بالمحتوى Widget x3 - $150
    • اطبع سطراً فارغاً
    • استخدم المصنع لإنشاء رسالة واطبع نتيجة توليدها بالمحتوى Thank you for your order

لاحظ كيف يتفاعل ملفك الرئيسي فقط مع المصنع ونوع Document المجرد - فهو لا يقوم أبداً بإنشاء كائنات Report أو Invoice أو Letter بشكل مباشر!

المخرجات المتوقعة:

=== REPORT ===
Sales increased by 25%
=============

INVOICE
--------
Widget x3 - $150
Total Due

Dear Reader,
Thank you for your order
Sincerely

ورقة مرجعية

يقوم نمط المصنع (Factory pattern) بتفويض إنشاء الكائنات إلى طريقة أو فئة منفصلة، مما يسمح لك بإنشاء كائنات دون تحديد فئتها الدقيقة. يتم تمركز منطق الإنشاء ويمكنه إرجاع أنواع مختلفة بناءً على المدخلات.

الهيكل الأساسي لنمط المصنع:

abstract class Notification {
  void send(String message);
}

class EmailNotification implements Notification {
  @override
  void send(String message) => print('Email: $message');
}

class SMSNotification implements Notification {
  @override
  void send(String message) => print('SMS: $message');
}

class NotificationFactory {
  static Notification create(String type) {
    switch (type) {
      case 'email':
        return EmailNotification();
      case 'sms':
        return SMSNotification();
      default:
        return EmailNotification();
    }
  }
}

void main() {
  var notification = NotificationFactory.create('sms');
  notification.send('Hello!');  // SMS: Hello!
}

يتفاعل كود العميل فقط مع المصنع والنوع المجرد، وليس مع فئات التنفيذ الملموسة. وهذا يجعل إضافة أنواع جديدة أمراً سهلاً - حيث تقوم فقط بتعديل المصنع.

استخدم نمط المصنع عندما:

  • يتضمن إنشاء الكائن منطقاً معقداً
  • تريد إخفاء فئات التنفيذ عن العملاء
  • يعتمد النوع الدقيق المراد إنشاؤه على ظروف وقت التشغيل

جرّب بنفسك

import 'document_factory.dart';

void main() {
  // TODO: استخدم DocumentFactory.create() لإنشاء تقرير (report)
  // ثم اطبع نتيجة توليده بالمحتوى: "Sales increased by 25%"
  
  // TODO: اطبع سطرًا فارغًا
  
  // TODO: استخدم DocumentFactory.create() لإنشاء فاتورة (invoice)
  // ثم اطبع نتيجة توليده بالمحتوى: "Widget x3 - \$150"
  
  // TODO: اطبع سطرًا فارغًا
  
  // TODO: استخدم DocumentFactory.create() لإنشاء رسالة (letter)
  // ثم اطبع نتيجة توليده بالمحتوى: "Thank you for your order"
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming