كل ما تحتاج لمعرفته حول المبادئ الصلبة في جافا



في هذه المقالة سوف تتعلم بالتفصيل ما هي المبادئ الصلبة في جافا مع الأمثلة وأهميتها مع مثال واقعي.

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

تاريخ مبادئ SOLID في جافا

قدم روبرت سي مارتن خمسة مبادئ للتصميم الموجه للكائنات ، وتم استخدام اختصار 'S.O.L.I.D' لذلك. عندما تستخدم جميع مبادئ S.O.L.I.D بطريقة مجمعة ، يصبح من الأسهل عليك تطوير برامج يمكن إدارتها بسهولة. الميزات الأخرى لاستخدام S.O.L.I.D هي:





  • يتجنب الروائح البرمجية.
  • بسرعة رمز المنكسر.
  • يمكنه القيام بتطوير برمجيات تكيفية أو رشيقة.

عندما تستخدم مبدأ S.O.L.I.D في الترميز الخاص بك ، فإنك تبدأ في كتابة التعليمات البرمجية التي تتسم بالكفاءة والفعالية.



كيفية استخدام اناكوندا بيثون

ما هو معنى S.O.L.I.D؟

يمثل Solid خمسة مبادئ لجافا وهي:

  • س : مبدأ المسؤولية الواحدة
  • أو : مبدأ مفتوح مغلق
  • إل : مبدأ استبدال Liskov
  • أنا : مبدأ الفصل بين الواجهة
  • د : مبدأ انعكاس التبعية

في هذه المدونة ، سنناقش جميع مبادئ SOLID الخمسة لجافا بالتفصيل.



مبدأ المسؤولية الفردية في جافا

ماذا يقول؟

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

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

يمكن فهم المبدأ جيدًا بمثال. تخيل أن هناك فئة تقوم بالعمليات التالية.

  • متصل بقاعدة بيانات

  • اقرأ بعض البيانات من جداول قاعدة البيانات

  • أخيرًا ، اكتبه في ملف.

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

على سبيل المثال ، يمكن لفئة Automobile بدء أو إيقاف نفسها ولكن مهمة غسلها تنتمي إلى فئة CarWash. في مثال آخر ، تحتوي فئة الكتاب على خصائص لتخزين اسمها ونصها. لكن مهمة طباعة الكتاب يجب أن تنتمي إلى فئة طابعة الكتاب. قد تطبع فئة Book Printer (طابعة الكتب) إلى وحدة تحكم أو وسيط آخر ولكن تتم إزالة هذه التبعيات من فئة Book

لماذا هذا المبدأ مطلوب؟

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

مثال لتوضيح هذا المبدأ:

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

