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

ننتقل إلى "توفق الأرفف" لنهج التصميم أعلاه.
مبدأ المسؤولية الفردية (SRP) مبدأ المسؤولية الوحيد
يجب تغيير قطعة واحدة من التعليمات البرمجية فقط أثناء تنفيذ هدف واحد. إذا قام قسم من التعليمات البرمجية بتنفيذ مهمتين وتغييرات لاستخدامات مختلفة ، فيجب عليك تكرار هذا القسم في مثيل لكل غرض. هذا مهم للغاية لأنه يتطلب الخروج عن المبدأ المقبول عمومًا وهو القضاء على الازدواجية.
الغرض من هذا المبدأ هو إزالة الأخطاء الضمنية التي تم تقديمها نظرًا لوجود المتغيرات التالية لتطوير قسم الكود أو الإجراء أو الفئة أو المكون (المشار إليه فيما يلي ، يتم استخدام المصطلح [المكون] لدمج هذه المفاهيم):
- [1] مكتوب بشكل صحيح [مكون] يستخدم بالضرورة وغالبًا ما يكون عدة مرات ،
- [2] في كل مكان من الاستخدام ، من المتوقع أن يحافظ [المكون] على سلوك ثابت يؤدي إلى نتيجة قابلة للتكرار ،
- [3] عند استخدام [المكون] في عدة أماكن ، يجب أن تلبي النتيجة كل مكان للاستخدام ،
- إذا كان التغيير في [المكون] مطلوبًا لأحد أماكن الاستخدام ، وكان السلوك السابق لـ [المكون] مطلوبًا في مكان آخر للاستخدام ، فيجب إنشاء نسخة من [المكون] مع التعديل اللاحق (أو تعميم [المكون] بمعلمات إضافية توفر سلوكًا مختلفًا) ،
إذا كانت هناك أماكن لاستخدام [المكون] ليست مهمة للمهمة الحالية التي حلها المبرمج ، فمن السهل جدًا عليه أن ينسى التحقق من التوافق مع أماكن استخدام التغييرات التي تمت على هذا [المكون].
لذلك ، يجب أن تكون جميع أماكن الاستخدام في منطقة [مسؤولية واحدة] من مسؤولية واحدة ، أي ، يجب تغييرها وأخذها في الاعتبار مرة واحدة لأي مشكلة يحلها المبرمج).
ينطبق المبدأ على قسم من التعليمات البرمجية وعلى مكون ، مكتبة ، برنامج ، مجموعة من البرامج المستخدمة في عدة أماكن.
تقدم العديد من المصادر مثالاً للفئة ذات "دالة" واحدة فقط كمثل مثالي لـ SRP وفئة "كائن إلهي" ، تجمع بين جميع وظائف التطبيق ، كمضاد. فئة IMHO ذات "دالة" واحدة فقط هي شرط لتحسين سرعة إنشاء بنية الشفرة ، مع المطالبة بكتابة العديد من الفئات (كيانات الكود) من الصفر ، مع نسيان أن عدم وجود أكثر من مكان استخدام يسمح للمبرمج بإجراء تقييم سريع لمقدار صغير موجود محليًا (في فصل واحد) كود التفاعل من تحليل العلاقات الخارجية لكيانات الكود المتباينة المسؤولة عن "وظيفتها". لا يعد "الكائن الإلهي" للتطبيق الصغير أيضًا جريمة قوية - فهو يسمح لك ببدء التطوير: تحديد جميع الكيانات اللازمة ، وكتابتها جنبًا إلى جنب ، منفصلة عن الكائنات الخارجية للمكتبة القياسية والوحدات الخارجية (إنشاء خلية حية وفصلها بغشاء). في عملية نمو وتطوير المشروع ، هناك العديد من الطرق التي تساعد على اتباع برنامج التقويم الاستراتيجي ، واحدة منها هي التقسيم إلى فصول وتقليل عدد "الوظائف" التي يتحملها كل فصل (تقسيم الخلية وتخصصها في الجسم).
هنا أود أن أكتب مجموعة من التقنيات للحفاظ على برنامج التقويم الاستراتيجي ، لكن هذا العمل لم يكتمل بعد (آمل أن "تصل اليدين"). من المناطق الواضحة حيث يمكنك البحث عن هذه الحيل:
- أنماط التصميم
- باستخدام مختلف فروع المكونات المتخصصة ، بدلاً من إنشاء مكون يرضي جميع أساليب التطبيق (شوكة على جيثب).
مبدأ مفتوح مغلق (OCP) مبدأ مفتوح / مغلق
من الأفضل تخطيط تطوير الكود بحيث يكون للمبرمجين تنفيذ مهام جديدة ضروري لإضافة كود جديد ، بينما لا يلزم تغيير الكود القديم. يجب أن يكون الرمز مفتوحًا (مفتوح) للإغلاق والإغلاق (مغلق) للتغيير.
الغرض من هذا المبدأ هو تقليل تكاليف العمالة إلى أدنى حد والقضاء على الأخطاء الضمنية التي تم إدخالها نتيجة للثوابت التالية في التنمية:
- [1] ، [2] ، [3] الموصوفة سابقًا ،
- لتنفيذ مهمة جديدة ، يمكن للمبرمج إضافة [مكونات] جديدة أو تغيير سلوك [المكونات] القديمة ،
- تتطلب إضافة [المكون] التحقق في مكان الاستخدام الجديد ، وتكلف وقت المبرمج
- يتطلب التغيير في سلوك [المكون] الناجم عن المهمة الجديدة التحقق في مكان الاستخدام الجديد وفي جميع أماكن الاستخدام القديم ، مما يتسبب أيضًا في استهلاك مبرمج الوقت ، وفي حالة [المكون] المنشور ، عمل جميع المبرمجين الذين استخدموا [المكون].
من المستحسن اختيار خيار لتنفيذ مهمة جديدة مع تقليل الوقت الذي يقضيه المبرمج.
في كثير من الأحيان في ممارسة تطوير البرمجيات ، تكون تكلفة الإضافة أقل بكثير من تكلفة التغيير ، مما يجعل استخدام مبدأ [مفتوح مغلق] واضحًا. في الوقت نفسه ، هناك الكثير من التقنيات للحفاظ على بنية البرنامج في حالة حيث يتم تنفيذ مهمة جديدة لإضافة [مكونات] فقط. يتطلب هذا العمل مع الهندسة المعمارية أيضًا وقتًا للمبرمجين ، لكن الممارسة في المشروعات الكبيرة تظهر أقل بكثير من استخدام نهج تغيير الإجراءات القديمة. وبطبيعة الحال ، فإن هذا الوصف للتطوير هو الكمال. لا يوجد أي تنفيذ تقريبًا للمهمة بمجرد إضافة أو تغيير فقط. في الحياة الواقعية ، يتم استخدام مزيج من هذه الأساليب ، ولكن يؤكد OCP على الاستفادة من استخدام أسلوب الإضافة.
وهنا أود أن أكتب مجموعة من التقنيات للحفاظ على OCP. من المناطق الواضحة حيث يمكنك البحث عن هذه الحيل:
- أنماط التصميم
- مكتبات dll وخيارات توزيعها وتحديثها وتطوير وظائفها ؛
- تطوير مكتبات COM والأشياء الموجودة فيها ؛
- تطوير لغات البرمجة ودعم الكود المكتوب مسبقًا ؛
- تطوير النظام التشريعي للدولة.
مبدأ استبدال Liskov (LSP) مبدأ استبدال Liskov Barbara
يحد هذا المبدأ من استخدام امتداد الواجهة الأساسية [الأساس] في التنفيذ ، مع الإشارة إلى أن كل تطبيق للواجهة الأساسية يجب أن يكون سلوكًا كواجهة أساسية. في الوقت نفسه ، تعمل الواجهة الأساسية على إصلاح السلوك المتوقع في أماكن استخدامه. ووجود اختلاف في سلوك التنفيذ عن السلوك المتوقع ، الذي تحدده الواجهة الأساسية ، سيؤدي إلى احتمال انتهاك المتغير [2].
ويستند هذا المبدأ ويحسن تقنية التصميم على أساس التجريد. في هذا النهج ، يتم تقديم التجريد - يتم إصلاح بعض الخصائص الأساسية وخصائص السلوك للعديد من الحالات. على سبيل المثال ، [إجراء المكون] "الانتقال إلى الموضع السابق" للحالات: "المؤشر في النص" ، "الكتاب على الرف" ، "العنصر في صفيف" ، "القدم في الرقص" ، وما إلى ذلك والمخصص لهذا [المكون] ( غالبًا عن طريق التجربة اليومية وبدون إضفاء الطابع الرسمي) بعض الشروط والسلوكيات ، على سبيل المثال: "وجود كائن متحرك" ، "تكرار عدة مرات" ، "وجود ترتيب العناصر" ، "وجود مواضع ثابتة للعناصر". يتطلب LSP أنه عند إضافة حالة استخدام جديدة لـ [المكون] يتم استيفاء جميع الشروط والقيود الأساسية. ولا يمكن وصف حالة "الحبوب في علبة السكر" بهذا التجريد ، على الرغم من أن الحبوب ، بالطبع ، لها وضعية ، وهناك مواقف كانت فيها الحبوب من قبل ، ومن الممكن تحريكها فيها - لا يوجد سوى مواقع ثابتة للعناصر.
الغرض من هذا المبدأ هو إزالة الأخطاء الضمنية التي تم تقديمها نتيجة للمخترعين التاليين في التطوير:
- [1] ، [2] ، [3] الموصوفة سابقًا ،
- يصف [الإجراء] الأساسي السلوك الذي يكون مفيدًا في عدد كبير من المواقف ، مع تحديد القيود المطلوبة للتطبيق ،
يجب أن يفي [الإجراء] المطوَّر لتنفيذ القاعدة بكل قيوده ، بما في ذلك القيود الضمنية ذات المسار الصعب (المقدمة بشكل غير رسمي).
في كثير من الأحيان ، يتم إعطاء مثال مع مستطيل ([قاعدة]) ومربع (تنفيذ) لوصف هذا المبدأ. class CSquare : public CRectangle
الحالة class CSquare : public CRectangle
. في [الأساس] ، يتم تقديم عمليات العمل مع العرض والارتفاع (Set (Get) Width ، Set (Get) Height). في تطبيق CSquare ، تُجبر عمليات Set هذه على تغيير أحجام الكائن. لقد افتقرت دائمًا إلى التفسير الذي يفيد بأن التقييد التالي قد تم تعيينه "بشكل غير رسمي" في [القاعدة]: "القدرة على استخدام العرض والارتفاع بشكل مستقل." في تطبيق CSquare ، يتم انتهاكه ، وفي أماكن الاستخدام تسلسل بسيط من الإجراءات بناءً على استخدام هذا الاستقلال: r.SetWidth(r.GetWidth()*2); r.SetHeight(r.GetHeight()*2)
r.SetWidth(r.GetWidth()*2); r.SetHeight(r.GetHeight()*2)
- للتنفيذ ، سيزيد CSquare كلا الأحجام بمقدار 4 مرات ، بدلاً من 2 مرات مفترضًا CRectangle.
IMHO يشير هذا المبدأ إلى صعوبة تتبع هذه القيود غير الرسمية ، والتي ، مع فائدة كبيرة وتيرة عالية لاستخدام نهج التنمية "التنفيذ الأساسي" يتطلب اهتماما خاصا.
مبدأ فصل الواجهة (ISP) مبدأ فصل الواجهات ؛ مبدأ انعكاس التبعية (DIP) مبدأ انعكاس التبعية
هذان المبدأان قريبان جدًا في مجال متطلباتهم. كلاهما يتضمن ضمنيًا فائدة استخدام أصغر واجهة أساسية ممكنة كأداة للتفاعل بين عنصرين: "العميل" و "الخادم" - يتم اختيار هذه الأسماء ببساطة لتحديد الهوية. في هذه الحالة ، تتركز المعلومات العامة المستخدمة من قبل [المكونات] في الواجهة الأساسية. واحد [مكون] ("خادم") ينفذ تطبيق الواجهة الأساسية ، ويشير الآخر [مكون] ("عميل") إلى هذا التطبيق.
الهدف من هذه المبادئ هو تقليل تبعيات المكون ، والسماح بإجراء تغييرات مستقلة على الكود الخاص بها إذا لم يغير الواجهة الأساسية. يقلل استقلالية تغييرات المكونات من التعقيد والعمالة إذا كانت المكونات تفي بمتطلبات مبدأ SRP. من الممكن اتباع نهج مشابه لأن المتغيرات التالية موجودة في التطوير:
- [1] ، [2] ، [3] الموصوفة سابقًا ،
- كل [مكون] متأصل في سلوكه يشكل حدود استخدامه ،
- في كل مكان من استخدام [المكون] قد تكون جميع القيود الخاصة به متورطة ،
- النتيجة [المكون] الأساسية للتعريف أقل تعقيدًا وعدد القيود من تنفيذ [المكون] ،
- أي تغيير في [مكون] يغير حدوده ويتطلب التحقق من جميع أماكن استخدامه ، مما يتسبب في إنفاق مبرمج الوقت ،
أماكن استخدام القاعدة [المكون] لا تتطلب التحقق بعد إجراء تغييرات على تطبيق [المكون].
من الواضح أنه من المستحسن تقليل "حجم" الواجهة الأساسية عن طريق تجاهل الوظائف والقيود غير المستخدمة ، وبالتالي الحد من [المكون] التنفيذ بمبدأ (LSP) أقل
يؤكد مبدأ مزود خدمة الإنترنت على الحاجة إلى الفصل (الفصل) لواجهة "الخادم" ، إن لم يكن يتم استخدام جميع وظائفه المنشورة من قبل هذا "العميل". في هذه الحالة ، يتم تخصيص [الأساس] فقط المطلوبة من قبل العميل ويتم ضمان الحد من المعلومات تقييد مشترك.
وهنا أود أن أكتب مجموعة من التقنيات للحفاظ على DIP. من المناطق الواضحة حيث يمكنك البحث عن هذه الحيل:
- فصل وصف الفصل إلى أجزاء عامة وخاصة (وغيرها من مبادئ OOP) ،
- وصف للتفاعل مع مكتبة ديناميكية مع مجموعة محدودة من الوظائف واصفات الكائن ،
- باستخدام خزانة الملفات كواجهة للوصول إلى مكتبة الكتب.
بالعودة إلى العنوان ، سأشرح لماذا يتم اختيار "لا يفهم". يتم إضافة النفي من أجل التأكيد من قبل الأخطاء التي طال أمدها وقاعدة IMHO مفيدة للغاية. من الأفضل عدم فهم التكنولوجيا وبالتالي عدم استخدامها ، بدلاً من سوء الفهم ، أخذها على عقيدة ، إنفاق مواردك على تطبيق التكنولوجيا ونتيجة لذلك لا تحصل على أي استنفاد مفيد باستثناء الرضا عن النفس وإمكانية التفاخر بالمشاركة في التكنولوجيا العصرية.
شكرا لاهتمامكم
مراجع