المحتوى:

  1. أنماط التصميم الإبداعية “Structural patterns”
  2. ما هو نمط التصميم الإبداعي”Adapter design pattern”
  3. مشكلة يمكن حلها باستخدام نمط التصميم” Adapter design pattern”
  4. حل المشكلة باستخدام نمط التصميم” Adapter design pattern”
  5. بناء نمط التصميم الإبداعي” Adapter design pattern”
  6. تمثيل نمط التصميم ” Adapter design pattern” بشكل كود
  7. قابلية نمط التصميم ” Adapter design pattern” للتطبيق
  8. كيفية تنفيذ نمط التصميم ” Adapter design pattern”
  9. إيجابيات وسلبيات نمط التصميم ” Adapter design pattern “
  10. علاقات نمط التصميم ” Adapter design pattern ” مع الأنماط الأخرى
  11. الخاتمة
  12. المراجع
  1. أنماط التصميم الإنشائية“Structural patterns

الأنماط الهيكلية هي فئة من أنماط التصميم في هندسة البرمجيات. تركِّز هذه الأنماط على تنظيم الفئات والكائنات المختلفة لتكوين هياكل أكبر وتوفير العلاقات فيما بينها تهتم الأنماط الهيكلية في المقام الأول بتكوين الفئة وتكوين الكائن.
نفكر في كيفية دمج الميراث المتعدد بين فئتين أو أكثر في فئة واحدة. والنتيجة هي فئة تجمع بين خصائص الفئات الأصلية وهناك موضوعان متكرران في هذا النمط:
يُعد هذا النمط مفيداً بشكل خاص لجعل مكتبات الفئات المطورة بشكل مستقل تعمل معاً.
وتصف أنماط التصميم الهيكلي طرقاً لتكوين الكائنات لتحقيق وظائف جديدة. تأتي المرونة الإضافية لتكوين الكائن من القدرة على تغيير التكوين في وقت التشغيل، وهو أمر مستحيل مع تكوين الفئة الثابتة. وسنرى مثال لأنماط التصميم الإنشائية.
لنأخذ على سبيل المثال، محرر رسم يتيح للمستخدمين رسم وترتيب العناصر الرسومية (الخطوط والمضلعات والنص وما إلى ذلك) في الصور والرسوم البيانية. التجريد الرئيسي لمحرر الرسم هو الكائن الرسومي، الذي له شكل قابل للتحرير ويمكنه رسم نفسه. حيث يتم تعريف واجهة الكائنات الرسومية بواسطة فئة مجردة تسمى الشكل. يقوم المحرر بتعريف فئة فرعية من الشكل لكل نوع من الكائنات الرسومية: فئة Line Shape للخطوط، وفئة Polygon Shape للمضلعات، وما إلى ذلك.

  1. ما هو نمط التصميم الإنشائي”Adapter pattern”

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

  1. مشكلة يمكن حلها باستخدام نمط التصميم”Adapter pattern”

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

  1. حل المشكلة باستخدام نمط التصميم”Adapter pattern”

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

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

في بعض الأحيان يكون من الممكن إنشاء محول ثنائي الاتجاه يمكنه تحويل المكالمات في كلا الاتجاهين. 

دعونا نعود إلى تطبيق سوق الأوراق المالية الخاص بنا. لحل معضلة التنسيقات غير المتوافقة، حيث يمكننا إنشاء محولات XML-to-JSON لكل فئة من مكتبة التحليلات التي تعمل معها ونرى أن التعليمات البرمجية الخاصة بنا مباشرةً. ثم نقوم بضبط الكود الخاص بنا للتواصل مع المكتبة فقط عبر هذه المحولات. عندما يتلقى المحول مكالمة، فإنه يُترجم بيانات XML الواردة إلى بنية JSON ويمرر المكالمة إلى الأساليب المناسبة لكائن التحليلات الملتف (wrapped analytics object).

  • تشبيه العالم الحقيقي
    عندما تسافر من الولايات المتحدة إلى أوروبا لأول مرة، قد تتفاجأ عندما تحاول شحن الكمبيوتر المحمول الخاص بك. حيث تختلف معايير قابس ومآخذ الطاقة باختلاف البلدان. لهذا السبب لن يتناسب القابس الأمريكي مع المقبس الألماني. ويمكن حل المشكلة باستخدام محول قابس طاقة يحتوي على مقبس على الطراز الأمريكي ومقبس على الطراز الأوروبي.
  1. بناء نمط التصميم الإبداعي”Adapter design pattern”

