سؤال

ما هو مبدأ انعكاس التبعية ولماذا هو مهم؟

هل كانت مفيدة؟

المحلول

تحقق من هذه الوثيقة: مبدأ انعكاس التبعية.

يقول في الأساس:

  • لا ينبغي أن تعتمد الوحدات عالية المستوى على الوحدات ذات المستوى المنخفض.وكلاهما يجب أن يعتمد على التجريدات.
  • لا ينبغي أن تعتمد التجريدات أبدًا على التفاصيل.التفاصيل يجب أن تعتمد على التجريدات.

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

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

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

نصائح أخرى

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

لتقديم ملخص، فإن مبدأ انعكاس التبعية يدور في المقام الأول حول عكس الاتجاه التقليدي للتبعيات من مكونات "المستوى الأعلى" إلى مكونات "المستوى الأدنى" بحيث تعتمد مكونات "المستوى الأدنى" على الواجهات مملوكة بواسطة مكونات "المستوى الأعلى".(ملحوظة:يشير المكون "المستوى الأعلى" هنا إلى المكون الذي يتطلب تبعيات/خدمات خارجية، وليس بالضرورة موقعه المفاهيمي داخل بنية الطبقات.) عند القيام بذلك، لا يكون الاقتران كذلك مخفض بقدر ما هو عليه تحول من المكونات الأقل قيمة من الناحية النظرية إلى المكونات الأكثر قيمة من الناحية النظرية.

يتم تحقيق ذلك من خلال تصميم المكونات التي يتم التعبير عن تبعياتها الخارجية من حيث الواجهة التي يجب توفير التنفيذ لها من قبل مستهلك المكون.بمعنى آخر، تعبر الواجهات المحددة عما يحتاجه المكون، وليس كيفية استخدامك للمكون (على سبيل المثال."INeedSomething"، وليس "IDoSomething").

