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

أحمد رمضان

. 4 د قراءة

بما إن كذا حد كلمني وقاللي إنه مش فاهم حتة Registering a User و الي موجوده هنا

فقررت أرجع أوضّح النقطة دي بسرعة كده 

(الاتنين تلاتة الي بخليهم يقرأو عافية و يقولولي رأيهم ) ف لو عاوز تبقي منهم ممكن تكلمني برضه 




المهم 


لازم لازم لازم تقرا الي فات من هنا علشان تفهم ال Abstraction  الي موجوده هنا بعدين تيجي نكمل سوا
ملحوظة: مش هنغوص دلوقتي في شرح الـ Repository Pattern لأنه مشروح بالتفصيل في Chapter 2، لكن خلينا نعمل مقدمة سريعة على شوية مفاهيم أساسية:


Inversion of Control (IoC)Dependency Injection (DI)Dependency Inversion Principle (DIP)

تعالي نتكلم عن نفس المثال 


أولا : عندي Interface اسمه ConnectionInterface


السؤال هل ال interface يقدر يشتغل لوحده طبعا لأ 

الـ Interface ده مجرد "عقد" بيقول إن أي class هيورث منه لازم يكون فيه ميثود اسمها insert().

و هينفذ الي هيحصل جوه ال class 


ثانيا هنكتب الclass الي هنفذ الي جواه زي م اتفقنا 

يبقي الوقتي لما اروح أ call ال ConnectionInterface و من خلاله أ call ال method (insert)

هيروح يطبق الي داخل الclass (ConnectionDummy)


ف هنيجي للنطقة دي بقا و هيه ماذا لو كان عندي 

SqlConnection class 

و بعمل implements لل ال Interface

و قتها هيطبق ال method (insert)

و لكن الي موجودة ف الConnectionSql 


و هكذا بقا و دا الي كنت اقصده بكلامي هنا ف المقالة الي فاتت

و بكدا نكون حققنا مبدأ ال abstraction كويس اوي 


تعالي بقا ل موضوعنا الاصلي و قبل م نبدأ لازم نجيب مثود ال registration و نشرحها خلف الكواليس 




اقرأ المثود  ب ال class و ركز معايا اوي اوي اوي اوي 


السؤال الاول : ازاي هعرف اربط ال interface مع ال class ؟؟؟؟؟؟؟


لو انتا بتستخدم laravel ف انتا هتستخدم ال service providor 

و لو انتا بستخدم Type Script هتعملها يدوي 

و اخيرا spring boot هتعملها بطريقة @service و ال autowired


بس انا هتكلم عن laravel 


السؤال التاني : اي هوه بقا ال Inversion of Control ؟؟؟؟؟؟؟؟؟؟


"ما تمسكش بيدك الحاجات الـ Low-Level، وسيب الـ High-Level هي اللي تطلب اللي محتاجاه."


يعني بدل ما الكلاس يروح بنفسه يعمل

new ConnectionSql()

أو new ConnectionDummy()



سيبه يطلب بس الحاجة اللي هو محتاجها، واللي يديهاله هو الـ Framework أو الـ Container.

وهو ده بالضبط اللي عملناه جوه الـ ServiceProvider

هل هيربط  التلاتة هقولك لأ طبع بص ع الصورة الي تحت 


المعنى هنا إننا بنقول للـ Laravel:

لما حد يطلب ConnectionInterface, اديله نسخة من ConnectionSql.

طب لو عايز تديه نسخة تانية زي ConnectionDummy أو ConnectionPostgres؟

سهل جدًا، كل اللي عليك تغيّر الكود جوه الـ bind، أو حتى تربطه على حسب نوع بعتّه من config أو .env أو من الـ runtime.


و كدا طبقا ال Inversion of Control (IoC)



و السؤال التالت : اي هوه Dependency Injection (DI) ؟؟؟؟؟؟؟؟؟


وده هو الآلية اللي بتخليك تطبّق IoC.

يعني إيه؟


يعني بدل ما الكلاس يخلق الحاجة اللي محتاجها (بـ new)، إنت تحقنها فيه من بره، مثلاً من الـ Constructor.


زي class ال UserRegistration 




هنا إحنا ما عملناش new ConnectionSql() جوه الكلاس.

إحنا حقناه بالـ dependency من بره عن طريق الـ Constructor، وده بالضبط هو Dependency Injection.

طب لو مشينا بالعكس؟

هتبقى كده:




طب ال constract الي فوق غلط ليه 

علشان 

كده إحنا ربطنا الكلاس بحاجة Low-Level مباشرة، وده ضد مبادئ التصميم الصح



السؤال الخير بقا : Dependency Inversion Principle (DIP) ؟؟؟؟؟؟؟


"الموديولات العالية المستوى (High-level) ما تعتمدش على الموديولات القليلة المستوى (Low-level). الاتنين لازم يعتمدوا على abstraction (interface)."


يعني بدل ما الكلاس يعتمد على ConnectionDummy أو ConnectionSql بشكل مباشر، يعتمِد على ConnectionInterface:


الصح


الغلط 



طب ليه غلط

علشان 

علشان لو حبيت تغير طريقة الاتصال من Dummy إلى SQL أو PostgreSQL، مش محتاج تغيّر كود الكلاس نفسه.
مجرد تغيّر الـ binding في الـ container وخلاص. (الكود الي اتكتب ف services provider)



🙂🙂سؤااااال ال Interview 

هل Dependency Inversion Principle (DIP) هو نفسه Dependency Injection (DI)؟


لأأأأأأأ... الاتنين مختلفين تمامًا!


Dependency Injection (DI) هو مجرد طريقة (Mechanism) لتوصيل الكلاسات ببعض.


يعني بدل ما تكتب جوه الكلاس:
هتكتب كدا 


اما Dependency Inversion Principle (DIP)


ده بقى مبدأ تصميم من مبادئ SOLID، وبيقول:

"الموديولات العالية المستوى ما تعتمدش على الموديولات قليلة المستوى. الاتنين لازم يعتمدوا على abstraction."

يعني لما تحقن dependency في الكلاس، ما تحقنش ConnectionSql مباشرة، بل تحقن ConnectionInterface.
وده اللي بيميز DIP.






الخلاصة: ازاي التلاتة مرتبطين ببعض؟


لما تعمل Inject بـ ConnectionInterface ➜ إنت كده بتطبّق Dependency Inversion Principle.
لما تسيب إنشاء الكائنات للـ Container بدل ما تعمل new بنفسك (الخطوة بتاعت ال service provider) و دا ال Inversion Of Controle
والـ Mechanism اللي بيساعدك تعمل كده هو Dependency Injection.





طب عملنا كده ليه من الأساس؟

علشان الكلاس UserRegistration مش مهم بالنسباله إزاي الـ insert بيحصل، كل اللي يهمه إن فيه insert() شغال.
فـ سواء كنت بتتعامل مع:
MySQL
PostgreSQL
MongoDB
Array في الذاكرة (Dummy)
كلهم بينفذوا نفس الـ interface، وكلهم عندهم نفس الميثود insert()، والكلاس مش فارق معاه التفاصيل.
وده بيخلي الكود:
قابل لإعادة الاستخدام
و سهل في الاختبار (تقدر تدي للكلاس نسخة وهمية Dummy من غير داتا بيز)
و مرن وقابل للتطوير بسهولة.


او يلا نروح للقاعدة 2 من هنا


قبل م نروح بص ع ال digram