يتم تنفيذ مبدأ انعكاس التبعية باستخدام. انعكاس التبعية

الصفحة الرئيسية / الشجار

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

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

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

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

فئة عامة Bard (جيتار جيتار خاص ؛ جيتار بارد (جيتار جيتار) (this.guitar = جيتار ؛) لعب باطل عام () (guitar.play () ؛))

الطبقة العامة بارد (

الغيتار الغيتار الخاص

العامة بارد (الغيتار الغيتار)

هذه. الغيتار = الغيتار

لعب الفراغ العام ()

غيتار. لعب()؛

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

ملف الصك. جافا:

أداة الواجهة العامة (تشغيل باطل () ؛)

أداة الواجهة العامة (

voidplay () ؛

ملف الغيتار. جافا:

class Guitar يطبق الآلة (Override public void play () (System.out.println ("Play Guitar!")؛))

فئة الغيتار تنفذ الصك (

@تجاوز

لعب الفراغ العام ()

نظام. خارج . println ("العزف على الجيتار!") ؛

ملف lute.java:

ينفذ العود من الفئة العامة أداة (Override public void play () (System.out.println ("Play Lute!") ؛))

صك العود من الدرجة العامة (

@تجاوز

لعب الفراغ العام ()

نظام. خارج . println ("تشغيل العود!") ؛

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

فئة عامة Bard (أداة خاصة ؛ Bard العامة () () تشغيل باطل عام () (آلة موسيقية () ؛) مجموعة أدوات عامة باطلة (أداة آلة) (this.instrument = آلة ؛))

الطبقة العامة بارد (

أداة خاصة

2 ردود

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

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

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

يحررفقط للتوضيح:

"في مكان ما أرى أيضًا أنه يسمى انعكاس التبعية"

انعكاس:عكس إدارة التبعية من التطبيق إلى الحاوية (مثل الربيع).

حقن التبعية:

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

ماذا عن انعكاس التحكم (IoC)؟

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

يخدم عكس التحكم كدليل تصميم الأغراض التالية:

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

انظر لمزيد من المعلومات.

آخر تحديث: 03/11/2016

مبدأ انعكاس التبعية(مبدأ انعكاس التبعية) يُستخدم لإنشاء كيانات غير مترابطة يسهل اختبارها وتعديلها وتحديثها. يمكن صياغة هذا المبدأ على النحو التالي:

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

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

لفهم المبدأ ، ضع في اعتبارك المثال التالي:

Class Book (public string Text (get؛ set؛) public ConsolePrinter Printer (get؛ set؛) public void Print () (Printer.Print (Text)؛)) class ConsolePrinter (طباعة عامة باطلة (نص سلسلة) (Console.WriteLine (نص)؛ ) )

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

الآن دعونا نحاول جعل فصولنا تتماشى مع مبدأ انعكاس التبعية من خلال فصل التجريدات عن التنفيذ منخفض المستوى:

Interface IPrinter (void Print (string text) ؛) class Book (public string Text (get؛ set؛) public IPrinter Printer (get؛ set؛) public Book (IPrinter printer) (this.Printer = printer؛) public void Print ( ) (Printer.Print (Text) ؛)) فئة ConsolePrinter: IPrinter (طباعة باطلة عامة (نص سلسلة) (Console.WriteLine ("Print to Console") ؛)) class HtmlPrinter: IPrinter (طباعة عامة باطلة (نص سلسلة) ( Console.WriteLine ("طباعة إلى html") ؛))

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

كتاب كتاب = كتاب جديد (new ConsolePrinter ()) ؛ book.Print () ؛ book.Printer = new HtmlPrinter () ؛ book.Print () ؛

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

تم تطوير هذا الوصف بالاشتراك مع Vladimir Matveev استعدادًا للصفوف مع طلاب Java.

مقالات أخرى من هذه السلسلة:

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

أدناه الفئة A داخل عملية تسمى someMethod () تنشئ بشكل صريح كائنًا من الفئة B وتصل إلى طريقتها someMethodOfB ()

فئة عامة A (باطل someMethod () (B b = new B () ؛ b.someMethodOfB () ؛))

وبالمثل ، على سبيل المثال ، تشير الفئة B صراحةً إلى الحقول والطرق الثابتة لفئة النظام:

فئة عامة B (void someMethodOfB () (System.out.println ("Hello world") ؛))

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

ما الخطأ في التبعيات المباشرة؟ التبعيات المباشرة سيئة لأن الفئة التي تنشئ بشكل مستقل فئة أخرى داخل نفسها مرتبطة "بشدة" بهذه الفئة. أولئك. إذا كتب صراحة أن B = new B () ؛ ، إذن ستعمل الفئة A دائمًا مع الفئة B وليس مع أي فئة أخرى. أو إذا كانت تقول System.out.println ("...") ؛ ثم سيخرج الفصل دائمًا إلى System.out وليس في أي مكان آخر.

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

يمكن عرض التبعية المباشرة بيانياً كما يلي:

أولئك. عند إنشاء فئة A في التعليمات البرمجية الخاصة بك: A a = new A () ؛ في الواقع ، لم يتم إنشاء فئة واحدة A ، ولكن يتم إنشاء تسلسل هرمي كامل للفئات التابعة ، ومثال على ذلك في الصورة أعلاه. هذا التسلسل الهرمي "جامد": بدون تغيير التعليمات البرمجية المصدر للفئات الفردية ، لا يمكن استبدال أي من الفئات في التسلسل الهرمي. لذلك ، فإن الفئة أ في مثل هذا التنفيذ غير قابلة للتكيف بشكل جيد مع البيئة المتغيرة. على الأرجح ، لن يكون من الممكن استخدامه في أي كود ، باستثناء الرمز المحدد الذي كتبته من أجله.

لفصل الفئة أ عن التبعيات المحددة ، قم بتطبيق حقن التبعية. ما هو حقن التبعية؟ بدلاً من إنشاء الفئة المطلوبة بشكل صريح في الكود ، يتم تمرير التبعيات إلى الفئة A من خلال المُنشئ:

فئة عامة A (نهائي خاص B b ؛ عام A (B b) (this.b = b ؛) بعض الطرق العامة باطلة () (b.someMethodOfB () ؛))

الذي - التي. تحصل الفئة A الآن على تبعية من خلال المنشئ. الآن ، من أجل إنشاء فئة A ، ستحتاج أولاً إلى إنشاء صنفها التابع. في هذه الحالة ، يكون B:

ب ب = جديد ب () ؛ أ أ = جديد أ (ب) ؛ طريقة واحدة () ؛

إذا تكرر نفس الإجراء لجميع الفصول ، أي قم بتمرير مثيل من الفئة D إلى مُنشئ الفئة B ، إلى مُنشئ الفئة D - تبعياتها E و F ، وما إلى ذلك ، ثم ستحصل على رمز ، يتم إنشاء جميع تبعياته بترتيب عكسي:

G g = جديد G () ؛ ح ح = جديد ح () ؛ F و = جديد (ز ، ح) ؛ E e = جديد E () ؛ د د = جديد د (هـ ، و) ؛ ب ب = جديد ب (د) ؛ أ أ = جديد أ (ب) ؛ طريقة واحدة () ؛

بيانيا ، يمكن عرض هذا على النحو التالي:

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

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

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

© 2022 skudelnica.ru - الحب والخيانة وعلم النفس والطلاق والمشاعر والمشاجرات