المحتوى:

  1. مقدمة
  2. تعريف أنماط التصميم
  3. مم تتكون أنماط التصميم؟
  4. تاريخ أنماط التصميم
  5. لماذا يجب أن أتعلم الأنماط؟
  6. نقد الأنماط
  7. تصنيف الأنماط
  8. الأنماط الإبداعية
  9. الأنماط الهيكلية
  10. الأنماط السلوكية
  11. الخاتمة
  12. المراجع

المقدمة:
يعد تصميم البرامج كائنية التوجه أمرًا صعبًا، كما أن تصميم البرامج كائنية التوجه القابلة لإعادة الاستخدام هو أمر أكثر صعوبة. يجب علينا العثور على الكائنات ذات الصلة، وتقسيمها إلى فئات بالدقة الصحيحة، وتحديد واجهات الفئات والتسلسلات الهرمية للميراث، وإنشاء علاقات رئيسية فيما بينها. يجب أن يكون تصميمنا محددًا للمشكلة المطروحة ولكن أيضًا عام بما يكفي لمعالجة المشكلات والمتطلبات المستقبلية. نحن أيضًا نريد تجنب إعادة التصميم، أو على الأقل تقليله. سيخبرنا المصممون ذوو الخبرة في مجال البرامج كائنية التوجه أن التصميم المرن والقابل لإعادة الاستخدام يصعب إن لم يكن من المستحيل الحصول عليه “بشكل صحيح” في المرة الأولى. قبل الانتهاء من التصميم، يحاولون عادةً إعادة استخدامه عدة مرات، وتعديله في كل مرة.

ما هي أنماط التصميم؟
تعد أنماط التصميم بمثابة حلول نموذجية للمشاكل الشائعة في تصميم البرامج. إنها تشبه المخططات المعدة مسبقًا والتي يمكننا تخصيصها لحل مشكلة التصميم المتكررة في التعليمات البرمجية الخاصة بنا و لا يمكننا العثور على نمط ونسخه في برنامجنا فحسب، بنفس الطريقة التي يمكننا بها ذلك باستخدام الوظائف أو المكتبات الجاهزة. النمط ليس جزءًا محددًا من التعليمات البرمجية، ولكنه مفهوم عام لحل مشكلة معينة. يمكننا متابعة تفاصيل النمط وتنفيذ الحل الذي يناسب واقع برنامجنا الخاص وغالبًا ما يتم الخلط بين الأنماط والخوارزميات، لأن كلا المفهومين يصفان حلولًا نموذجية لبعض المشكلات المعروفة. في حين أن الخوارزمية تحدد دائمًا مجموعة واضحة من الإجراءات التي يمكنها تحقيق بعض الأهداف، فإن النمط هو وصف عالي المستوى للحل. قد يكون رمز نفس النمط المطبق على برنامجين مختلفين مختلفًا فتشبيه الخوارزمية هو وصفة الطبخ: كلاهما لديه خطوات واضحة لتحقيق الهدف. من ناحية أخرى، النمط يشبه المخطط: يمكننا رؤية النتيجة وميزاته، ولكن الترتيب الدقيق للتنفيذ متروك لنا.

مم تتكون أنماط التصميم؟
يتم وصف معظم الأنماط بشكل رسمي للغاية حتى يتمكن الأشخاص من إعادة إنتاجها في العديد من السياقات وفيما يلي الأقسام الموجودة عادةً في وصف النمط:

  • غرض النموذج Intent of the pattern: يصف بإيجاز كلاً من المشكلة والحل.
  • الدافع Motivation: يشرح أيضًا المشكلة والحل الذي يتيحه النمط.
  • هيكل الفئات Structure of classes يوضح كل جزء من النموذج وكيفية ارتباطها.

