واحدة من أهم الأسباب في استخدام ال Interface هو أنه يساعد في جعل الكود أكثر قابلية للصيانة Maintainability، أي الكود المرن في التغيير وليس الذي يحتاج تغييره كاملاً بسبب تغيير بسيط، وبالتالي يضمن هذا الأمر أن الكود يعمل للمستقبل Future Proof Code.
فالتطبيقات دائماً تتغير إما بتغيير المتطلبات أو بالإضافة المزيد من الخصائص الجديدة، والفكرة هنا هي أنه عندما نريد العمل على جزء واحد من التطبيق فنحن نريد تقليل التغييرات التي سوف تطرأ على بقية الأجزاء في التطبيق. وسوف نرى كيف يمكن أن تفيدنا ال Interface في ذلك.
في هذه السلسلة سوف نوضح ما يلي:
- الفرق بين ال Abstract Class وال Interface
- دور ال Interface في قابلية الصيانة Maintainbility (المقالة الحالية)
- عمل ال Repository باستخدام ال Interface
- ما هو ال Dynamic Factory
لماذا ال Interface
قبل أن نبدأ، لنرى أحد العادات الجيدة في البرمجة، وال Interface لها نصيب من ذلك، وهي:
Program to an abstraction rather than a concrete type
كما ذكرنا في الفصل السابق أنه يمكن أن تستخدم ال Interface ك Abstraction وبالتالي تستطيع أن تفهم العادة على أنها:
Program to an Interface rather than a concrete type
لذلك عليك البرمجة بال Contract بغض النظر من سوف يطبقه كأن هناك شخص آخر سوف يتولى هذه المهمة.
وتذكر أن ال Concrete Class هي الكلاسات العادية التي تقوم بعملها أو موجودة ضمن مكتبة اللغة أو في مكتبة خارجية أخرى، مثلاً في ال Collections API كل ال Classesالتالية هي Concrete:
وكل هذه الكلاسات أعلاه تقوم بعمل Implements للكثير من ال Interfaces حتى تقوم بعملها بطريقة جيدة وتقدم Abstraction لك، مثلاً الكلاس List يقوم بعمل Implements لكل ال Interfaces التالية:
لاحظ أن List Class يطبق كل هذه ال Interfaces (بدلاً من وضعها في واحدة كبيرة، وهذا مثال ل Interface Segaration Principle والفكرة أن ال Interface يستطيع أن يرث من أي Interface أخرى وبالتالي لا تحتاج لتعديل أي Interface بعد أن يخرج لل Production وصار الكثير من ال clients يعتمدوا عليها).
ال IEnumerable أحد ال Interface التي تطبقها ال List والكثير من ال Concrete Collection وهي تستخدم عندما تريد ال loop على ال container، ولذلك لتطبيق القاعدة Program to abstraction فيمكنك استخدام ال interface بدلاً من اسم الكلاس عندما تستخدم أي من ال Containers.
الفرق بين Programming to Concrete و Programming to Abstraction
لو لاحظت لدالة ارجاع الاشكال ExtractShapes في الدارس السابق، كانت بهذا الشكل:
static void Main(string[] args) { IRegularPolygon[] shapes = ExtractShapes(); foreach(IRegularPolygon shape in shapes) { Console.WriteLine("Area: " + shape.GetArea()); } Console.ReadKey(); } private static IRegularPolygon[] ExtractShapes() { // Read from external sources and return the polygons // parsing the file and extract the shapes return new IRegularPolygon[] { new Sequare(3), new Triangle(4), new Sequare(5) }; }
طريقة استخراج الأشكال خارج نطاق الموضوع، لذلك افترض أنك حصلت عليهم سواء من قراءتك لملف أو من قاعدة بيانات أو أي مصدر يكن، ومن ثم ترجع تلك الأشكال.
الذي يهم هنا طريقة ارجاع المجموعة ولاحظ أنه تم ارجاعها على شكل مصفوفة (وهي تعتبر Concrete Type)، فماذا يحدث لو قمت بتغيير الكود ورجعت Data Structure أفضل منها، مثلاً List أو Set لأنك لا تريد تكرار تلك الأشكال التي لها نفس الطول مثلاً؟
لذلك حتى تطبق تلك العادة عليك بإرجاع ال Abstraction (باستخدام ال IEnumerable) وبالتالي تضمن أن أي Implementation يطبق ال IEnumerable سوف يعمل بغض النظر عن ماهيته والسبب كونك تعتمد على ذلك ال Abstraction. نلاحظ الكود الآن بعد التغيير إلى IEnumerable<IRegularPolygon>
static void Main(string[] args) { IEnumerable<IRegularPolygon> shapes = ExtractShapes(); foreach (IRegularPolygon shape in shapes) { Console.WriteLine("Area: " + shape.GetArea()); } Console.ReadKey(); } private static IEnumerable<IRegularPolygon> ExtractShapes() { // Read from external sources and return the polygons // parsing the file and extract the shapes return new IRegularPolygon[] { new Sequare(3), new Triangle(4), new Sequare(5) }; }
الكود سوف يعمل كمخرج بدون أي تغيير، ولكن الآن جرب غير الكود داخل الدالة وبدل أن ترجع Array جرب أن ترجع List أو Queue، وستجد أن ال Main (ال Client Code) لم تتغير ابداً، وهكذا تستطيع تغيير ال Implementation طالما يطبق ال Abstraction بدون تغيير ال client code، وهذا ما أطلقنا عليه اول الفصل بالكود المستقبلي Future Proofing code.
طرق أخرى في ال Maintainability
استخدام ال Interface ليس الطريق الوحيدة لجعل الكود أكثر قابلية للصيانة، فهذه الخاصية لها أكثر من مسار تستطيع تطبيقه حتى يكون كودك أفضل، مثلاً:
- جعله أكثر مقروئية Readability من ناحية الأسماء والتنظيم وعدم استخدام الدوال والكلاسات الطويلة (ما هي رائحة الكود Code Smell؟)
- جعل الدوال والكلاسات لديك مسؤولة عن شيء واحد فقط Single Responsibility (ما هو مفهوم Single Responsibility Principle) وهكذا لن تكون مضطر لتغيير تلك الأمور إلا لسبب واحد فقط
- كلما حولت مشروعك لفكرة ال Modules) Layers أو Packages أو Namespaces) وقللت التداخل Coupling بين تلك الوحدات ماذا تعرف عن ال Coupling وال Cohesion في تصميم البرمجيات؟
- اخفاء كل شيء بقدر الامكان Hide Implementation أي جعل المتغيرات والدوال private، لذلك النصيحة العامة لا تستخدم public إلا عندما تحتاجها فقط.
المقروئية ليست في التعليقات
المقروئية Readability لا تكون من خلال التعليقات فقط والتي يفضل أن تعتبرها أخر ورقة لديك تقوم بها عندما لا تستطيع كتابه كود أفضل من الذي قمت بكتابته. خصوصاً لو كان مجرد Business Logic وليس عباره عن خوارزمية ما (مثلاً حساب تقويم أو معالجة لصورة بطريقة ما).
وقد تصل للمقروئية الجيدة في حال اتبعت التسميات الجيدة والتي فيها الغالب لكل لغة Convention خاص بها، وأيضاً إذا استخدمت بعض ال Patterns لكي تحسن ال API لديك، على سبيل المثال لماذا تقوم بعمل دالة بناء Constructor تستقبل 20 متغير؟ فيمكنك بدلاً من ذلك أن تستخدم Builder Pattern أو Static Factory وذلك لتحسين ال API.
المقالة التالية سوف نرى أحد اهم الأسباب لاستخدام ال Abstraction وبالأخص ال Interface وهي في جعل الكود قابل للتطوير Extendibility.
خلاصة
- تحدثنا عن مفهوم Program to abstraction rather than a concrete type والذي يجعل الكود أكثر صموداً مع التغيير، وليس كما هو الحال مع ال concrete type والذي يحدث فيه Broken بسهولة وقد تحتاج لعمل التغييرات.
- ال Interface يبعدك عن تفاصيل ال Implementation وتجعلك تركز على ال Contract الموجود.
- يفضل بدل ارجاع list أو Array أن تقوم بإرجاع IEnumerable، لأن الراجع قد يتغير من مصفوفه إلى list وسوف تحتاج لتعديل ال client ولكن عندما تستخدم ال interface فلن يحتاج ال client للتغير لأن الاثنين يطبقوا ال IEnumerable وهكذا لكل API التي تقوم بعملها.
[…] post دور ال Interface في قابلية الصيانة Maintainability appeared first on […]