المحتوى عن 'design pattern'.



مزيد من الخيارات

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المُحتوى


التصنيفات

  • التخطيط وسير العمل
  • التمويل
  • فريق العمل
  • دراسة حالات
  • نصائح وإرشادات
  • التعامل مع العملاء
  • التعهيد الخارجي
  • التجارة الإلكترونية
  • مقالات ريادة أعمال عامة

التصنيفات

  • PHP
    • Laravel
    • ووردبريس
  • جافاسكريبت
    • Node.js
    • jQuery
    • AngularJS
    • Cordova
  • HTML5
  • CSS
    • Sass
    • إطار عمل Bootstrap
  • SQL
  • سي شارب #C
    • منصة Xamarin
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • برمجة أندرويد
  • لغة Swift
  • لغة R
  • لغة TypeScript
  • سير العمل
    • Git
  • صناعة الألعاب
    • Unity3D
  • مقالات برمجة عامة

التصنيفات

  • تجربة المستخدم
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
    • كوريل درو
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • مقالات تصميم عامة

التصنيفات

  • خواديم
    • الويب HTTP
    • قواعد البيانات
    • البريد الإلكتروني
    • DNS
    • Samba
  • الحوسبة السّحابية
    • Docker
  • إدارة الإعدادات والنّشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • مقالات DevOps عامة

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • استسراع النمو
  • المبيعات

التصنيفات

  • إدارة مالية
  • الإنتاجية
  • تجارب
  • مشاريع جانبية
  • التعامل مع العملاء
  • الحفاظ على الصحة
  • التسويق الذاتي
  • مقالات عمل حر عامة

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
  • أندرويد
  • iOS
  • macOS
  • ويندوز

التصنيفات

  • شهادات سيسكو
    • CCNA
  • شهادات مايكروسوفت
  • شهادات Amazon Web Services
  • شهادات ريدهات
    • RHCSA
  • شهادات CompTIA
  • مقالات عامة

أسئلة وأجوبة

  • الأقسام
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة البرمجة
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات
    • أسئلة الشهادات المتخصصة

التصنيفات

  • ريادة الأعمال
  • العمل الحر
  • التسويق والمبيعات
  • البرمجة
  • التصميم
  • DevOps

