المحتوى:
- أنماط التصميم الإنشائية” Structural patterns”
- ما هو نمط التصميم الإنشائي ” Composite design pattern”
- مشكلة يمكن حلها باستخدام نمط التصميم” Composite design pattern”
- حل المشكلة باستخدام نمط التصميم” Composite design pattern”
- بناء نمط التصميم الإنشائي” Composite design pattern”
- تمثيل نمط التصميم ” Composite design pattern”بشكل كود
- قابلية نمط التصميم ” Composite design pattern” للتطبيق
- كيفية تنفيذ نمط التصميم ” Composite design pattern”
- إيجابيات وسلبيات نمط التصميم ” Composite design pattern “
- علاقات نمط التصميم ” Composite design pattern ” مع الأنماط الأخرى
- الخاتمة
- المراجع
- أنماط التصميم الإنشائية”Structural patterns”
الأنماط الهيكلية هي فئة من أنماط التصميم في هندسة البرمجيات. تُركِّز هذه الأنماط على تنظيم الفئات والكائنات المختلفة لتكوين هياكل أكبر وتوفير العلاقات فيما بينها وتهتم الأنماط الهيكلية في المقام الأول بتكوين الفئة وتكوين الكائن. نُفكِّر في كيفية دمج الميراث المتعدد بين فئتين أو أكثر في فئة واحدة. والنتيجة هي فئة تجمع بين خصائص الفئات الأصلية وهناك موضوعان متكرران في هذا النمط:
يُعد هذا النمط مفيداً بشكل خاص لجعل مكتبات الفئات المطورة بشكل مستقل تعمل معاً.
وتصف أنماط التصميم الهيكلي طرقاً لتكوين الكائنات لتحقيق وظائف جديدة. تأتي المرونة الإضافية لتكوين الكائن من القدرة على تغيير التكوين في وقت التشغيل، وهو أمر مستحيل مع تكوين الفئة الثابتة. وسنرى مثال لأنماط التصميم الإنشائية:
لنأخذ على سبيل المثال، محرِّر رسم يتيح للمستخدمين رسم وترتيب العناصر الرسومية (الخطوط والمضلعات والنص وما إلى ذلك) في الصور والرسوم البيانية. التجريد الرئيسي لمحرر الرسم هو الكائن الرسومي، الذي له شكل قابل للتحرير ويمكنه رسم نفسه. حيث يتم تعريف واجهة الكائنات الرسومية بواسطة فئة مجردة تسمى الشكل. يقوم المحرِّر بتعريف فئة فرعية من الشكل لكل نوع من الكائنات الرسومية: فئة Line Shape للخطوط، وفئة Polygon Shape للمضلعات، وما إلى ذلك.
- ما هو نمط التصميم الإنشائي”Composite design pattern”
نمط التصميم المركَّب هو نمط تصميم هيكلي يسمح لنا بتركيب الكائنات في هياكل شبيهة بالشجرة لتمثيل تسلسلات هرمية جزئية كاملة. يُتيح للعملاء التعامل مع الكائنات الفردية وتركيبات الكائنات بشكل موحَّد.
في الأساس، يمكِّننا النمط المركَّب من إنشاء هياكل يتم فيها التعامل مع الكائنات الفردية (الأوراق) وتركيبات الكائنات (الفروع) بشكل موحِّد. يكون هذا النمط مفيداً عندما يكون لدينا كائنات يمكن تركيبها في بنيات أكبر، وتريد التعامل مع هذه الكائنات بشكل موحِّد دون التمييز بين الكائنات الفردية والتراكيب.
على سبيل المثال، فكِّر في بنية هرمية مثل نظام الملفات، حيث يمكن أن تحتوي الأدلة على ملفات أو أدلة أخرى. باستخدام النمط المركب، يمكننا تمثيل كل من الملفات والدلائل بشكل موحِّد، ممَّا يتيح لنا العمل مع البنية بأكملها بطريقة متسقة.
في التنفيذ، يتضمن النمط المركب عادةً إنشاء واجهة مشتركة أو فئة مجردَّة لكل من الكائنات الورقية والمركَّبة. تُمثِّل الكائنات الورقية العناصر الفردية، بينما تُمثِّل الكائنات المركبة الحاويات التي يمكن أن تحتوي على كائنات أخرى. يتفاعل العملاء مع البنية من خلال هذه الواجهة المشتركة، ممَّا يمكنهم من التعامل مع الكائنات والتراكيب الفردية بشكل موحَّد.
- مشكلة يمكن حلها باستخدام نمط التصميم”Composite design pattern”
يُعدُّ استخدام النمط المركب أمراً منطقياً فقط عندما يمكن تمثيل النموذج الأساسي لتطبيقك كشجرة.
على سبيل المثال، تخيَّل أنَّ لديك نوعين من الكائنات: المنتجات والصناديق. يمكن أن يحتوي الصندوق على العديد من المنتجات بالإضافة إلى عدد من الصناديق الصغيرة. يمكن لهذه الصناديق الصغيرة
لنفترض أنَّنا قررنا إنشاء نظام ترتيب يستخدم هذه الفئات. يمكن أن تحتوي الطلبيات على منتجات بسيطة دون أي تغليف، وكذلك الصناديق المحشوة بالمنتجات…وصناديق أخرى. فكيف يمكننا تحديد السعر الإجمالي لمثل هذا الطلب؟
يمكننا تجربة الطريقة المباشرة: حيث نقوم بفك جميع الصناديق، ونقوم بمراجعة جميع المنتجات ثم نقوم بحساب الإجمالي. سيكون ذلك ممكناً في العالم الحقيقي؛ لكن في البرنامج، الأمر ليس بهذه البساطة مثل تشغيل حلقة. علينا أن نعرف فئات المنتجات والصناديق التي تمر بها، ومستوى تداخل الصناديق والتفاصيل السيئة الأخرى مسبقاً. وكل هذا يجعل النهج المباشر إما محرجاً للغاية أو حتى مستحيلاً.
- حل المشكلة باستخدام نمط التصميم”Composite design pattern”
يقترح النمط المركب أنَّنا نعمل مع المنتجات والصناديق من خلال واجهة مشتركة تعلن عن طريقة لحساب السعر الإجمالي.
كيف ستعمل هذه الطريقة؟ بالنسبة للمنتج، فإنَّه ببساطة يعيد سعر المنتج. بالنسبة للصندوق، سيتم مراجعة كل عنصر يحتوي عليه الصندوق، والسؤال عن سعره ثم إرجاع إجمالي هذا الصندوق. إذا كان أحد هذه العناصر عبارة عن صندوق أصغر، فسيبدأ هذا الصندوق أيضاً في مراجعة محتوياته وهكذا، حتى يتم حساب أسعار جميع المكونات الداخلية. يمكن أن يضيف الصندوق بعض التكلفة الإضافية إلى السعر النهائي، مثل تكلفة التغليف.
الفائدة الكبرى من هذا النهج هي أنَّنا لا نحتاج إلى الاهتمام بالفئات الملموسة من الكائنات التي تشكل الشجرة. ولا نحتاج إلى معرفة ما إذا كان المنتج منتجاً بسيطاً أم صندوقاً متطوراً. يمكننا معاملتهم جميعاً بنفس الطريقة عبر الواجهة المشتركة. عند استدعاء أسلوب ما، تقوم الكائنات نفسها بتمرير الطلب إلى أسفل الشجرة.
تشبيه العالم الحقيقي:
يتم تنظيم جيوش معظم البلدان على شكل تسلسل هرمي.حيث يتكَّون الجيش من عدِّة فرق؛ الفرقة عبارة عن مجموعة من الألوية، ويتكون اللواء من فصائل يمكن تقسيمها إلى فرق. وأخيراً، الفرقة هي مجموعة صغيرة من الجنود الحقيقيين. يتم إعطاء الأوامر في أعلى التسلسل الهرمي ويتم تمريرها إلى كل مستوى حتى يعرف كل جندي ما يجب القيام به.
- بناء نمط التصميم الإنشائي”Composite design pattern”
- تصف واجهة المكوِّن (The component interface) العمليات المشتركة بين العناصر البسيطة والمعقَّدة للشجرة.
- تُعتبر الورقة عنصراً أساسياً في الشجرة ولا تحتوي على عناصر فرعية.وعادة، تقوم المكونات الورقية في نهاية المطاف بمعظم العمل الحقيقي، نظراً لعدم وجود أي شخص لتفويض العمل إليه.
- الحاوية (The Container) المعروفة أيضاً باسم المركب وهي عنصر يحتوي على عناصر فرعية: الأوراق أو الحاويات الأخرى. الحاوية لا تعرف الطبقات الملموسة لأبنائها. حيث يعمل مع كافة العناصر الفرعية فقط عبر واجهة المكون فعند تلقي الطلب، تقوم الحاوية بتفويض العمل إلى عناصرها الفرعية، ومعالجة النتائج المتوسطة ثم إرجاع النتيجة النهائية إلى العميل.
- يعمل العميل (The client) مع كافة المكونات من خلال واجهة المكون. ونتيجة لذلك، يمكن للعميل العمل بنفس الطريقة مع كل من العناصر الشجرية البسيطة أو المعقدة.
- تمثيل نمط التصميم”Composite design pattern”بشكل كود.
في هذا المثال، يتيح لنا النمط المركب إمكانية تنفيذ تجميع الأشكال الهندسية في محرر رسومي.
CompoundGraphic عبارة عن حاوية يمكن أن تشتمل على أي عدد من الأشكال الفرعية، بما في ذلك الأشكال المركبة الأخرى. الشكل المركب له نفس طرق الشكل البسيط. ومع ذلك، بدلاً من القيام بشيء ما بمفرده، يقوم الشكل المركب بتمرير الطلب بشكل متكرِّر إلى جميع أبنائه و”يلخص” النتيجة.,يعمل رمز العميل مع كافة الأشكال من خلال واجهة واحدة مشتركة بين جميع فئات الأشكال. وبالتالي، لا يعرف العميل ما إذا كان يتعامل مع شكل بسيط أم مركب. يمكن للعميل العمل مع هياكل كائنات معقدة للغاية دون أن يقترن بفئات محددة تشكل تلك البنية.
- قابلية نمط التصميم “Composite design pattern”للتطبيق
- نستخدم النمط المركب عندما يتعين علينا تنفيذ بنية كائن تشبه الشجرة.يوفِّر لنا النمط المركب نوعين أساسيين من العناصر التي تشترك في واجهة مشتركة: الأوراق البسيطة والحاويات المعقدة. يمكن أن تتكون الحاوية من الأوراق وحاويات أخرى. يتيح لك هذا إنشاء بنية كائن متكررة متداخلة تشبه الشجرة.
- نستخدم النمط عندما نريد أن يتعامل كود العميل مع العناصر البسيطة والمعقدة بشكل موحد حيث تشترك جميع العناصر المحددة بواسطة النمط المركب في واجهة مشتركة. باستخدام هذه الواجهة، لا داعي للقلق بشأن الفئة المحددة للكائنات التي يعمل معها.
- كيفية تنفيذ نمط التصميم “Composite design pattern”
- بداية نتأكد من إمكانية تمثيل النموذج الأساسي لتطبيقه كبنية شجرة.حيث نحاول تقسيمها إلى عناصر وحاويات بسيطة. ونتذكر أنِّ الحاويات يجب أن تكون قادرة على احتواء العناصر البسيطة والحاويات الأخرى.
- نقوم بتعريف واجهة المكون بقائمة من الأساليب المنطقية لكل من المكونات البسيطة والمعقدة.
- نقوم بإنشاء فئة أوراق لتمثيل العناصر البسيطة. قد يحتوي البرنامج على عدة فئات أوراق مختلفة.
- نقوم بإنشاء فئة حاوية لتمثيل العناصر المعقدة. في هذه الفئة، نقوم بتوفير حقل مصفوفة لتخزين المراجع إلى العناصر الفرعية. ويجب أن تكون المصفوفة قادرة على تخزين كل من الأوراق والحاويات، لذا نتأكد من الإعلان عنها باستخدام نوع واجهة المكون. وأثناء تنفيذ أساليب واجهة المكون، ونتذكر أنه من المفترض أن تقوم الحاوية بتفويض معظم العمل إلى العناصر الفرعية.
- وأخيراً، سنحدِّد طرق إضافة وإزالة العناصر الفرعية في الحاوية.
ونضع في اعتبارنا أنَّه يمكن الإعلان عن هذه العمليات في واجهة المكون. وهذا من شأنه أن ينتهك مبدأ فصل الواجهة لأنَّ الأساليب ستكون فارغة في فئة الأوراق. ومع ذلك، سيكون العميل قادراً على التعامل مع جميع العناصر بالتساوي، حتى عند تكوين الشجرة.
- إيجابيات وسلبيات نمط التصميم”Composite design pattern”
الإيجابيات:
- يمكننا العمل مع هياكل الأشجار المعقدة بسهولة أكبر: استخدم تعدد الأشكال والتكرار لصالحك.
- تحقيق مبدأ مفتوح/مغلق.حيث يمكننا إدخال أنواع عناصر جديدة في التطبيق دون كسر التعليمات البرمجية الموجودة، والتي تعمل الآن مع شجرة الكائنات.
السلبيات:
- قد يكون من الصعب توفير واجهة مشتركة للفئات التي تختلف وظائفها كثيراً. في بعض السيناريوهات، سنحتاج إلى الإفراط في تعميم واجهة المكون، مما يجعل فهمها أكثر صعوبة.
- علاقات نمط التصميم”Composite design pattern”مع الأنماط الأخرى
- يمكنك استخدام Builder عند إنشاء أشجار مركبة معقدة (complex Composite trees) لأنَّه يمكنك برمجة خطوات بنائها للعمل بشكل متكرر.
- غالباً ما يتم استخدام سلسلة المسؤولية (Chain of Responsibility) جنباً إلى جنب مع المركب (Composite) في هذه الحالة، عندما يتلقى مكون طرفي طلباً، فقد يمرِّره عبر سلسلة جميع المكونات الأصلية وصولاً إلى جذر شجرة الكائن.
- يمكنك استخدام التكرارات (Iterators) لاجتياز الأشجار المركبة (Composite trees).
- يمكنك استخدام الزائر (Visitor) لتنفيذ عملية على شجرة مركبة بأكملها.
- يحتوي ال Composite & Decorator على مخططات هيكلية متشابهة نظراً لأن كلاهما يعتمد على التركيب التكراري لتنظيم عدد مفتوح من الكائنات حيث يشبه المركب ولكنه يحتوي على مكون فرعي واحد فقط. هناك اختلاف مهم آخر: يضيف برنامج Decorator مسؤوليات إضافية إلى الكائن الملتف، بينما يقوم Composite فقط “بتلخيص” نتائج أطفاله. ومع ذلك، يمكن للأنماط أيضاً أن تتعاون حيث يمكنك استخدام Decorator لتوسيع سلوك كائن معين في الشجرة المركبة.
- الخاتمة
يُعدُّ نمط التصميم المركب نمطاً هيكلياً محوريا في المواقف التي تحتاج فيها إلى التعامل مع الكائنات الفردية وتركيبات الكائنات بشكل موحد. فهو يسمح لنا بتركيب الكائنات في هياكل شجرية لتمثيل تسلسلات هرمية جزئية وكاملة، مما يمكّن العملاء من التعامل مع الكائنات الفردية وتركيبات الكائنات بنفس الطريقة.
وفي الختام، يُعدُّ نمط التصميم المركب أداة قوية في هندسة البرمجيات لإدارة الهياكل الهرمية بطريقة فعالة ومبسطة. عند استخدامه بشكل مناسب، فإنه يمكن أن يعزز بشكل كبير نمطية التطبيق وقابليته للتوسع. ومع ذلك، من المهم تقييم قابلية تطبيقه بناءً على الاحتياجات والقيود المحددة للمشروع لتجنب التعقيد غير الضروري أو عقوبات الأداء.
12.المراجع
https://refactoring.guru/design-patterns/composite