ما لا يشير إليه مبدأ انعكاس التبعية هو الممارسة البسيطة المتمثلة في تجريد التبعيات من خلال استخدام الواجهات (على سبيل المثال.MyService → [ILogger ⇐ Logger]).في حين أن هذا يفصل مكونًا عن تفاصيل التنفيذ المحددة للتبعية، إلا أنه لا يعكس العلاقة بين المستهلك والتبعية (على سبيل المثال.[MyService → IMyServiceLogger] ⇐ المسجل.

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

ضمن هذا الهدف العام لإعادة الاستخدام، يمكننا تحديد نوعين فرعيين من إعادة الاستخدام:

  1. استخدام مكون برمجي ضمن تطبيقات متعددة مع تطبيقات التبعية الفرعية (على سبيل المثال.لقد قمت بتطوير حاوية DI وترغب في توفير التسجيل، ولكن لا تريد ربط الحاوية الخاصة بك بمسجل محدد بحيث يتعين على كل شخص يستخدم الحاوية الخاصة بك أن يستخدم أيضًا مكتبة التسجيل التي اخترتها).

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

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

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

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

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

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

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

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

ينص مبدأ انعكاس التبعية على ما يلي:

  • لا ينبغي أن تعتمد الوحدات عالية المستوى على الوحدات ذات المستوى المنخفض.وكلاهما يجب أن يعتمد على التجريدات.
  • لا ينبغي أن تعتمد التجريدات على التفاصيل.التفاصيل يجب أن تعتمد على التجريدات.

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

بالنسبة لي، مبدأ عكس التبعية، كما هو موضح في المادة الرسمية, ، هي في الواقع محاولة مضللة لزيادة إمكانية إعادة استخدام الوحدات النمطية التي تكون بطبيعتها أقل قابلية لإعادة الاستخدام، بالإضافة إلى أنها طريقة لحل مشكلة في لغة C++.

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

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

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

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

العمارة التقليدية ذات الطبقات

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

http://xurxodev.com/content/images/2016/02/Traditional-Layered.png

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

سيكون لدينا مكتبة أو حزمة لطبقة الوصول إلى البيانات.

// DataAccessLayer.dll
public class ProductDAO {

}

ومكتبة أخرى أو منطق عمل طبقة الحزمة يعتمد على طبقة الوصول إلى البيانات.

// BusinessLogicLayer.dll
using DataAccessLayer;
public class ProductBO { 
    private ProductDAO productDAO;
}

بنية الطبقات مع انعكاس التبعية

يشير انعكاس التبعية إلى ما يلي:

لا ينبغي أن تعتمد الوحدات عالية المستوى على الوحدات ذات المستوى المنخفض.كلاهما يجب أن يعتمد على التجريدات.

لا ينبغي أن تعتمد التجريدات على التفاصيل.التفاصيل يجب أن تعتمد على التجريدات.

ما هي الوحدات ذات المستوى العالي والمستوى المنخفض؟وحدات التفكير مثل المكتبات أو الحزم، الوحدات عالية المستوى هي تلك التي لها تبعيات تقليديًا والمستوى المنخفض الذي تعتمد عليه.

بمعنى آخر، سيكون المستوى العالي للوحدة هو المكان الذي يتم فيه استدعاء الإجراء والمستوى المنخفض حيث يتم تنفيذ الإجراء.

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

تخيل أننا قمنا بتعديل الكود الخاص بنا على النحو التالي:

سيكون لدينا مكتبة أو حزمة لطبقة الوصول إلى البيانات التي تحدد التجريد.

// DataAccessLayer.dll
public interface IProductDAO
public class ProductDAO : IProductDAO{

}

ومكتبة أخرى أو منطق عمل طبقة الحزمة يعتمد على طبقة الوصول إلى البيانات.

// BusinessLogicLayer.dll
using DataAccessLayer;
public class ProductBO { 
    private IProductDAO productDAO;
}

على الرغم من أننا نعتمد على التبعية التجريدية بين الأعمال والوصول إلى البيانات، إلا أنها تظل كما هي.

http://xurxodev.com/content/images/2016/02/Traditional-Layered.png

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

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

// Domain.dll
public interface IProductRepository;

using DataAccessLayer;
public class ProductBO { 
    private IProductRepository productRepository;
}

بعد أن تعتمد طبقة الثبات على المجال، سيتم عكسها الآن إذا تم تعريف التبعية.

// Persistence.dll
public class ProductDAO : IProductRepository{

}

http://xurxodev.com/content/images/2016/02/Dependency-Inversion-Layers.png

تعميق المبدأ

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

لكن لماذا نقلب التبعية؟ما هو الهدف الرئيسي وراء أمثلة محددة؟

مثل هذا عادة يسمح للأشياء الأكثر استقرارًا، التي لا تعتمد على أشياء أقل استقرارًا، بالتغيير بشكل متكرر.

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

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

أبنية

هناك بنيات يكون فيها انعكاس التبعية هو المفتاح لتعريفها.في جميع المجالات هو الأهم وهو التجريد الذي سيشير إلى بروتوكول الاتصال بين المجال وبقية الحزم أو المكتبات المحددة.

العمارة النظيفة

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

العمارة السداسية

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

في الأساس تقول:

يجب أن تعتمد الفئة على التجريدات (مثل الواجهة والفئات المجردة)، وليس على تفاصيل محددة (التطبيقات).

هناك طريقة أكثر وضوحًا لتوضيح مبدأ انعكاس التبعية وهي:

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

أي بدلاً من تنفيذ صفك Logic كما يفعل الناس عادة:

class Dependency { ... }
class Logic {
    private Dependency dep;
    int doSomething() {
        // Business logic using dep here
    }
}

يجب عليك أن تفعل شيئا مثل:

class Dependency { ... }
interface Data { ... }
class DataFromDependency implements Data {
    private Dependency dep;
    ...
}
class Logic {
    int doSomething(Data data) {
        // compute something with data
    }
}

Data و DataFromDependency يجب أن يعيش في نفس الوحدة النمطية مثل Logic, ، ليس مع Dependency.

لماذا فعل هذا؟

  1. تم الآن فصل وحدتي منطق الأعمال.متى Dependency التغييرات، لا تحتاج إلى التغيير Logic.
  2. فهم ماذا Logic هل هي مهمة أبسط بكثير:إنه يعمل فقط على ما يشبه ADT.
  3. Logic يمكن الآن اختبارها بسهولة أكبر.يمكنك الآن إنشاء مثيل مباشرة Data ببيانات وهمية وتمريرها.لا حاجة للنماذج أو سقالات الاختبار المعقدة.

الإجابات الجيدة والأمثلة الجيدة مقدمة بالفعل من قبل الآخرين هنا.

السبب تراجع المهم هو أنه يضمن مبدأ OO "التصميم المترابط بشكل فضفاض".

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

تريد أن تكون كائنات "المستوى الأعلى" الخاصة بك مستقرة جدًا وغير قابلة للتغيير، لذلك تحتاج إلى عكس التبعيات.

قلب السيطرة (IoC) هو نمط تصميم حيث يتم تسليم كائن ما تبعيته من خلال إطار عمل خارجي، بدلاً من طلب إطار عمل لتبعيته.

مثال على الكود الزائف باستخدام البحث التقليدي:

class Service {
    Database database;
    init() {
        database = FrameworkSingleton.getService("database");
    }
}

رمز مماثل باستخدام IoC:

class Service {
    Database database;
    init(database) {
        this.database = database;
    }
}

فوائد IoC هي:

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

الهدف من انعكاس التبعية هو إنشاء برامج قابلة لإعادة الاستخدام.

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

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

تخيل هذا الكود الزائف..

public class MyClass
{
  public Service myService = ServiceLocator.service;
}

يعتمد MyClass بشكل مباشر على كل من فئة الخدمة وفئة ServiceLocator.فهو يحتاج إلى كليهما إذا كنت تريد استخدامه في تطبيق آخر.والآن تخيل هذا...

public class MyClass
{
  public IService myService;
}

الآن، يعتمد MyClass على واجهة واحدة، وهي واجهة IService.لقد سمحنا لحاوية IoC بتعيين قيمة هذا المتغير بالفعل.

والآن، يمكن بسهولة إعادة استخدام MyClass في مشاريع أخرى، دون جلب تبعيات هاتين الفئتين الأخريين معه.

والأفضل من ذلك، أنك لا تحتاج إلى سحب تبعيات MyService، وتبعيات تلك التبعيات، و...جيد، لقد وصلتك الفكرة.

انقلاب حاويات التحكم ونمط حقن التبعية بقلم مارتن فاولر قراءة جيدة أيضًا.وجدت رئيس أنماط التصميم الأول كتاب رائع لأول تجربة لي في تعلم DI والأنماط الأخرى.

انعكاس التبعية:تعتمد على التجريدات، وليس على الخرسانة.

قلب السيطرة:الرئيسي مقابل التجريد، وكيف أن الرئيسي هو الغراء للأنظمة.

DIP and IoC

هذه بعض المشاركات الجيدة التي تتحدث عن هذا:

https://coderstower.com/2019/03/26/dependency-inversion-why-you-shouldnt-avoid-it/

https://coderstower.com/2019/04/02/main-and-abstraction-the-decoupled-peers/

https://coderstower.com/2019/04/09/inversion-of-control-putting-all-together/

مبدأ انعكاس التبعية (DIP) يقول ذلك

ط) لا ينبغي أن تعتمد الوحدات عالية المستوى على الوحدات ذات المستوى المنخفض.وكلاهما يجب أن يعتمد على التجريدات.

2) لا ينبغي أن تعتمد التجريدات أبدًا على التفاصيل.التفاصيل يجب أن تعتمد على التجريدات.

مثال:

    public interface ICustomer
    {
        string GetCustomerNameById(int id);
    }

    public class Customer : ICustomer
    {
        //ctor
        public Customer(){}

        public string GetCustomerNameById(int id)
        {
            return "Dummy Customer Name";
        }
    }

    public class CustomerFactory
    {
        public static ICustomer GetCustomerData()
        {
            return new Customer();
        }
    }

    public class CustomerBLL
    {
        ICustomer _customer;
        public CustomerBLL()
        {
            _customer = CustomerFactory.GetCustomerData();
        }

        public string GetCustomerNameById(int id)
        {
            return _customer.GetCustomerNameById(id);
        }
    }

    public class Program
    {
        static void Main()
        {
            CustomerBLL customerBLL = new CustomerBLL();
            int customerId = 25;
            string customerName = customerBLL.GetCustomerNameById(customerId);


            Console.WriteLine(customerName);
            Console.ReadKey();
        }
    }

ملحوظة:يجب أن يعتمد الفصل على تجريدات مثل الواجهة أو الفئات المجردة، وليس على تفاصيل محددة (تنفيذ الواجهة).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top