تاريخ أنماط التصميم
من اخترع الأنماط؟ هذا سؤال جيد، لكنه ليس دقيقًا جدًا. أنماط التصميم ليست مفاهيم غامضة ومتطورة، بل على العكس تمامًا. الأنماط هي حلول نموذجية للمشاكل الشائعة في تصميم البرامج كائنية التوجه. عندما يتكرر الحل مرارًا وتكرارًا في مشاريع مختلفة، يقوم شخص ما في النهاية بوضع اسم له ويصف الحل بالتفصيل. هذا هو الأساس الذي يتم من خلاله اكتشاف النمط.
تم وصف مفهوم الأنماط لأول مرة بواسطة كريستوفر ألكساندر في لغة الأنماط: المدن والمباني والإنشاءات. ويصف الكتاب “لغة” لتصميم البيئة الحضرية. وحدات هذه اللغة هي الأنماط. وقد تصف مدى ارتفاع النوافذ، وعدد المستويات التي يجب أن يحتوي عليها المبنى، وحجم المساحات الخضراء في الحي، وما إلى ذلك.
وقد التقط الفكرة أربعة مؤلفين: إريك جاما، وجون فليسيدس، ورالف جونسون، وريتشارد هيلم. في عام 1994، نشروا أنماط التصميم: عناصر البرامج كائنية التوجه القابلة لإعادة الاستخدام،
Design Patterns: Elements of Reusable Object-Oriented Software,)
حيث طبقوا مفهوم أنماط التصميم على البرمجة. يضم الكتاب 23 نموذجًا لحل مشكلات مختلفة تتعلق بتصميم البرامج كائنية التوجه، وأصبح من أكثر الكتب مبيعًا بسرعة كبيرة. نظرًا لاسمه الطويل، بدأ الناس يطلقون عليه اسم “كتاب عصابة الأربعة” والذي سرعان ما تم اختصاره إلى “كتاب GoF”.
ومنذ ذلك الحين، تم اكتشاف العشرات من الأنماط الشيئية الأخرى.
أصبح “نهج النمط (“pattern approach”)” شائعًا جدًا في مجالات البرمجة الأخرى، لذلك توجد الآن الكثير من الأنماط الأخرى خارج تصميم البرامج كائنية التوجه أيضًا.

لماذا يجب أن نتعلم الأنماط؟
الحقيقة هي أننا قد نتمكن من العمل كمبرمجين لسنوات عديدة دون أن نعرف نمطًا واحدًا. الكثير من الناس يفعلون ذلك. وحتى في هذه الحالة، قد نقوم بتنفيذ بعض الأنماط دون أن نعرف ذلك.
فلماذا نقضي وقتًا في تعلمها؟
أنماط التصميم هي مجموعة أدوات من الحلول المجربة والمختبرة للمشاكل الشائعة في تصميم البرمجيات. حتى لو لم تواجه هذه المشكلات مطلقًا، فإن معرفة الأنماط لا تزال مفيدة لأنها تعلمنا كيفية حل جميع أنواع المشكلات باستخدام مبادئ تصميم البرامج كائنية التوجه.
تحدد أنماط التصميم لغة مشتركة يمكننا استخدامها للتواصل بشكل أكثر كفاءة. يمكننا أن نقول: “أوه، فقط استخدم Singleton لذلك”، وسيفهم الجميع الفكرة وراء اقتراحنا. لا حاجة لشرح الفكرة إذا كنا نعرف النمط واسمه.

نقد الأنماط
يبدو أن الأشخاص الكسالى فقط هم الذين لم ينتقدوا أنماط التصميم بعد.
دعونا نلقي نظرة على الحجج الأكثر شيوعًا ضد استخدام الأنماط.

 عادةً ما تنشأ الحاجة إلى الأنماط عندما يختار الأشخاص لغة برمجة أو تقنية تفتقر إلى المستوى الضروري من التجريد. في هذه الحالة، تصبح الأنماط بمثابة خدعة تمنح اللغة قدرات فائقة تشتد الحاجة إليها.
على سبيل المثال، يمكن تنفيذ نمط الإستراتيجية (the Strategy pattern) باستخدام وظيفة مجهولة بسيطة (lambda) في معظم لغات البرمجة الحديثة.

حلول غير فعالة
تحاول الأنماط تنظيم الأساليب المستخدمة بالفعل على نطاق واسع. ينظر الكثيرون إلى هذا التوحيد على أنه عقيدة، ويقومون بتنفيذ الأنماط “حرفيًا”، دون تكييفها مع سياق مشروعهم.

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