فئة عامة UserSettingService {public void changeEmail (مستخدم مستخدم) {if (checkAccess (user)) {// Grant option to change}} checkAccess منطقية عامة (مستخدم مستخدم) {// تحقق مما إذا كان المستخدم صالحًا. }}

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

فئة عامة UserSettingService {public void changeEmail (مستخدم مستخدم) {if (SecurityService.checkAccess (user)) {// Grant option to change}}} public class SecurityService {public static boolean checkAccess (مستخدم مستخدم) {// check the access. }}

افتح المبدأ المغلق في جافا

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

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

  • الميراث من الفصل

  • الكتابة فوق السلوكيات المطلوبة من الفصل

  • توسيع سلوكيات معينة للفصل

يمكن فهم مثال ممتاز لمبدأ مفتوح مغلق بمساعدة المتصفحات. هل تتذكر تثبيت الملحقات في متصفح Chrome الخاص بك؟

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

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

لماذا هذا المبدأ مطلوب؟

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

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

مستطيل فئة عامة {public double length public double width}

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

فئة عامة AreaCalculator {public double calculateRectangleArea (Rectangle rectangle) {return rectangle.length * rectangle.width}}

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

دائرة الطبقة العامة {public double radius}

ثم نقوم بتعديل Areacalculatorفئة لإضافة حسابات الدائرة من خلال طريقة جديدة calculateCircleaArea ()

فئة عامة AreaCalculator {public double calculateRectangleArea (Rectangle rectangle) {return rectangle.length * rectangle.width} public double calculateCircleArea (Circle Circle) {return (22/7) * circle.radius * Circle.radius}}

ومع ذلك ، لاحظ أنه كانت هناك عيوب في الطريقة التي صممنا بها الحل أعلاه.

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

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

تعديل التصميم أعلاه ليتوافق مع مبدأ الفتح / الإغلاق:

دعونا الآن نرى تصميمًا أكثر أناقة يحل العيوب في التصميم أعلاه من خلال الالتزام بمبدأ Open / Closed. سنجعل التصميم قابلاً للتوسيع أولاً وقبل كل شيء. لهذا نحتاج أولاً إلى تحديد نوع القاعدة Shape ولديك واجهة تطبيق Circle & Rectangle Shape.

شكل الواجهة العامة {public double calculateArea ()} فئة عامة Rectangle implements الشكل {double length double width public double calculateArea () {return length * width}} فئة عامة أدوات دائرة شكل {public double radius public double calculateArea () {return (22 / 7) * نصف قطر * نصف قطر}}

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

فئة عامة AreaCalculator {public double calculateShapeArea (Shape Shape) {return shape.calculateArea ()}}

هذه حاسبة المنطقةتقوم class الآن بإزالة عيوب التصميم المشار إليها أعلاه تمامًا وتعطي حلاً نظيفًا يلتزم بمبدأ Open-Closed. دعنا ننتقل إلى مبادئ SOLID الأخرى في جافا

مبدأ استبدال Liskov في Java

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

يفترض مبدأ استبدال Liskov أن q (x) خاصية ، يمكن إثباتها حول كيانات x التي تنتمي إلى النوع T. الآن ، وفقًا لهذا المبدأ ، يجب الآن إثبات q (y) للكائنات y التي تنتمي إلى النوع S ، و S هو في الواقع نوع فرعي من T. هل أنت مرتبك الآن ولا تعرف ما يعنيه مبدأ استبدال Liskov بالفعل؟ قد يكون تعريفه معقدًا بعض الشيء ، لكنه في الواقع سهل للغاية. الشيء الوحيد هو أن كل فئة فرعية أو فئة مشتقة يجب أن تكون قابلة للاستبدال بفئة الأصل أو الفئة الأساسية.

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

لماذا هذا المبدأ مطلوب؟

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

يتم شرح LSP بشكل شائع باستخدام مثال المربع والمستطيل. إذا افترضنا وجود علاقة ISA بين Square و Rectangle. وبالتالي ، نسمي 'المربع مستطيل'. يمثل الكود أدناه العلاقة.

مستطيل فئة عامة {private int length، private int width، public int getLength () {return length} public void setLength (int length) {this.length = length} public int getBreadth () {return width} public void setBreadth (int width) { this.breadth = breadth} public int getArea () {return this.length * this.breadth}}

يوجد أدناه رمز Square. لاحظ أن المربع يمتد إلى المستطيل.

فئة عامة مربع يمتد المستطيل {public void setBreadth (int width) {super.setBreadth (width) super.setLength (width)} public void setLength (int length) {super.setLength (length) super.setBreadth (length)}}

في هذه الحالة ، نحاول إنشاء علاقة ISA بين Square و Rectangle بحيث يبدأ استدعاء 'Square is a Rectangle' في الكود أدناه في التصرف بشكل غير متوقع إذا تم تمرير مثيل Square. سيتم إلقاء خطأ في التأكيد في حالة التحقق من 'المنطقة' والتحقق من 'النطاق' ، على الرغم من أن البرنامج سينتهي عندما يتم طرح خطأ التأكيد بسبب فشل فحص المنطقة.

فئة عامة LSPDemo {public void calculateArea (Rectangle r) {r.setBreadth (2) r.setLength (3) تأكيد r.getArea () == 6: printError ('area'، r) assert r.getLength () == 3: printError ('length'، r) تأكيد r.getBreadth () == 2: printError ('breadth'، r)} خطأ سلسلة طباعة خاصة (String errorIdentifer، Rectangle r) {إرجاع 'قيمة غير متوقعة لـ' + errorIdentifer + ' على سبيل المثال '+ r.getClass (). getName ()} public static void main (String [] args) {LSPDemo lsp = new LSPDemo () // تم تمرير مثيل المستطيل lsp.calculateArea (new Rectangle ()) // تم تمرير مثيل Square lsp.calculateArea (new Square ())}}

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

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

  1. يجب أن يكون الطول دائمًا مساويًا للطول الذي يتم تمريره كإدخال إلى الطريقة ، setLength
  2. يجب أن يكون العرض دائمًا مساويًا للعرض الذي تم تمريره كمدخل إلى الطريقة setBreadth
  3. يجب أن تكون المساحة دائمًا مساوية لمنتج الطول والعرض

في حالة محاولة إنشاء علاقة ISA بين Square و Rectangle بحيث نسميها 'Square is a Rectangle' ، سيبدأ الرمز أعلاه في التصرف بشكل غير متوقع إذا تم تمرير مثيل Square سيتم طرح خطأ التأكيد في حالة التحقق من المنطقة والتحقق للحصول على اتساع ، على الرغم من أن البرنامج سينتهي عندما يتم طرح خطأ التأكيد بسبب فشل فحص المنطقة.

لا تحتاج فئة Square إلى طرق مثل setBreadth أو setLength. ستحتاج فئة LSPDemo إلى معرفة تفاصيل الفئات المشتقة من Rectangle (مثل Square) للتشفير بشكل مناسب لتجنب حدوث خطأ. التغيير في الكود الحالي يكسر مبدأ Open-Closed في المقام الأول.

مبدأ فصل الواجهة

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

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

على سبيل المثال ، تعد واجهة تسجيل واحدة لكتابة السجلات وقراءتها مفيدة لقاعدة بيانات ولكن ليس لوحدة التحكم. سجلات القراءة لا معنى لها لمسجل وحدة التحكم. المضي قدمًا في مقالة مبادئ SOLID في Java.

لماذا هذا المبدأ مطلوب؟

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

الآن ، دعنا ننشئ واجهة جافا للمطعم ونسميها RestaurantInterface.java.

الواجهة العامة RestaurantInterface {public void acceptOnlineOrder () public void takeTelephoneOrder () public void payOnline () public void walkInCustomerOrder () public void payInPerson ()}

هناك 5 طرق محددة في RestaurantInterface وهي لقبول الطلب عبر الإنترنت ، وتلقي الطلبات الهاتفية ، وقبول الطلبات من العملاء دون حجز مسبق ، وقبول الدفع عبر الإنترنت وقبول الدفع شخصيًا.

لنبدأ بتطبيق RestaurantInterface للعملاء عبر الإنترنت باسم OnlineClientImpl.java

الطبقة العامة OnlineClientImpl تنفذ RestaurantInterface {public void AcceptOnlineOrder () {// logic for put online order} public void takeTelephoneOrder () {// Not Applicable for Online Order throw new UnsupportedOperationException ()} public void payOnline () {// logic for pay online} walkInCustomerOrder () باطل عام {// Not Applicable for Online Order () طرح UnsupportedOperationException ()} public void payInPerson () {// Not Applicable for Online Order throw new UnsupportedOperationException ()}}
  • نظرًا لأن الكود أعلاه (OnlineClientImpl.java) مخصص للطلبات عبر الإنترنت ، قم برمي UnsupportedOperationException.

  • يستخدم العملاء عبر الإنترنت والهاتف والحضور تطبيق RestaurantInterface المخصص لكل منهم.

  • سيكون لفئات التنفيذ الخاصة بالعميل الهاتفي والعميل الفوري طرق غير مدعومة.

  • نظرًا لأن الطرق الخمس هي جزء من RestaurantInterface ، يجب على فئات التنفيذ تنفيذ جميع هذه الطرق الخمس.

  • الطرق التي تطرحها كل فئة من فئات التنفيذ UnsupportedOperationException. كما ترى بوضوح - تنفيذ جميع الأساليب غير فعال.

  • سيتم نشر أي تغيير في أي من أساليب RestaurantInterface لجميع فئات التنفيذ. ثم تبدأ صيانة الكود في أن تصبح مرهقة حقًا وستستمر تأثيرات الانحدار للتغييرات في الزيادة.

    الدمية مقابل الشيف مقابل عامل ميناء
  • يكسر RestaurantInterface.java مبدأ المسؤولية الفردية لأن منطق المدفوعات بالإضافة إلى منطق تقديم الطلب يتم تجميعهما معًا في واجهة واحدة.

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

  1. افصل بين وظائف الدفع ووضع الطلبات في واجهتين منفصلتين ، PaymentInterface.java و OrderInterface.java.

  2. يستخدم كل عميل تطبيقًا واحدًا لكل من PaymentInterface و OrderInterface. على سبيل المثال - يستخدم OnlineClient.java OnlinePaymentImpl و OnlineOrderImpl وما إلى ذلك.

  3. تم إرفاق مبدأ المسؤولية الفردية الآن بواجهة الدفع (PaymentInterface.java) وواجهة الطلب (OrderInterface).

  4. لا يؤثر التغيير في أي من واجهات الطلبات أو واجهات الدفع على الآخر. إنها مستقلة الآن لن تكون هناك حاجة للقيام بأي تنفيذ وهمي أو طرح UnsupportedOperationException لأن كل واجهة لها طرق ستستخدمها دائمًا.

بعد تطبيق ISP

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

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

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

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

لماذا هذا المبدأ مطلوب؟

يسمح للمبرمج بإزالة التبعيات المشفرة بحيث يصبح التطبيق مرتبطًا بشكل غير محكم وقابل للتمديد.

طالب فئة عامة {عنوان خاص عنوان عام طالب () {عنوان = عنوان جديد ()}}

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

بهذا ، نصل إلى نهاية مبادئ SOLID هذه في Java.

تفحص ال من Edureka ، وهي شركة تعليمية موثوقة عبر الإنترنت مع شبكة تضم أكثر من 250000 متعلم راضٍ منتشرين في جميع أنحاء العالم. تم تصميم دورة تدريب وشهادة Java J2EE و SOA من Edureka للطلاب والمهنيين الذين يرغبون في أن يصبحوا مطوري Java. تم تصميم الدورة التدريبية لمنحك السبق في برمجة Java وتدريبك على مفاهيم Java الأساسية والمتقدمة جنبًا إلى جنب مع العديد من أطر Java مثل Hibernate & Spring.

لديك سؤال لنا؟ يرجى ذكر ذلك في قسم التعليقات في مدونة 'SOLID Principles in Java' وسنعاود الاتصال بك في أقرب وقت ممكن.