محول الكائن (Object adapter)

يُستخدم هذا التنفيذ مبدأ تكوين الكائن حيث يقوم المحول بتنفيذ واجهة أحد الكائنات ولف الكائن الآخر. ويُمكن تنفيذه بجميع لغات البرمجة الشائعة.

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

محول الطبقة (Class adapter)

يُستخدم هذا التنفيذ الوراثة: يرث المحول الواجهات من كلا الكائنين في نفس الوقت. لاحظ أنه لا يمكن تنفيذ هذا الأسلوب إلا في لغات البرمجة التي تدعم الوراثة المتعددة، مثل C++.

  • لا يحتاج محول الفئة إلى تغليف أي كائنات لأنه يرث السلوكيات من كل من العميل والخدمة. يحدث التكيف ضمن الأساليب التي تم تجاوزها حيث يمكن استخدام المحول الناتج بدلاً من فئة العميل الموجودة.
  1. تمثيل نمط التصميم”Adapter design pattern”بشكل كود

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

  1. قابلية نمط التصميم ” Adapter design pattern” للتطبيق
  • نستخدم فئة المحول عندما نريد استخدام بعض الفئات الموجودة، ولكن واجهتها غير متوافقة مع بقية التعليمات البرمجية الخاصة بنا. حيث يتيح لنا نمط المحول إنشاء فئة طبقة متوسطة تعمل كمترجم بين التعليمات البرمجية الخاصة بنا والفئة القديمة أو فئة الجهة الخارجية أو أي فئة أخرى ذات واجهة غريبة.
  • نستخدم النمط عندما نريد إعادة استخدام العديد من الفئات الفرعية الموجودة التي تفتقر إلى بعض الوظائف الشائعة التي لا يمكن إضافتها إلى الفئة الفائقة. حيث يمكننا توسيع كل فئة فرعية ووضع الوظيفة المفقودة في فئات فرعية جديدة. ومع ذلك، سنحتاج إلى تكرار الكود عبر كل هذه الفئات الجديدة، والتي تبدو سيئة للغاية.

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

  1. كيفية تنفيذ نمط التصميم “Adapter design pattern”
  • بداية نتأكد من أن لدينا فئتين على الأقل بواجهات غير متوافقة:

فئة خدمة مفيدة، لا يمكن تغييرها (غالباً ما تكون تابعة لجهة خارجية أو قديمة أو مع الكثير من التبعيات الموجودة) وفئة عميل واحدة أو عدة فئات قد تستفيد من استخدام فئة الخدمة.

  • بعدها نقوم بتعريف واجهة العميل ووصف كيفية تواصل العملاء مع الخدمة.
  • نقوم بإنشاء فئة المحول ونجعلها تتبع واجهة العميل. وسنترك جميع الطرق فارغة في الوقت الحالي.
  • نضيف حقلاً إلى فئة المحول لتخزين مرجع لكائن الخدمة. حيث الممارسة الشائعة هي تهيئة هذا الحقل عبر المنشأ، لكن في بعض الأحيان يكون من الملائم أكثر تمريره إلى المحول عند استدعاء أساليبه.
  • نقوم بتنفيذ كافة أساليب واجهة العميل في فئة المحول واحداً تلو الآخر. حيث يجب أن يقوم المحول بتفويض معظم العمل الحقيقي إلى كائن الخدمة، والتعامل فقط مع الواجهة أو تحويل تنسيق البيانات.
  • يجب على العملاء استخدام المحول عبر واجهة العميل. والذي سيسمح لنا هذا بتغيير المحولات أو توسيعها دون التأثير على رمز العميل.
  1. إيجابيات وسلبيات نمط التصميم”Adapter design pattern”

الإيجابيات:

  • مبدأ المسؤولية الوحيد:

