نمط الواجهة

من موسوعة حسوب

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

المشكلة

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

الحل

ويأتي نمط الواجهة (Facade) هنا كفئة توفر واجهة بسيطة لنظام فرعي معقد يحتوي الكثير من الأجزاء المتحركة، وقد يكون ما يقدمه نمط الواجهة محدودًا مقارنة بالعمل مع النظام الفرعي مباشرة، لكنها ستحتوي فقط على المزايا التي يرغب فيها العملاء.

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

مثال واقعي

ضع الصورة. طلب المنتجات عن طريق الهاتف.

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

البُنية

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

مثال توضيحي

في هذا المثال، يبسط نمط الواجهة التفاعل مع إطار عمل معقد لتحويل الفيديو.

ضع الصورة. مثال لعزل عدة اعتماديات داخل فئة واجهة وحيدة.

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

// هذه بعض من فئات لإطار عمل من طرف ثالث معقد لتحويل الفيديو.
// نحن لا نتحكم في هذه الشيفرة، ولهذا لا نستطيع تبسيطها.

class VideoFile
// ...

class OggCompressionCodec
// ...

class MPEG4CompressionCodec
// ...

class CodecFactory
// ...

class BitrateReader
// ...

class AudioMixer
// ...


// سننشئ فئة واجهة تخفي تعقيد إطار العمل خلف واجهة بسيطة. 
// هذه مقايضة بين الوظيفة والبساطة.
class VideoConverter is
    method convert(filename, format):File is
        file = new VideoFile(filename)
        sourceCodec = new CodecFactory.extract(file)
        if (format == "mp4")
            destinationCodec = new MPEG4CompressionCodec()
        else
            destinationCodec = new OggCompressionCodec()
        buffer = BitrateReader.read(filename, sourceCodec)
        result = BitrateReader.convert(buffer, destinationCodec)
        result = (new AudioMixer()).fix(result)
        return new File(result)

// لا تعتمد فئات التطبيق على ملايين الفئات التي يوفرها إطار العمل المعقد.
// وكذلك، فإن قررت تبديل أطر العمل فلا تحتاج إلا إلى كتابة فئة الواجهة فقط.
class Application is
    method main() is
        convertor = new VideoConverter()
        mp4 = convertor.convert("youtubevideo.ogg", "mp4")
        mp4.save()

قابلية التطبيق

استخدم نمط الواجهة عندما ترغب في واجهة محدودة ومباشرة في نفس الوقت تربطك بنظام فرعي معقد.

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

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

أنشئ واجهات لتعريف نقاط الدخول (entry points) لكل مستوى في نظام فرعي ما، وهكذا تقلل الارتباط بين عدة أنظمة فرعية من خلال إجبارها على التواصل فيما بينها من خلال الواجهات فقط.

فمثلًا، بالعودة إلى مثال إطار العمل الخاص بتحويل الفيديو المذكور أعلاه، فإنك تقسِّمه إلى طبقتين، إحداهما تتعلق بالفيديو والأخرى بالصوت، وتنشئ واجهة لكل طبقة وتجعل فئاتها تتواصل مع فئات الطبقة الأخرى من خلال الواجهات التي أنشأتها. يشبه هذا الأسلوب في تبسيط حل تعقيد المثال أسلوبَ نمط الوسيط (Mediator).

كيفية الاستخدام

  1. تأكد من إمكانية توفير واجهة أبسط من التي يوفرها النظام الفرعي الموجود حاليًا، فإن كانت الواجهة ستجعل شيفرة العميل مستقلة من فئات النظام الفرعي تكون أفضل من واجهة النظام الموجودة.
  2. صرِّح عن هذه الواجهة واستخدمها في فئة واجهة (facade) جديدة، وينبغي لهذه الواجهة أن تعيد توجيه الاستدعاءات من شيفرة العميل إلى الكائنات المناسبة في النظام الفرعي، ويجب أن تكون الواجهة مسؤولة عن بدء النظام الفرعي وإدارة دورة حياته ما لم تكن شيفرة العميل تقوم بهذا فعلًا.
  3. للحصول على أقصى فائدة من النمط، اجعل شيفرة العميل تتواصل مع النظام الفرعي من خلال الواجهة فقط، وهكذا تكون شيفرة العميل محصنة من أي تغيير يحدث في شيفرة النظام الفرعي. فمثلًا حين يحصل نظام فرعي على ترقية إلى إصدار أعلى، فلا تحتاج إلى تغيير شيء سوى الشيفرة التي في الواجهة.
  4. إن أصبحت الواجهة كبيرة جدًا، فابحث إمكانية استخراج جزء من سلوكها إلى فئة واجهة جديدة منقحة.

المزايا والعيوب

المزايا

يمكنك عزل شيفرتك من تعقيد النظام الفرعي.

العيوب

يمكن أن تتحول الواجهة إلى كائن إلهي (God Object) يرتبط بكل الفئات في التطبيق.

العلاقات مع الأنماط الأخرى

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

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

يوضح نمط وزن الذبابة (Flyweight) كيف تصنع الكثير من الكائنات الصغيرة، بينما تشرح الواجهة كيف تصنع كائنًا وحيدًا يمثل نظامًا فرعيًا كاملًا.

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