تمّ العثور على 7 نتائج

  1. يهدف نمط التصميم معمل التجريد Abstract Factory إلى توفير واجهة Interface لإنشاء مجموعة من الكائنات المرتبطة أو المنفصلة دون الحاجة إلى التعامل مع أصنافها الفعليّة. كما يوفّر هرمية Hierarchy تغلّف الكثير من المنصات Platforms المحتملة، وتعمل على بناء مجموعة من “المنتجات”. ينطلق نمط التصميم هذا من مبدأ أن العامل new مؤذٍ وينبغي التقليل من استخدامه. ملاحظة: نعني بالتغليف Encapsulation في إطار البرمجة كائنيّة التوجه Object-oriented programming تلك الآليّة التي تتيح جمع البيانات (الخاصيّات Attributes) والإجراءات المطبّقة عليها (التوابع Methods) ضمن نفس الكائن، مع تقييد إمكانيّة وصول الكائنات الأخرى إلى عناصر الكائن. المشكلة إذا توجب على التطبيق Application أن يكون محمولا Portable، فلا بد من تغليف اعتمادات المنصات Platform dependencies التي يُراد له أن يعمل عليها. قد تتضمن هذه الاعتمادات نظام النوافذ، نظام التشغيل، قاعدة البيانات وغيرها. في كثير من الأحيان لا يُصمَّم التغليف مسبقا لأخذ الاعتمادات بالحسبان، فتبدأ عبارات الاختبار (if.. else) مع خيارات لجميع المنصات الحالية المدعومة، بالتكاثر كالأرانب داخل الشفرة البرمجية. المناقشة يوفّر نمط التصميم معمل التجريد Abstract Factory مستوى من المراوغة يجرّد Abstract عمليّة إنشاء أصناف من الكائنات، المرتبطة أو المنفصلة؛ وبالتالي لا يحدّد طريقة التنفيذ الفعليّة للأصناف محلّ التساؤل. المعمل؛ أي كائن من صنف Factory؛ هو - حسب هذا النمط - خادم يوفّر خدمات إنشاء الأصناف التي نريد تجريدها - اعتمادات المنصات مثلا - لبقيّة الكائنات التي تلعب دور العميل. لا يمكن للعملاء بأي حال من اﻷحوال إنشاء الأصناف المقصودة بأنفسهم، بل يطلبون من المعمل فعل ذلك، عن طريق توابع مناسبة. تسهّل هذه الآلية تبديل مجموعات المنتجات، لأن الصنف المحدد في كائن المعمل يظهر مرة واحدة فقط في التطبيق، وذلك في المكان الذي استهل Instantiated فيه. يمكن للتطبيق ببساطة أن يبادل بين مجموعة كاملة من المنتجات عن طريق استهلال صنف فعليّ آخر من المعمل. وبما أن الخدمة التي يقدمها كائن المعمل واسعة الانتشار، فإنها تُنفَّذ عادة باستخدام النمط المفرد The Singleton pattern. ملاحظة: يحيل مفهوم التجريد Abstraction في هندسة البرمجيّات إلى الآليّة التي يُتخلَّص بموجبها من تعقيدات نظام مّا بتحديد مستوى من التعقيد لا يتجاوزه من يتفاعل مع النظام، ممّا يعني أنه يحذف التفاصيل الأكثر تعقيدا. يعتمد التجريد على استخلاص العناصر الرئيسية المطلوبة لحل المُشكلة والتركيز على هذه العناصر فقط وإهمال كافة التفاصيل الأخرى. الهيكلية يعرّف معمل التجريد تابعا Method لكل صنف منتَج. يغلّف كل تابع العامل new والصنف الفعلي المحدد للمنصّة؛ ثم بعد ذلك، تتم نمذجة كل “منصة” بصنف مشتق Derived class من المعمل. مثال إن الهدف من نموذج معمل التجريد هو توفير واجهة لإنشاء مجموعات من الكائنات المرتبطة دون تحديد أصنافها الفعلية. يوجد مثال على هذا النمط في طبع الصفائح المعدنية المستخدمة في صناعة المركبات اليابانية. تعدّ معدات الطبع هذه معمل تجريد، حيث تنشئ أجزاء المركبة الآلية. تُستخدم الآلة نفسها في طبع الأبواب اليمنى واليسرى، المصدات الأمامية اليمنى، اليسرى وغطاء المحرك وغيرها، وذلك من أجل نماذج مختلفة من السيارات. تُستخدم آلات نقل (التوابع) في تغيير قوالب الطبع وإنتاج نوعيّة جديدة من المعدّات (أصناف فعلية). يوفّر معمل التجريد StampingEquipment في مخطَّط الأصناف التالي تابعًا stampPart لكلّ مجموعة منتجات (stampWheelمثلا للعجلات Wheels وstampDoor للأبواب Doors). تستدعي الكائنات العميلة Clients (بقيّة أجزاء التطبيق) التابع المناسب لمجموعة المنتجات التي تريدها، مع تحديد نوعيّة (صنف) النموذج الذي تريد إنشاء كائن منه. يتضمّن التابع stampPart العامل new الذي ينشئ نموذجا جديدا باستدعاء الصنف الفعلي من بين مجموعات الأصناف ModelXHood، ModelXWheels وModelXDoor (حيث X عدد يمثل معرّف نموذج من المنتجات). نحصُل من العملية السابقة على كائن من معمل التجريد StampingEquipment لكنّه يحمل خواصّ المنتج الذي نريده، ولا يتبقّى لنا للحصول على المنتج سوى استدعاء التابع المناسب: stampHood، stampWheel أو stampDoor. إن استدعينا مثلا التابع اstampWhee في معمل التجريد StampingEquipment مع تحديد الصنف Model1Wheels (النموذج رقم 1 من العجلات) فسنحصُل على كائن من الصنف StampingEquipment لديه تابع stampWheel يؤدّي استدعاءه إلى الحصول على كائن من الصنف Model1Wheels. إن أردنا الآن عجلات من النموذج رقم 2 فكلّ ما علينا فعله هو اتباع نفس الطريقة ولكن مع تحديد Model2Wheels بدلا من Model1Wheels عند استدعاء اstampWhee في معمل التجريد. نفس الشيء ينطبق على الكائنات الأخرى، مع تغيير اسم التابع في معمل التجريد حسب مجموعة الأصناف (stampHood بالنسبة لنماذج اﻷغطية ModelXHood، وstampDoor بالنسبة لنماذج الأبواب ModelXDoor). لاحظ أنه بهذه الطريقة لن نحتاج لاستهلال الصنف StampingEquipment (إنشاء كائن منه) سوى مرة واحدة، ثم نستدعي بعدها التوابع المناسبة لنوعيّة المنتجات التي نريد. أي أن العميل هنا يعمل في مستوى من التعقيد أقلّ بكثير ممّا كان سيعمل عليه لو أنه تولّى بنفسه استهلال الأصناف الفعليّة (ModelXHood، ModelXWheels وModelXDoor) وما قد يترتّب عن ذلك من تعريف للخاصيّات والتوابع وكيفية عملها وغيرها من التفاصيل. قائمة التدقيق ينبغي - قبل اللجوء إلى نمط التصميم معمل التجريد التأكّد من حاجتك إليه عمليًّا وذلك بـ: تقرير ما إذا كانت اعتمادات المنصة وخدمات الإنشاء هي المصدر الحالي للمشكلة. إعداد مصفوفة “منصات” مقابل “منتجات”. تأكّد عند استخدام هذا النمط من: تعريف واجهة للمعمل تتكّون من تابع معمل لكل “منتج”. تعريف صنف مشتق من المعمل لكل منصة لتغليف كافة استدعاءات العامل new. حذف جميع استدعاءات العامل new من الصنف العميل وجعله يستخدم توابع المعمل في إنشاء الكائنات للمنتَج. ترجمة - بتصرّف - للمقال Abstract Factory Design Pattern لأصحابه Alexander Shvets, Gerhard Frey, Marina Pavlova. حقوق الصورة البارزة محفوظة لـ Freepik
  2. يُعرَف نمط التصميم Design Pattern في هندسة البرمجيات بأنه حل عام قابل للتكرار لمشكلة متكررة الحدوث في تصميم البرمجيات. نمط التصميم ليس نموذجا نهائيا يمكن تحويله إلى تعليمات برمجية مباشرة؛ بل هو توصيف أو قالب لكيفية حل المشكلة، يمكن استخدامه في العديد من الحالات المختلفة. استخدام أنماط التصميم يمكن لأنماط التصميم أن تسرّع عملية التطوير عن طريق توفير تصوّرات Paradigms أثبتت جدواها بعد اختبارها مرات كثيرة. يتطلب التصميم البرمجي الفعال أن نأخذ بعين الاعتبار المشاكل التي قد لا تظهر إلا لاحقا عند التنفيذ. تساعد إعادة استخدام أنماط التصميم في منع الأمور الدقيقة من التسبب بمشاكل كبيرة، كما تحسّن من القدرة على قراءة التعليمات البرمجية للمبرمجين والمعماريين Architects الذين هم على دراية بهذه الأنماط. يدرك الناس، في كثير من الأحيان، كيفية تطبيق تقنيات تصميم معينة لحل مشاكل بعينها فقط. لكن هذه التقنيات تكون صعبة التطبيق على نطاق أوسع من المشاكل. توفر أنماط التصميم حلولا عامة موثقة في تنسيق، لا يتطلب تفاصيل مرتبطة بمشكلة معينة. بالإضافة لذلك، تسمح هذه الأنماط للمطورين بالتواصل باستخدام أسماء معروفة ومفهومة جيدا للتفاعلات البرمجيّة software interactions. يمكن تحسين أنماط التصميم الشائعة مع مرور الوقت، الأمر الذي يجعلها أكثر قوة من التصاميم المخصصة. أنماط التصميم الإنشائية Creational design patterns تعنى نماذج التصميم هذه باستهلال الأصناف Class instantiation. يمكن تقسيم هذه النوعيّة من النماذج إلى فئتيْن: نماذج لإنشاء الأصناف ونماذج لإنشاء الكائنات. في حين تستخدم نماذج إنشاء الفئات التوريث Inheritance بفعالية في عملية التكوين، فإن نماذج إنشاء الكائنات تستخدم التفويض Delegation بفعالية لإنجاز العمل. من أمثلة أنماط التصميم الإنشائية: نمط معمل التجريد Abstract Factory: يخلق عينة Instance لعدة عائلات من الأصناف. نمط الباني Builder: يقوم بفصل عملية بناء الكائن Object Construction عن عملية تمثيله Representation. نمط طريقة المعمل Factory Method: يخلق عينة لعدة أصناف مشتقة Derived classes. أنماط التصميم الهيكلية Structural design patterns تعنى أنماط التصميم هذه بتركيب Composition الكائنات والأصناف. تستخدم الأنماطُ الهيكليّة لإنشاء الأصناف التوريثَ Inheritance لتركيب واجهات Interfaces، أما الأنماطُ الهيكليّة لإنشاء الكائنات فتعرّف طرقا لتكوين الكائنات بهدف الحصول على وظائف جديدة. من أمثلة هذه الأنماط: نمط المحول Adapter: يربط الواجهات Interfaces بأصناف مختلفة. نمط الجسر Bridge: يفصل واجهة الكائن عن تطبيقه Implementation. نمط المظهر Facade: صنف مفرد يمثل نظاما فرعيا Subsystem كاملا. نمط بيانات الصنف الخاصة Private Class Data: يقيد وصول المسترجعات Accessors والمعدّلات Mutators إلى خاصيّات الصنف. أنماط التصميم السلوكية Behavioral design patterns تعنى أنماط التصميم هذه بالتواصل Communication بين كائنات الأصناف. النماذج السلوكية هي تلك النماذج التي تهتم على وجه الخصوص بالتواصل بين الكائنات، ومن بينها: نمط سلسلة المسؤوليات Chain of Responsibility: طريقة لتمرير الطلب Request بين سلسلة من الكائنات. نمط السيطرة Command: يقوم بتغليف Encapsulate الطلب على هيئة كائن. نمط المفسّر Interpreter: طريقة لتضمين عناصر اللغة في البرنامج. نمط المكرّر Iterator: يؤمن وصولا تسلسليا للعناصر في مجموعة ما. نموذج الوسيط Mediator النقد انتقد بعض العاملين في مجال علوم الحاسب مفهوم أنماط التصميم وأبدوا اعتراضاتٍ عليه نجملها في ما يلي. يستهدف المشكلة الخاطئة تظهر الحاجة إلى الأنماط عند استخدام لغات البرمجة أو التقنيات التي لا تملك قدرة تجريد Abstraction كافية. في الحالة المثالية، لا ينبغي نسخ مفهوم ما بل تجدر الإشارة إليه. ولكن عند الإشارة إلى شيء ما بدل نسخه فلن يكون هناك نمط لتسميته أو الدلالة عليه، وهذا ما كتبه بول غراهام Paul Graham في مقال بعنوان “انتقام المهووسين Revenge of the Nerds “. يقدم بيتر نورفيغ Peter Norvig نقاشا مشابها، حيث يوضح أن 16 نمطا من أصل 23 في كتاب أنماط التصميم (الذي يركز بشكل أساسي على ++C ) بُسِّطت أو ألغيت (عن طريق دعم اللغة المباشر لها) في كل من لغتي Lisp و Dylan. يفتقر إلى الأسس الرسمية لقد كانت دراسة أنماط التصميم متخصّصة جدا، وقد جادل البعض في الحاجة الملحة لوضع هذا المفهوم في إطار أكثر رسمية. في مؤتمر OOPSLA (البرمجة كائنيّة التوجّه: الأنظمة، اللغات والتطبيقات) عام 1999، خضعت عصابة الأربعة Gang of Four (بتعاونهم الكامل) إلى محاكمة علنية، اتهموا فيها بعدة جرائم تمس علوم الحاسب. وقد تمت إدانتهم من قبل ثلثي المحلفين الذين حضروا المحاكمة. ملحوظة: غالبا ما يُشار إلى مؤلّفي كتاب Design Patterns: Elements of Reusable Object-Oriented Software (أنماط التصميم: مكوّنات من البرامج كائنيّة التوجّه القابلة لإعادة الاستخدام) الذي روّج لأنماط التصميم، غالبا ما يُشار إليهم باسم “عصابة الأربعة”. يقود إلى حلول غير فعالة إن فكرة نمط التصميم ما هي إلا محاولة لتقييس Standardize ما يعتبر سلفا مقبولا كأفضل ممارسة. قد يبدو هذا الأمر مفيدا من الجانب النظري، لكنه في الجانب العملي غالبا ما يؤدي إلى تكرار غير ضروري للتعليمات البرمجية. وبالتالي يكون الحل الأكثر فعالية هو استخدام تطبيق مصمم جيدا عوضا عن نمط تصميم بالكاد يعتبر جيدا. لا يختلف كثيرا عن التجريدات الأخرى يزعم بعض المؤلفين أن أنماط التصميم لا تختلف كثيرا عن أشكال التجريد الأخرى، وبأن استخدام مصطلح جديد (استعير من مجتمع العمارة) لوصف ظاهرة موجودة سابقا في مجال البرمجة يعتبر أمرا غير ضروري. تعدّ بنية بنية MVC ( “نموذج – عرض – متحكم”، “Model – View – Controller”) مثالا عن “نمط” يسبق مفهوم أنماط التصميم بعدة سنوات. ويجادل البعض بأن أول مساهمة في مجتمع أنماط التصميم (وكتاب عصابة الأربعة) هو استخدام كتاب A pattern language (لغة نمط) طريقةً للتوثيق Documentation؛ وهي ممارسة غالبا ما يتجاهلها المختصّون عند عرضهم لأصول مفهوم أنماط التصميم. ترجمة - بتصرّف - لمقال Design Patterns لأصحابه Alexander Shvets, Gerhard Frey, Marina Pavlova. حقوق الصورة البارزة محفوظة لـ Freepik
  3. يمكن لنمط التصميم البرمجي مجمع الكائنات Object pool أن يؤمّن دَفعة كبيرة للأداء ، ويكون أكثر فعالية في الحالات التي تكون فيها كلفة بدء عينة من الصنف Class instance مرتفعة، أو ترتفع فيها نسبة استهلال الأصناف مع انخفاض عدد العيّنات المستخدمة في آن واحد. المشكلة تستخدم مجمعات الكائنات (والتي تعرف أيضا باسم مجمعات المصادر Resources pools) لإدارة تخبئة الكائنات Object caching. يستطيع العميل الذي يملك وصولا إلى مجمع الكائنات أن يتجنب إنشاء كائنات جديدة بسؤال المجمع عوضا عن ذلك عن كائن سبق استهلاله. ينشئ المجمع كائنات جديدة إذا كان فارغًا وينمو حجمُه، إلّا أنه من الممكن تقييد عدد الكائنات المُنشَأة. يُفضَّل أن توضَع جميع الكائنات التي تمكن إعادة استخدامها Reusable objects، غير المستخدمة حاليًّا؛ ضمن مجمع الكائنات نفسه، حتى يصبح بالإمكان إدارتها بطريقة متناسقة. يُتوَصَّل إلى هذا الغرض باستخدام نمط الصنف المنفرد Singleton لتصميم الصنف القابل لإعادة الاستخدام. المناقشة يسمح مجمع الكائنات للعميل بـ”استعارة” الكائنات الموجودة فيه. يعيد العملاء الكائنات بعد استخدامها إلى المجمع، الذي يمكنه بعد ذلك إعارتها لعميل آخر ليستخدمها بدوره. إلا أننا لا نريد أن ينتظر عميلٌ إعادةَ كائن مستخدَم، فهذا مخالف للرغبة في تحسين اﻷداء؛ لذا فإن مجمع الكائنات يمكنه أن يستهل كائنات جديدة عندما تظهر الحاجة إليها، لكنْ يجب عليه أيضا أن يستخدم وسيلة لتنظيف الكائنات غير المستخدمة دوريّا. الهيكلية يقوم المبدأ العامّ لنمط مجمع الكائنات على أنه عند وجود عيّنات من صنف مّا، قابلة لإعادة الاستخدام فإنه من الأفضل تفادي إنشاء كائنات جديدة واستخدام العيّنات الموجودة. تظهر في المخطّط التالي ثلاثةُ أصناف: الصّنف Reusable: تتعاون الكائنات من هذا الصّنف مع بقيّة الكائنات (الكائنات العميلة المذكورة أدناه) لمدّة محدودة، تصبح بعدها كائنات الصّنف Reusable غير ضروريّة لعمل العملاء. الصّنف Client: تستخدم الكائنات التي تلعب دور العميل عيّنات من الكائنات القابلة لإعادة الاستخدام +(أي كائنات الصّنف Reusable المذكور في النقطة اﻷولى). الصّنف ReusablePool: تُدير الكائنات من هذا الصنف كائناتٍ قابلةً لإعادة الاستخدام (دور الصّنف Reusable) وتوفّرها للكائنات العميل +(الصّنف Client). ينبغي الانتباه هنا إلى أن الأصناف المذكورة أعلاه تمثّل أدوارا Roles، إذ يمكن أن يوجد أكثر من مجمع كائنات (الصّنف ReusablePool)، ولكلّ مجمع أصناف Reusable خاصّة به يوفّرها للعملاء الذين يطلُبون ذلك. يمكن لنفس العميل أن يطلُب خِدمات مجمعَيْ كائنات أو أكثر في نفس الوقت. يُفضل عادة أن يُحتَفَظ بجميع الكائنات القابلة لإعادة الاستخدام غير المُستخدَمة حاليا ضمن مجمع الكائنات نفسه، حتى يصبح بالإمكان إدارتها بسياسة متناسقة واحدة. لهذا الغرض، يُصمَّم الصّنف ReusablePool ليكون صنفا فريدا، توابعه المشيّدة Constructors خاصّة ممّا يُجبر الأصناف العميلة على استدعاء التابع getInstance للحصول على عيّنة من الصّنف ReusablePool. يستدعي الكائن العميل Client، عندما يحتاج لعيّنة من الصّنف القابل لإعادة الاستخدام، التابعَ acquireReusable الذي يوفّره الصّنف ReusablePool. يحتفظ كائن ReusablePool مجموعة من الكائنات القابلة لإعادة الاستخدام Reusable غير المستخدمة حاليا. ينظُر كائن ReusablePool عند استدعاء التابع acquireReusable في مجموعة كائنات Reusable التي يحتفظ بها، ويحذف منها كائنا ويعيده إلى العميل الذي طلب ذلك. إذا كان المجمع فارغا فإن التابع acquireReusable ينشئ - إن استطاع - كائنا جديدا. إن لم يستطع التابع acquireReusable إنشاء كائن جديد فإنه ينتظر أن يُرجِع أحد الكائنات العميلة كائنَ Reusable. يمرّر الكائنُ العميل كائنَ الصّنف Reusable عند انتهائه من استخدامه إلى التابع releaseReusable الذي يوفّره كائن الصّنف ReusablePool. يعيد التابعُ releaseReusable الكائنَ الذي تلقّاه من العميل إلى مجمع كائنات Reusable غير المستخدمة. تقيّد كثير من التطبيقات التي تستخدم نمط التصميم مجمع الكائنات، لأسباب مختلفة، عددَ كائنات الصنف Reusable التي يمكن تواجدها. يكون كائن ReusablePool الذي ينشئ كائنات Reusable مسؤولا في هذه الحالة من احترام هذا الشرط. تتوفّر كائنات ReusablePool - في حالة تقييد عدد الكائنات - على تابع لتحديد عدد كائنات Reusable الذي لا ينبغي تجاوزه. يظهر هذا التابع في المخطَّط أعلاه باسم setMaxPoolSize. قائمة التدقيق تأكّد عند استخدام نمط التصميم مجمع الكائنات من: إنشاء صنف مجمع الكائنات بمصفوفة خاصة من اﻷصناف القابلة لإعادة الاستخدام داخله. إنشاء تابعَي طلب الكائنات وتحريرها ضمن صنف مجمع الكائنات. استخدام نمط الصّنف المنفرد Singleton لتطبيق مجمع الكائنات. ترجمة - بتصرّف - للمقال Object Pool Design Pattern لأصحابه Alexander Shvets ،Gerhard Frey وMarina Pavlova. حقوق الصورة البارزة محفوظة لـ Freepik
  4. يهدف نمط الباني The Builder في التصميم البرمجي إلى فصل عمليّة بناء الكائنات المعقّدة عن طريقة عرضها، بحيث يُمكن إنشاء طرق عرض عدّة بنفس عمليّة البناء. كما يُستخدَم هذا النمط في التعامل مع طريقة عرض معقّدة لتحويلها إلى واحدة من بين طرق عرض أقلّ تعقيدا. عرض المشكل يتطلب تطبيق ما إنشاء عناصر من تجميع معقد. تتوافر مواصفات هذا التجمع في ذاكرة تخزين ثانوية (خارجية)، ونحتاج لبناء عرض واحد – من بين عدّة عروض ممكنة - في ذاكرة التخزين الأساسية. المناقشة تُفصَل خوارزمية التفسير (أي القراءة والتحليل) في آليّة التخزين المُستدام (كملفات RTF) عن خوارزمية بناء وعرض أحد المنتجات المستهدفة (مثل: ASCII، TeX والمربعات الجانبية “ودجة” Widgets). ينصب التركيز/التمييز على إنشاء تجميعات معقدة. يستدعي الصنف القائد Director خدمات الباني أثناء تفسير التنسيق الخارجي. ينشئ الباني جزءًا من الكائن المعقد في كلّ مرة يُستدعى فيها، كما يُحافظ على جميع الحالات الوسيطة. عندما يكتمل المنتج، يحصل العميل (وهو كائن آخر من التطبيق يحتاج الوظيفة المصمَّمة وفق نمط الباني) على النتيجة من “الباني”. يؤمّن نمط الباني تحكما أفضل بعملية الإنشاء. وعلى عكس أنماط التصميم التي تنشئ المنتجات بخطوة واحدة، يُنشئ النمط الباني المنتج خطوة بخطوة تحت إشراف القائد. مثال يفصل نمط الباني عملية بناء الكائن المعقد عن عملية عرضه بحيث يمكن لعملية البناء نفسها أن تنشئ عروضا مختلفة. يستخدم هذا النمط في مطاعم الوجبات السريعة لتحضير وجبات الأطفال. حيث تتكون وجبات الأطفال عادة من عنصر رئيسي (شطيرة هامبرغ) وعنصر جانبي (بطاطا مقلية) ومشروب ولعبة. لاحظ هنا إمكانية وجود اختلاف في محتوى وجبة الأطفال، لكن عملية بناء الوجبة هي نفسها، سواء طلب الزبون شطيرة هامبرغر أو هامبرغر بالجبنة أو دجاجًا فإن العملية هي نفسها. حيث يقوم الموظف المتواجد على النضد بتوجيه طاقم العمل لتجميع عنصر رئيسي وعنصر جانبي ولعبة ومن ثم وضع هذه العناصر في كيس، بينما يوضع المشروب في كأس ويبقى خارج الكيس. تُستخدَم العملية نفسها في المطاعم المنافسة. كيف يُطبَّق نمط التصميم “الباني” يجب أولا التأكّد قبل اختيار هذا النمط من التصميم البرمجي من أن المُدخلات المشتركة وكثرة طرق العرض الممكنة هما سبب المشكل. يغلّف Encapsulate الصنف القارئ Reader تحليل المُدخلات المشتركة. تسمح هرمية الباني بالإنشاء متعدد الأشكال Polymorphic للعديد من الأهداف أو العروض المتميزة. ملاحظة: نعني بالتغليف Encapsulation في إطار البرمجة كائنيّة التوجه Object-oriented programming تلك الآليّة التي تتيح جمع البيانات (الخاصيّات Attributes) والإجراءات المطبّقة عليها (التوابع Methods) ضمن نفس الكائن، مع تقييد إمكانيّة وصول الكائنات الأخرى إلى عناصر الكائن. يبيّن مخطَّط الأصناف التالي الارتباط بين الأصناف الداخلة في تنفيذ هذا النمط: يُغلّف تحليل المدخلات المشتركة ضمن صنف القارئ. يُصمَّم ميثاق (بروتوكول) قياسي لإنشاء جميع العروض المحتملة في المُخرجات. - تُحفظ خطوات عمل هذا البروتوكول في واجهة الباني (الصنف Converter في المخطَّط). يُعرّف صنف مشتق من الباني لكل عرض مستهدف (الأصناف ASCIIConverter، PostScriptConverter وPDFConverterفي المخطَّط). ينشئ العميل كائنًا للقراءة وكائنًا للبناء، ثم يسجّل الأخيرَ لدى الأول. يطلب العميل من القارئ أن “يبني”. يطلب العميل من الباني أن يعيد النتيجة. ترجمة - بتصرّف - للمقال Builder Design Pattern لأصحابه Alexander Shvets, Gerhard Frey, Marina Pavlova. حقوق الصورة البارزة محفوظة لـ Freepik
  5. يهدف نمط التصميم تابع المعمل Factory Method إلى تعريف واجهة Interface لإنشاء الكائنات مع ترك مهمّة تحديد الصنف الذي سيُستهَل Instantiate إلى الأصناف المتفرّعة عن الواجهة. يعرّف نمط تابع المعمل تابِعا (دالة) مشيّدا افتراضيا Virtual، كما ينطلق من مبدأ أن استخدام العامل new مؤذ ويجب تغليفه Encapsulate. ملاحظة: نعني بالتغليف Encapsulation في إطار البرمجة كائنيّة التوجه Object-oriented programming تلك الآليّة التي تتيح جمع البيانات (الخاصيّات Attributes) والإجراءات المطبّقة عليها (التوابع Methods) ضمن نفس الكائن، مع تقييد إمكانيّة وصول الكائنات الأخرى إلى عناصر الكائن. المشكلة تحتاج أطر العمل Frameworks إلى توحيد النموذج المعماري Architectural model لمجموعة من التطبيقات، لكنها تسمح للتطبيقات الفردية أن تعرّف كائنات مجالها الخاص. تؤمّن أطر العمل استهلال تلك الكائنات. المناقشة يشبه نمط تابع المعمل في إنشائها للكائنات طريقة القالب Template Method في تطبيقها للخوارزميات، إذ يقوم الصنف الأساسي بتحديد السلوك العام والقياسي (مستخدما ماسكات مكان افتراضية Virtual Placeholders واضحة لخطوات الإنشاء)، ومن ثم يفوّض إنشاء التفاصيل إلى الأصناف الفرعية التي يؤمنها العميل. يجعل نمط تابع المعمل التصميم أكثر قابلية للتخصيص من دون تعقيده كثيرا. وفي حين تتطلب أنماط التصميم الأخرى أصنافا جديدة فإن تابع المعمل لا يحتاج سوى لتابع جديد. يُستخدَم نمط تابع المعمل غالبا كطريقة قياسية لإنشاء الكائنات، لكن هذا غير ضروري عندما يكون الصنف المستهل لا يتغير أبدا، أو عندما يحصل الاستهلال بعملية يمكن للصنف الفرعي أن يلغيها بسهولة (كعملية الاستهلال). يشبه تابع المعمل نمطَ معمل التجريد، ولكن دون الاهتمام كثيرا بتجميع الكائنات ضمن مجموعات مرتبطة. تُحدّد البنية المعمارية لأُطر العمال توابع المعمل عادةً، بينما يُترَك تطبيقها لمستخدمي إطار العمل. الهيكلية تتداخل طريقة التطبيق الأصليّة - كما عرَّفها روّاد أنماط التصميم البرمجي - مع طريقة تطبيق معمل التجريد؛ إلا أن طريقة أخرى اشتهرت بعد ذلك. يتمثّل التطبيق الأكثر شعبية لنمط تابع المعمل في استخدام تابع ثابت Static يُرجِع كائنا من الصنف حيثُ يوجد التابع المذكور. يختلف التابع المُستخدَم عن التابع المشيّد Constructor في نقاط عدّة، منها: أن الكائن المُرجَع قد يكون عيّنة من صنف فرعي. أنه يمكن استخدام كائن موجود - سبق إنشاءه - بدلا من إنشاء كائن جديد. أن توابع المعمل يمكنها أن تتسمّى بطريقة مغايرة لتلك التي تفرضها لغة البرمجة، ممّا يعني أن الأسماء ستكون أكثر دلالة على عمل التوابع. على سبيل المثال: Color.make_HSB_color(float hue, float saturation, float brightness) وColor.make_RGB_color(float red, float green, float blue). يستقبل التابع ()makeProduct الثابت في الواجهة Product ضمن مخطَّط الأصناف أعلاه المُعطَيات ثمّ يقرّر بناءً عليها الصنف الفعلي للكائن الذي سيُرجعه (ProductOne أو ProductTwo). تُفصَل بقيّة أجزاء البرنامج كليّا عن التفاصيل الخاصّة بالأصناف المشتقة، ويصبح الإنشاء متعدد الأشكال Polymorphic ممكنا. ملحوظة: يشير مصطلح تعدّد الأشكال Polymorphism إلى القدرة على توفير صنف وحيد يعمل واجهةً لأصناف أخرى مختلفة. تستفيد الأصناف العميلة من الواجهة دون أن تعبأ بتفاصيل تنفيذ الأصناف (الفعلية) التي “تختبئ” وراءها. مثال يعرّف نمط تابع المعمل واجهة لإنشاء الكائنات، مع ترك مهمّة تحديد الأصناف الفعليّة التي ستُستهَل للأصناف المتفرّعة عن الواجهة. يُطبّق مصّنعو الألعاب البلاستيكية هذا النمط عند معالجة بودرة القوالب البلاستيكية. يُحقَن البلاستيك في قوالب الأشكال المرغوبة ثم يُحدَّد صنف اللعبة (سيارة مثلا) عن طريق القالب. قائمة التدقيق إن كان لديك هرمية توارث Inheritance hierarchy تمارس تعددية الأشكال، فكر في إضافة إمكانية الإنشاء متعدد الأشكال عن طريق تعريف تابع معمل ثابت Static في الصنف الأساسي. صمم معطيات Arguements تابع المعمل. ما هي النوعيات والخصائص الضرورية والكافية لتعريف الصنف المشتق الصحيح الذي سيُستهَل؟ فكر في تصميم مجمع كائنات Object Pool يسمح بإعادة استخدام الكائنات عوضا عن إنشائها من الصفر. فكر في جعل جميع التوابع المشيّدة خاصّة Private أو محميّة Protected. ترجمة - بتصرّف - للمقال Factory Method Design Pattern لأصحابه Alexander Shvets، Gerhard Frey وMarina Pavlova. حقوق الصورة البارزة محفوظة لـ Freepik
  6. عندما يواجه المُصمّمون مشكلةً مُشتركة (مثل القوائم في تطبيقات الهواتف) ويحلّها أحدهم بأسلوب أنيق (كالقائمة المخفيّة في فيسبوك على الهاتف) ثمّ يتبنّى هذا الحلّ كثيرٌ من المُصمّمين، فإنّ هذا الأسلوب يُصبح نمطًا يألفه المُستخدمون ويُساعدهم في فهم التّطبيق بصورة أسرع. نُسمّي هذه الحلول الشّائعة الاستخدام أنماط التّصميم. فهرس سلسلة مدخل إلى تجربة المستخدم: مدخل إلى تجربة المستخدم User Experience فهم ودراسة المستخدمين في مجال تجربة المستخدم دراسة الشريحة المستهدفة في مجال تجربة المستخدم كيفية التصميم للأجهزة المختلفة هندسة المعلومات في تجربة المستخدم تعرف على أنماط التصميم في مجال تجربة المستخدم (هذا الدرس) أشياء لا يمكن اعتبارها رسوما تخطيطية (Wireframes) في مجال تجربة المستخدم تعرف على الرسوم التخطيطية (Wireframes) في مجال تجربة المستخدم مفهوم الثقل المرئي (Visual Weight) والألوان في مجال تجربة المستخدم التكرار ومخالفة الأنماط في مجال تجربة المستخدم المحاذاة والقرب في مجال تجربة المستخدم تعرف على أساليب مسح الواجهة والتراتب المرئي في مجال تجربة المستخدم أساليب الإطلاع في مجال تجربة المستخدم: التصفح، البحث والاكتشاف تصميم هيكل صفحة الويب والعناصر الأساسية في مجال تجربة المستخدم الأزرار، النماذج والدعوات إلى الإجراء في مجال تجربة المستخدم استخدام علم النفس في مجال تجربة المستخدم لتكييف المستخدم وإقناعه كيف تغير الخبرة من تجربة المستخدم؟ تصميم تجربة المستخدم من خلال بيانات وإحصائيات المستخدمين تعرف على أنواع المخططات الإحصائية في مجال تجربة المستخدم اختبارات أ/ب (A/B Test) في مجال تجربة المستخدم لكنّ شيوع تصميم مُعيّن لا يعني بالضّرورة أنّه حلّ مناسب للمشكلة، وليكون نمط التّصميم جيّدًا، يجب أن يكون شائع الاستخدام وقابلًا للاستخدام في الوقت نفسه. تشيع بعض الأنماط بين المصمّمين الكُسالى لأنّها تسمح لهم بتجنّب عناء التّفكير في حلّ مناسب للمشكلة. ومن ذلك قائمة الهامبورغر الشّهيرة الّتي يستعملها فيسبوك، والّتي تمثّل قائمة مخفيّة من الأوامر تُستعمل في عديد من المواقع على الهواتف الذّكيّة، والّتي أخذت تظهر في مواقع ويب مُصمّمة للاستخدام على شاشات كبيرة لا مُبرّر لإخفاء العناصر فيها. شاع هذا النّمط لأنّه يوفّر على المُصمّم عناء إنشاء قائمة جميلة، وليس بالضّرورة لأنّه الحلّ الأفضل. في كثير من الحالات، لا يستخدم زوّار الموقع هذه القوائم لأنّهم لا يلحظونها، فإمّا أن يُغادروا الموقع أو يتخبّطوا بحثًا عن الأوامر. هذا حلّ سيئّ. وكسول. إيّاك أن تستعمله. لا يمكنني حصر قائمة بأنماط التّصميم لأنّها كثيرة ومُتغيّرة طوال الوقت بما يناسب تطوّر الأجهزة والتّقنيّات، ولكن إليك بعض الرّوابط لتطّلع عليها: GoodUI: قائمة ممتازة من الأفكار البسيطة الموضّحة بالرّسوم، والّتي يمكنك استخدامها أو تجربتها على الأقل عند تصميم مشروعك. PatternTap: مكتبة تجمع أمثلة يُشاركها أعضاء الموقع عن مختلف مكوّنات مواقع الويب. ملاحظة: بعض هذه الأمثلة جيّد، وبعضها سيئّ، ولكنّ الاطّلاع عليها يُعطيك فكرة عمّا هو شائع وما هو نادر الاستخدام. The Anatomy of a Perfect Landing Page: مقالة قديمة بعض الشّيء لكنّها لا تزال صالحة، تشرح كيفيّة تصميم صفحة عامّة للموقع تُعرض للزّوار القادمين من محرّكات البحث (أي أوّل ما يراه الزّائر). إن أعجبتك، فقد تُعجبك هذه أيضًا: Unbounce blog. Mobile Patterns: يُشبه PatternTap، وهي قائمة من تصاميم بعضها جيّد وبعضها سيّئ، لكنّها تعطيك فكرة عمّا هو شائع في تصاميم الهواتف الذّكيّة. Timoa on Pinterest: مجموعة منظّمة من عناصر الواجهات مُصنّفة حسب الميّزات. في الدّرس القادم سنطّلع على المكوّن الأكثر أهمّيّة في تصميم تجربة المُستخدم، ألا وهو هيكلة المعلومات. ترجمة بتصرّف للدّرس Design Patterns من سلسلة Daily UX Crash Course لصاحبها Joel Marsh.
  7. يكثر الحديث هذه الأيام عن أنماط تصميم البرمجيات، ومن الأسئلة الأكثر شيوعًا "كيف يمكنني استخدام النمط الفلاني مع التقنية (التكنولوجيا) الفلانيّة؟". أما في حالة Laravel ونمط المستودع (Repository pattern)، فكثيرًا أرى أسئلة من قبيل "كيف يمكنني أن أستخدم نمط المستودع في Laravel 4؟" أو في هذه الأيام "مع Laravel 5؟". من المهم أن تتذكر أنّ أنماط التصميم لا تعتمد على تقنيّة محدّدة، أو إطار برمجي محدد، أو لغة برمجة محددة. إذا كنت قد فهمت نمط المستودع بالفعل، فلا يهم الإطار البرمجي أو اللغة البرمجة التي ستستخدمها. المهم أن تفهم المبدأ الذي يقف خلف نمط المستودع، ومن ثم يمكنك استخدامه في أيّ تقنية تريد. آخذين هذا بعين الاعتبار، لنبدأ بتعريف نمط المستودع: يفصل نمط المستودع منطق الوصول إلى البيانات (data access logic) ويربطه مكانيًّا بكيانات الأعمال (business entities) في المنطق الأعمال (business logic). ويتم التواصل بين منطق الوصول إلى البيانات ومنطق الأعمال باستخدام واجهات (interfaces). ولتبسيط ذلك، فإن نمط المستودع نوع من الحاويات يخزّن فيه منطق الوصول إلى البيانات، بحيث يخفي منطق الوصول إلى البيانات عن منطق الأعمال. وبعبارة أخرى، نسمح لمنطق الأعمال أن يصل إلى كائن البيانات دون معرفة هيكلية الوصول إلى البيانات التي تتم خلف الكواليس. ولفصل الوصول إلى البيانات عن منطق الأعمال فوائد عدّة، منها: مركزية منطق الوصول إلى البيانات تجعل النصوص البرمجية أسهل في الصيانة.يمكن فحص منطق الأعمال ومنطق الوصول إلى البيانات كلًّا على حدة.تقليل تكرار الأكواد البرمجية.فرصة أقل للوقوع في أخطاء برمجية.الأمر كلّه يتعلق بالواجهاتكلّ ما في نمط المستودع ذو علاقة بالواجهات. تعمل الواجهة كاتفاقية تحدّد ما على فئة concrete تنفيذه.لنفكّر قليلًا. إذا كان لدينا كائني بيانات، الممثل والفلم، فما هي مجموعة العمليات الشائعة التي يمكن تطبيقها على هذين العنصرين؟ سنرغب في غالب الأحيان بالقيام بالعمليات التالية: الحصول على جميع السجلات.الحصول على مجموعة السجلّات مرقّمة.إنشاء سجلّ جديد.الحصول على سجل باستخدام المفتاح الرئيسيّ.الحصول على سجل باستخدام خواص (attributes) أخرى.تحديث سجلّ.حذف سجلّ.هل يمكنك الآن أن ترى كميّة النصوص البرمجيّة المكررة التي ستكون لدينا إذا قمنا بذلك مع كلّ كائن بيانات؟ حسنًا، هذه ليست مشكلة كبيرة بالنسبة للمشاريع الصغيرة، ولكنها أمر سيّء بالنسبة للمشاريع الكبيرة. الآن، وبعد أن عرّفنا العمليات الشائعة، يمكننا إنشاء واجهة: interface RepositoryInterface { public function all($columns = array('*')); public function paginate($perPage = 15, $columns = array('*')); public function create(array $data); public function update(array $data, $id); public function delete($id); public function find($id, $columns = array('*')); public function findBy($field, $value, $columns = array('*')); }هيكليّة الدليل Directory Structureقبل أن نتابع إنشاء فئة مستودع concrete التي ستنفّذ هذه الواجهة، لنفكّر قليلًا كيف نريد أن ننظّم النصوص البرمجيّة لدينا. عادة، عندما أنشئ شيئًا ما، أفضّل أن أفكر بطريقة تقسيمه إلى مكوّنات، حيث أرغب بأن أكون قادرًا على إعادة استخدام ذاك النصّ البرمجيّ لمشاريع أخرى. إن هيكليّة الدليل البسيطة التي أتبعها لمكونات المستودع تبدو كما يلي: ولكنها يمكن أن تكون مختلفة، كأن يكون للمكونات خيارات ضبط مثلًا. لدي في داخل الدليل src ثلاثة أدلّة أخرى، هي: Contracts وEloquent وexceptions. كما ترى، أسماء المجلدات مناسبة للغاية لما نريد وضعه فيها. ففي Contracts نضع الواجهات، أو الاتفاقيات – كما سميناها أعلاه - . ويحوي مجلد Eloquent مستودعي abstract و concrete تنفّذ الاتفاقات. ونضع في المجيد Exceptions فئات الاستثناءات. وحيث أننا ننشئ حزم، فعلينا أن ننشئ ملف composer.json، حيث نجد فيه ربطًا مكانيًّا لنطاق الأسماء (namespaces) لأدلّة معيّنة، واعتماديات حزم، وبيانات وصفيّة أخرى للحزم. فيما يلي محتوى composer.json لهذه الحزمة: { "name": "bosnadev/repositories", "description": "Laravel Repositories", "keywords": [ "laravel", "repository", "repositories", "eloquent", "database" ], "licence": "MIT", "authors": [ { "name": "Mirza Pasic", "email": "mirza.pasic@edu.fit.ba" } ], "require": { "php": ">=5.4.0", "illuminate/support": "5.*", "illuminate/database": "5.*" }, "autoload": { "psr-4": { "Bosnadev\\Repositories\\": "src/" } }, "autoload-dev": { "psr-4": { "Bosnadev\\Tests\\Repositories\\": "tests/" } }, "extra": { "branch-alias": { "dev-master": "0.x-dev" } }, "minimum-stability": "dev", "prefer-stable": true } كما ترى، فقد ربطنا Bosnadev\Repository إلى الدليل src. وهناك شيء آخر علينا أخذه بعين الاعتبار قبل البدء بتنفيذ RepositoryInterface، فحيث أنها موجودة في المجلد Contracts، فعلينا أن نحدّد نطاق الاسم لها: <?php namespace Bosnadev\Repositories\Contracts; interface RepositoryInterface {...}نحن الآن مستعدون لبدء تنفيذ المحتوى. تنفيذ المستودععلى كل مستودع فرعيّ في concrete أن يزيد من مستودع abstract لدينا، مما يعني تنفيذ اتفاقية RepositoryInterface. أما الآن، فكيف تنفّذ هذه الاتفاقيّة؟ ألقِ نظرة على method الأولى. ما الذي يمكنك قوله عنها بمجرد النظر إليها؟ تُسمى method الأولى في اتفاقيتنا بالاسم ()all للتوضيح. مهمتها هي جلب كلّ السجلات لهيئة concrete. تستقبل معامِلاً واحدًا، وهو columns$ الذي يجب أن يكون مصفوفة (array). يُستخدّم هذا المعامِل – كما هو واضح من اسمه – لتحديد الأعمدة التي ترغب بجلبها من مصدر البيانات، ومبدئيًّا نقوم بجلبها كلّها. لهئيات محدّدة، يمكن أن تبدو كالتالي: <?php namespace Bosnadev\Repositories\Contracts; interface RepositoryInterface {...}لكننا نريدها أن تكون عامّة أكثر لكي نتمكن من استخدامها متى أردنا: public function all($columns = array('*')) { return $this->model->get($columns); } في هذه الحالة this->model$ هي نسخة من Bosnadev\Models\Actor، ولهذا، فعلينا إنشاء نسخة جديدة للنموذج الموجود في مكان ما في المستودع. هنا أحد الحلول التي يمكنك استخدامها لتنفيذ هذا الأمر: <?php namespace Bosnadev\Repositories\Eloquent; use Bosnadev\Repositories\Contracts\RepositoryInterface; use Bosnadev\Repositories\Exceptions\RepositoryException; use Illuminate\Database\Eloquent\Model; use Illuminate\Container\Container as App; /** * Class Repository * @package Bosnadev\Repositories\Eloquent */ abstract class Repository implements RepositoryInterface { /** * @var App */ private $app; /** * @var */ protected $model; /** * @param App $app * @throws \Bosnadev\Repositories\Exceptions\RepositoryException */ public function __construct(App $app) { $this->app = $app; $this->makeModel(); } /** * Specify Model class name * * @return mixed */ abstract function model(); /** * @return Model * @throws RepositoryException */ public function makeModel() { $model = $this->app->make($this->model()); if (!$model instanceof Model) throw new RepositoryException("Class {$this->model()} must be an instance of Illuminate\\Database\\Eloquent\\Model"); return $this->model = $model; } } وحيث أننا عرفنا الفئة كـ abstract، فهذا يعني أن علينا زيادتها باستخدام فئة متفرّعة عن concrete. فعند تعريف method المسمّى ()model كـ abstract، فإننا نجبر المستخدم على تنفيذ هذه الطريقة (method) في فئة متفرعة عن concrete. فمثلًا: <?php namespace App\Repositories; use Bosnadev\Repositories\Contracts\RepositoryInterface; use Bosnadev\Repositories\Eloquent\Repository; class ActorRepository extends Repository { /** * Specify Model class name * * @return mixed */ function model(){ return 'Bosnadev\Models\Actor'; } }يمكننا الآن أن ننفذ بقية طرق (methods) الاتفاقات: <?php namespace Bosnadev\Repositories\Eloquent; use Bosnadev\Repositories\Contracts\RepositoryInterface; use Bosnadev\Repositories\Exceptions\RepositoryException; use Illuminate\Database\Eloquent\Model; use Illuminate\Container\Container as App; /** * Class Repository * @package Bosnadev\Repositories\Eloquent */ abstract class Repository implements RepositoryInterface { /** * @var App */ private $app; /** * @var */ protected $model; /** * @param App $app * @throws \Bosnadev\Repositories\Exceptions\RepositoryException */ public function __construct(App $app) { $this->app = $app; $this->makeModel(); } /** * Specify Model class name * * @return mixed */ abstract function model(); /** * @param array $columns * @return mixed */ public function all($columns = array('*')) { return $this->model->get($columns); } /** * @param int $perPage * @param array $columns * @return mixed */ public function paginate($perPage = 15, $columns = array('*')) { return $this->model->paginate($perPage, $columns); } /** * @param array $data * @return mixed */ public function create(array $data) { return $this->model->create($data); } /** * @param array $data * @param $id * @param string $attribute * @return mixed */ public function update(array $data, $id, $attribute="id") { return $this->model->where($attribute, '=', $id)->update($data); } /** * @param $id * @return mixed */ public function delete($id) { return $this->model->destroy($id); } /** * @param $id * @param array $columns * @return mixed */ public function find($id, $columns = array('*')) { return $this->model->find($id, $columns); } /** * @param $attribute * @param $value * @param array $columns * @return mixed */ public function findBy($attribute, $value, $columns = array('*')) { return $this->model->where($attribute, '=', $value)->first($columns); } /** * @return \Illuminate\Database\Eloquent\Builder * @throws RepositoryException */ public function makeModel() { $model = $this->app->make($this->model()); if (!$model instanceof Model) throw new RepositoryException("Class {$this->model()} must be an instance of Illuminate\\Database\\Eloquent\\Model"); return $this->model = $model->newQuery(); } } الأمر سهل للغاية، صح؟ الشيء الوحيد المتبقي الآن هو حقن ActorRepository في ActorsController، أو الجزء المتعلق بالأعمال (business logic) من تطبيقنا. <?php namespace App\Http\Controllers; use App\Repositories\ActorRepository as Actor; class ActorsController extends Controller { /** * @var Actor */ private $actor; public function __construct(Actor $actor) { $this->actor = $actor; } public function index() { return \Response::json($this->actor->all()); } }استعلامات المعايير Criteria Queriesكما يمكنك أن تتخيل، فهذه الأعمال البسيطة كافية فقط لاستعلامات البسيطة. أما بالنسبة للتطبيقات الكبيرة، فستحتاج بالتأكيد لعمل بعض الاستعلامات الخاصّة لاستدعاء مجموعة بيانات محدّدة أكثر باستخدام معايير محدّدة. للقيام بذلك، نبدأ بتحديد ما على معايير الفروع (child ، أو العميل client) القيام به. وبعبارة أخرى، سننشئ فئة abstract non-instantiable باستخدام method واحدة فقط : <?php namespace Bosnadev\Repositories\Criteria; use Bosnadev\Repositories\Contracts\RepositoryInterface as Repository; use Bosnadev\Repositories\Contracts\RepositoryInterface; abstract class Criteria { /** * @param $model * @param RepositoryInterface $repository * @return mixed */ public abstract function apply($model, Repository $repository); }ستحوي هذه الطريقة (method) استعلام معايير يتم تطبيقه في فئة Repository ضمن هيئة concrete. علينا أيضًا أن نزيد على فئة Repository قليلًا لتغطية استعلامات المعايير. لكن قبل ذلك، هيّا ننشئ اتفاقية أخرى لفئة Repository. <?php namespace Bosnadev\Repositories\Contracts; use Bosnadev\Repositories\Criteria\Criteria; /** * Interface CriteriaInterface * @package Bosnadev\Repositories\Contracts */ interface CriteriaInterface { /*** @param bool $status * @return $this */ public function skipCriteria($status = true); /*** @return mixed*/public function getCriteria(); /*** @param Criteria $criteria* @return $this*/public function getByCriteria(Criteria $criteria); /*** @param Criteria $criteria* @return $this*/public function pushCriteria(Criteria $criteria); /*** @return $this*/public function applyCriteria(); }يمكننا أن نزيد فاعلية فئة Repository بتنفيذ اتفاقية CriteriaInterface: <?php namespace Bosnadev\Repositories\Eloquent; use Bosnadev\Repositories\Contracts\CriteriaInterface; use Bosnadev\Repositories\Criteria\Criteria; use Bosnadev\Repositories\Contracts\RepositoryInterface; use Bosnadev\Repositories\Exceptions\RepositoryException; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Collection; use Illuminate\Container\Container as App; /** * Class Repository * @package Bosnadev\Repositories\Eloquent */ abstract class Repository implements RepositoryInterface, CriteriaInterface { /** * @var App */ private $app; /** * @var */ protected $model; /** * @var Collection */ protected $criteria; /** * @var bool */ protected $skipCriteria = false; /** * @param App $app * @param Collection $collection * @throws \Bosnadev\Repositories\Exceptions\RepositoryException */ public function __construct(App $app, Collection $collection) { $this->app = $app; $this->criteria = $collection; $this->resetScope(); $this->makeModel(); } /** * Specify Model class name * * @return mixed */ public abstract function model(); /** * @param array $columns * @return mixed */ public function all($columns = array('*')) { $this->applyCriteria(); return $this->model->get($columns); } /** * @param int $perPage * @param array $columns * @return mixed */ public function paginate($perPage = 1, $columns = array('*')) { $this->applyCriteria(); return $this->model->paginate($perPage, $columns); } /** * @param array $data * @return mixed */ public function create(array $data) { return $this->model->create($data); } /** * @param array $data * @param $id * @param string $attribute * @return mixed */ public function update(array $data, $id, $attribute="id") { return $this->model->where($attribute, '=', $id)->update($data); } /** * @param $id * @return mixed */ public function delete($id) { return $this->model->destroy($id); } /** * @param $id * @param array $columns * @return mixed */ public function find($id, $columns = array('*')) { $this->applyCriteria(); return $this->model->find($id, $columns); } /** * @param $attribute * @param $value * @param array $columns * @return mixed */ public function findBy($attribute, $value, $columns = array('*')) { $this->applyCriteria(); return $this->model->where($attribute, '=', $value)->first($columns); } /** * @return \Illuminate\Database\Eloquent\Builder * @throws RepositoryException */ public function makeModel() { $model = $this->app->make($this->model()); if (!$model instanceof Model) throw new RepositoryException("Class {$this->model()} must be an instance of Illuminate\\Database\\Eloquent\\Model"); return $this->model = $model->newQuery(); } /** * @return $this */ public function resetScope() { $this->skipCriteria(false); return $this; } /** * @param bool $status * @return $this */ public function skipCriteria($status = true){ $this->skipCriteria = $status; return $this; } /** * @return mixed */ public function getCriteria() { return $this->criteria; } /** * @param Criteria $criteria * @return $this */ public function getByCriteria(Criteria $criteria) { $this->model = $criteria->apply($this->model, $this); return $this; } /** * @param Criteria $criteria * @return $this */ public function pushCriteria(Criteria $criteria) { $this->criteria->push($criteria); return $this; } /** * @return $this */ public function applyCriteria() { if($this->skipCriteria === true) return $this; foreach($this->getCriteria() as $criteria) { if($criteria instanceof Criteria) $this->model = $criteria->apply($this->model, $this); } return $this; } } إنشاء معايير جديدة، حيث يمكنك الآن أن ترتب مستودعاتك بسهولة أكبر. لست بحاجة لأن تكون مستودعاتك مكونة من آلاف الأسطر. يمكن أن تبدو فئة المعايير لديك كالآتي: <?php namespace App\Repositories\Criteria\Films; use Bosnadev\Repositories\Contracts\CriteriaInterface; use Bosnadev\Repositories\Contracts\RepositoryInterface as Repository; use Bosnadev\Repositories\Contracts\RepositoryInterface; class LengthOverTwoHours implements CriteriaInterface { /** * @param $model * @param RepositoryInterface $repository * @return mixed */ public function apply($model, Repository $repository){ $query = $model->where('length', '>', 120); return $query; } }استخدام للمعايير (Criteria) في المتحكّمات (Controllers)الآن وقد صارت لدينا معايير بسيطة، لنرَ كيف يمكننا استخدامها. هناك طريقتان يمكنك اتباعهما لتطبيق المعايير على مستودع. الأولى باستخدام طريقة ()pushCriteria: <?php namespace App\Http\Controllers; use App\Repositories\Criteria\Films\LengthOverTwoHours; use App\Repositories\FilmRepository as Film; class FilmsController extends Controller { /*** @var Film*/private $film; public function __construct(Film $film) { $this->film = $film; } public function index() { $this->film->pushCriteria(new LengthOverTwoHours()); return \Response::json($this->film->all()); } }هذه الطريقة مفيدة إذا كنت ترغب بتطبيق أكثر من معيار في نفس الوقت، حيث يمكنك رصّها معًا كما تشاء، ولكن إذا رغب بتطبيق معيار واحد فقط، فيمكنك استخدام طريقة ()getByCriteria: <?php namespace App\Http\Controllers; use App\Repositories\Criteria\Films\LengthOverTwoHours; use App\Repositories\FilmRepository as Film; class FilmsController extends Controller { /** * @var Film */ private $film; public function __construct(Film $film) { $this->film = $film; } public function index() { $criteria = new LengthOverTwoHours(); return \Response::json($this->film->getByCriteria($criteria)->all()); } }تثبيت الحزميمكنك تثبيت هذه الحزمة بإضافة الاعتمادية التالية إلى قسم require في ملف composer لديك: "bosnadev/repositories": "0.*"وتنفيذ composer update بعد ذلك، الخلاصةلاستخدام المستودعات في تطبيقك العديد من الفوائد. من أشياء بسيطة كتقليل تكرار الأكواد ومنعك من ارتكاب أخطاء برمجيّة وجعل تطبيقك أسهل في التكبير والتوسعة، والاختبار، والصيانة. من وجهة نظر هندسيّة، فقد تمكنت من عزل الاهتمامات. المتحكّم (controller) لديك ليس بحاجة لأن يعرف كيف وأين تخزَّن البيانات. بسيط وجميل. تجريديّ (Abstract). ترجمة وبتصرف للمقال: Using Repository Pattern in Laravel 5.