حيث مكننا فصل الواجهة أو كود تحويل البيانات عن منطق العمل الأساسي للبرنامج.

  • مبدأ مفتوح/مغلق:

حيث يمكننا إدخال أنواع جديدة من المحولات في البرنامج دون كسر رمز العميل الحالي، طالما أنها تعمل مع المحولات من خلال واجهة العميل.

السلبيات:

  • يزداد التعقيد العام للكود لأننا نحتاج إلى تقديم مجموعة من الواجهات والفئات الجديدة. في بعض الأحيان حيث يكون من الأسهل تغيير فئة الخدمة بحيث تتطابق مع بقية التعليمات البرمجية الخاصة بنا 
  1. علاقات نمط التصميم ” Adapter design pattern ” مع الأنماط الأخرى
  • عادةً ما يتم تصميم الجسر Bridge مقدماً، مما يتيح لنا تطوير أجزاء من التطبيق بشكل مستقل عن بعضها البعض. من ناحية أخرى، يتم استخدام المحول Adapter بشكل شائع مع تطبيق موجود لجعل بعض الفئات غير المتوافقة تعمل معًا بشكل جيد.
  • يوفر المحول Adapter واجهة مختلفة تماماً للوصول إلى كائن موجود. من ناحية أخرى، مع نمط الديكور Decorator تظل الواجهة كما هي أو يتم توسيعها. بالإضافة إلى ذلك، يدعم Decorator التركيب التكراري، وهو أمر غير ممكن عند استخدام المحول Adapter.
  • باستخدام المحول Adapter، يمكننا الوصول إلى كائن موجود عبر واجهة مختلفة. مع Proxy، تظل الواجهة كما هي. باستخدام Decorator حيث يمكننا الوصول إلى الكائن عبر واجهة محسنة.
  • تحدد Facade واجهة جديدة للكائنات الموجودة، بينما يحاول المحول Adapter جعل الواجهة الحالية قابلة للاستخدام. حيث يقوم المحول عادةً بتغليف كائن واحد فقط، بينما تعمل الواجهة مع نظام فرعي كامل من الكائنات.
  • Bridge, State, Strategy (وإلى حد ما المحول Adapter) لها هياكل متشابهة جداً. في الواقع، كل هذه الأنماط تعتمد على التكوين، وهو تفويض العمل إلى أشياء أخرى. ومع ذلك، فإنهم جميعا يحلون مشاكل مختلفة. النمط ليس مجرد وصفة لتنظيم التعليمات البرمجية الخاصة بنا بطريقة معينة. ويمكنه أيضًا إبلاغ المطورين الآخرين بالمشكلة التي يحلها النمط
  1. الخاتمة

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

وفي الختام، يوفر نمط المحول الفوائد التالية:

التوافق: يسمح للكائنات ذات الواجهات غير المتوافقة بالعمل معاً، مما يعزّز إمكانية التشغيل البيني بين المكونات المختلفة للنظام.

إعادة الاستخدام: تتيح المحولات إعادة استخدام الفئات/الواجهات الموجودة دون الحاجة إلى تعديلات كبيرة. إنها تسمح بدمج التعليمات البرمجية القديمة أو مكتبات الطرف الثالث في الأنظمة الجديدة دون إعادة هيكلة قاعدة التعليمات البرمجية الحالية.

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

التغليف: تقوم المحولات بتغليف منطق التحويل بين الواجهات، مما يجعلها منفصلة عن رمز العميل. وهذا يعزز الفصل النظيف بين الاهتمامات ويحسن جودة التصميم الشاملة للنظام.

باختصار، يعد نمط المحول أداة قيمة لدمج المكونات المتباينة وتعزيز إعادة استخدام التعليمات البرمجية والمرونة والتغليف داخل أنظمة البرمجيات. فهو يتيح التعاون السلس بين المكونات ذات الواجهات المختلفة، مما يسهل تطوير تطبيقات قوية وقابلة للصيانة.

  1. المراجع

https://www.geeksforgeeks.org/adapter-pattern

https://refactoring.guru/design-patterns/adapter

Facebook
Twitter
YouTube
LinkedIn
Instagram