تصنيف الأنماط
تختلف أنماط التصميم حسب تعقيدها ومستوى التفاصيل وحجم قابلية التطبيق على النظام بأكمله الذي يتم تصميمه.
سنقوم بالتشبيه ببناء الطرق: يمكننا جعل التقاطع أكثر أمانًا إما عن طريق تركيب بعض إشارات المرور أو بناء تقاطع كامل متعدد المستويات مع ممرات تحت الأرض للمشاة.
غالبًا ما تسمى الأنماط الأساسية والمنخفضة المستوى basic and low-level patterns))
بالتعابيرidioms) ) وعادة ما تنطبق فقط على لغة برمجة واحدة.
الأنماط الأكثر عالمية وعالية المستوى (universal and high-level patterns) هي الأنماط المعمارية (architectural patterns). ويمكن للمطورين تنفيذ هذه الأنماط بأي لغة تقريبًا. وعلى عكس الأنماط الأخرى، يمكن استخدامها لتصميم بنية التطبيق بأكمله.
بالإضافة إلى ذلك، يمكن تصنيف جميع الأنماط حسب غرضها. سنغطي في هذه المقالة ثلاث مجموعات رئيسية من الأنماط:

Creational patterns الأنماط الإبداعية:
توفر آليات إنشاء الكائنات التي تزيد من المرونة وإعادة استخدام التعليمات البرمجية الموجودة.

Structural patterns الأنماط الهيكلية:
تشرح كيفية تجميع الأشياء والفئات في هياكل أكبر، مع الحفاظ على هذه الهياكل مرنة وفعالة.

Behavioral patterns الأنماط السلوكية:
تهتم بالتواصل الفعال وتوزيع المسؤوليات بين الأشياء.

الأنماط الإبداعية “Creational patterns“:
أنماط التصميم الإبداعي تلخص عملية إنشاء مثيل (instantiation process). إنها تساعد في جعل النظام مستقلاً عن كيفية إنشاء كائناته وتكوينها وتمثيلها. يستخدم نمط إنشاء الفئة الوراثة لتغيير الفئة التي تم إنشاء مثيل لها، في حين أن نمط إنشاء الكائن سوف يقوم بتفويض إنشاء مثيل إلى كائن آخر.
تصبح الأنماط الإبداعية مهمة مع تطور الأنظمة لتعتمد بشكل أكبر على تكوين الكائن بدلاً من وراثة الفئة. وعندما يحدث ذلك، يتحول التركيز بعيدًا عن الترميز الثابت لمجموعة ثابتة من السلوكيات نحو تحديد مجموعة أصغر من السلوكيات الأساسية التي يمكن تجميعها في أي عدد من السلوكيات الأكثر تعقيدًا. وبالتالي فإن إنشاء كائنات ذات سلوكيات معينة يتطلب أكثر من مجرد إنشاء مثيل لها.
توفر أنماط التصميم الإبداعي آليات مختلفة لإنشاء الكائنات، مما يزيد من المرونة وإعادة استخدام التعليمات البرمجية الموجودة.

Factory pattern:
نمط المصنع هو نمط تصميم إبداعي يوفر واجهة لإنشاء كائنات في فئة فائقة، ولكنه يسمح للفئات الفرعية بتغيير نوع الكائنات التي سيتم إنشاؤها.

مشكلته:
تخيل أننا نقوم بإنشاء تطبيق لإدارة الخدمات اللوجستية. يمكن للإصدار الأول من تطبيقنا التعامل مع النقل بالشاحنات فقط، وبالتالي فإن الجزء الأكبر من التعليمات البرمجية الخاصة بنا موجودة داخل فئة Truck.


وبعد فترة من الوقت، يصبح تطبيقنا مشهورًا جدًا. نتلقى كل يوم عشرات الطلبات من شركات النقل البحري لدمج الخدمات اللوجستية البحرية في التطبيق.

أخبار عظيمة، أليس كذلك؟ ولكن ماذا عن الكود؟ في الوقت الحاضر، تقترن معظم التعليمات البرمجية الخاصة بنا بفئة Truck. قد تتطلب إضافة السفن إلى التطبيق إجراء تغييرات على قاعدة التعليمات البرمجية بأكملها. علاوة على ذلك، إذا قررنا لاحقًا إضافة نوع آخر من وسائل النقل إلى التطبيق، فمن المحتمل أن نحتاج إلى إجراء كل هذه التغييرات مرة أخرى. ونتيجة لذلك،
سينتهي بنا الأمر مع تعليمات برمجية سيئة جدًا، مليئة بالشروط الشرطية التي تغير سلوك التطبيق اعتمادًا على فئة كائنات النقل.

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

على سبيل المثال، يجب أن تقوم كل من فئتي Truck وShip بتنفيذ واجهة النقل، التي تعلن عن طريقة تسمى التسليم. تطبق كل فئة هذه الطريقة بشكل مختلف: تقوم الشاحنات بتوصيل البضائع عن طريق البر، وتقوم السفن بتوصيل البضائع عن طريق البحر. تقوم طريقة المصنع في فئة Road Logistics بإرجاع كائنات الشاحنة، بينما تقوم طريقة المصنع في فئة Sea Logistics بإرجاع السفن.
لا يرى الكود الذي يستخدم طريقة المصنع (يُسمى غالبًا رمز العميل) فرقًا بين المنتجات الفعلية التي يتم إرجاعها بواسطة الفئات الفرعية المختلفة. يعامل العميل جميع المنتجات على أنها نقل مجرد. يعرف العميل أن جميع كائنات النقل من المفترض أن يكون لديها طريقة التسليم، ولكن كيفية عملها بالضبط ليست مهمة للعميل. 

البناء:

القابلية للتطبيق:
استخدم طريقة المصنع عندما لا تعرف مسبقًا الأنواع الدقيقة والتبعيات للكائنات التي يجب أن يعمل الكود الخاص بك معها.
استخدم طريقة المصنع عندما تريد تزويد مستخدمي مكتبتك أو إطار العمل الخاص بك بطريقة    لتوسيع مكوناته الداخلية.
استخدم طريقة المصنع عندما تريد حفظ موارد النظام عن طريق إعادة استخدام الكائنات الموجودة بدلاً من إعادة بنائها في كل مرة.
الإيجابيات:
يمكنك تجنب الاقتران الوثيق بين المبدع والمنتجات الملموسة. مبدأ المسؤولية الفردية. يمكنك نقل كود إنشاء المنتج إلى مكان واحد في البرنامج، مما يسهل دعم الكود
مبدأ مفتوح/مغلق. يمكنك إدخال أنواع جديدة من المنتجات إلى البرنامج دون كسر رمز العميل الحالي.
السلبيات:
قد تصبح التعليمات البرمجية أكثر تعقيدًا نظرًا لأنك تحتاج إلى تقديم الكثير من الفئات الفرعية الجديدة لتنفيذ النمط. أفضل سيناريو هو عندما تقوم بإدخال النمط في التسلسل الهرمي الحالي لفئات المنشئ.

الأنماط الهيكلية “ “Structural patterns:
تهتم الأنماط الهيكلية بكيفية تكوين الفئات والأشياء لتكوين هياكل أكبر. تستخدم الأنماط الهيكلية الوراثة لإنشاء واجهات أو تطبيقات. كمثال بسيط، نفكر في كيفية دمج الميراث المتعدد بين فئتين أو أكثر في فئة واحدة. والنتيجة هي فئة تجمع بين خصائص الفئات الأصلية. يعد هذا النمط مفيدًا بشكل خاص لجعل مكتبات الفئات المطورة بشكل مستقل تعمل معًا. مثال آخر هو النمط المحول (the Adapter pattern).
بشكل عام، يجعل هذا النمط واجهة واحدة متوافقة مع أخرى، وبالتالي يوفر تجريدًا موحدًا للواجهات المختلفة. ينجز محول الفئة ذلك عن طريق وراثة
تشرح أنماط التصميم الهيكلية كيفية تجميع الأشياء والفئات في هياكل أكبر، مع الحفاظ على هذه الهياكل مرنة وفعالة.

الأنماط السلوكية “Behavioral patterns“:
تهتم الأنماط السلوكية بالخوارزميات وتوزيع المسؤوليات بين الأشياء. لا تصف الأنماط السلوكية أنماط الأشياء أو الفئات فحسب، بل تصف أيضًا أنماط الاتصال بينها. تميز هذه الأنماط تدفق التحكم المعقد الذي يصعب متابعته في وقت التشغيل. إنها تحول تركيزك بعيدًا عن تدفق التحكم لتمكنك من التركيز فقط على الطريقة التي تترابط بها الأشياء.
تستخدم أنماط الطبقة السلوكية الوراثة لتوزيع السلوك بين الطبقات. ويتضمن هذا الفصل نموذجين من هذا القبيل. طريقة القالب (Template Method) هي الأسهل والأكثر شيوعًا بين الاثنين. طريقة القالب هي تعريف مجرد للخوارزمية. فهو يحدد الخوارزمية خطوة بخطوة.
تهتم أنماط التصميم السلوكي بالخوارزميات وتوزيع المسؤوليات بين الكائنات.

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

المراجع
https://www.oreilly.com/library/view/design-patterns-elements/0201633612
https://refactoring.guru/design-patterns/factory-method

Facebook
Twitter
YouTube
LinkedIn
Instagram