
أعمل في شركة لتطوير الألعاب ، ولكني هواية منزلية ، أصبحت مهتمًا مؤخرًا بتطوير تطبيقات الهاتف المحمول. لذلك ، عندما دعاني أحد الأصدقاء إلى اجتماع مخصص لتطوير تطبيقات الهاتف المحمول باستخدام إطار Flutter ، فقد وافقت بكل سرور. بعد أن جربت Flutter في العمل هناك ، قررت بالتأكيد دراسة هذه التكنولوجيا. نظرًا لأن Dart اللازمة للتنمية لم تكن مألوفة بالنسبة لي ، فقد تم أيضًا تضمين تعلم اللغة في البرنامج الإلزامي. بعد الجلوس قليلاً على أمثلة الكود ، وجدت دارت لغة سهلة الفهم وموجزة أحببت حقًا. واحدة من ميزات دارت التي أحببت هو الشوائب.
ما هي الشوائب؟
للتعارف الأولي ، سأقدم
مقتطفات من ويكيبيديا .
الاختلاط (مزيج اللغة الإنجليزية) هو أحد عناصر لغة البرمجة (عادةً فئة أو وحدة نمطية) التي تنفذ بعض السلوك المحدد بوضوح. يستخدم لتوضيح سلوك الفئات الأخرى ، وليس الغرض منه إنشاء كائنات مستخدمة بشكل مستقل.
في Dart ، يتم تعريف هذه التركيبات بواسطة الكلمة
mixin قبل الاسم.
التعريف أعلاه يعني أننا نحصل على وظائف السلوكيات المعزولة منطقيا والتي يمكن إضافتها إلى الفئات الأخرى.
هل يذكرك بإمكانية الميراث المتعدد؟ نعم ، ولكن يبدو لي أن نهج النجاسة هو أفضل. ولماذا ، دعونا ننظر إلى مثال.
لنفترض أن لدينا فئة الحيوان مجردة.
abstract class Animal { void voice(); }
وكذلك فصول القط والكلب التي تنفذ فئة الحيوان.
class Cat extends Animal { void voice() { print(“Meow”); } } class Dog extends Animal { void voice() { print(“Woof”); } }
نعم ، نعم ، أنا شخصياً لا أملك مثل هذه الأشياء أثناء التطوير.
وفي حالة الميراث المتعدد ، سنفعل الشيء نفسه.
class CatDog extends Cat, Dog { }
ولكن حالما نعبر عن أمرنا الصوتي في حيواننا الأليف ، فإننا نواجه وضعًا غير سارة للغاية - ليس من الواضح ما الذي يجب أن يجيب عليه بالضبط ، لأن طريقة
الصوت يتم تنفيذها في كلتا الفئتين. هذا الموقف معروف على نطاق واسع ويسمى
مشكلة الماس أو
الماس القاتل .
في حالة المبيعات من خلال الشوائب ، لن نواجهها.
lass Animal { void voice() { print(“Hakuna Matata!”); } } mixin Cat { void voice() { print(“Meow”); } } mixin Dog { void voice() { print(“Woof”); } } class CatDog extends Animal with Cat, Dog { }
وماذا سنسمع إذا أعطينا الآن أمرًا صوتيًا؟ في هذه الحالة - اللحمة ، وكما فهمت بالفعل ، يعتمد الأمر على ترتيب إضافة الشوائب. يحدث هذا لأن الإضافة ليست متوازية ، ولكنها متتابعة.
لقد طبقت فئة Animal خصيصًا لتمييز ميزة تم تقديمها في
Dart 2.1 . قبل ذلك ، يمكن إضافة الشوائب فقط إلى الفئات التي ترث من
كائن . بدءًا من الإصدار 2.1 ، يتم تطبيق إضافة أي فصول إلى الورثة.
تعمل هذه الآلية على تسهيل استخدام الأجزاء الشائعة للوظيفة واستخدامها ، مما يحل مشكلة تكرار التعليمات البرمجية. لنلقِ نظرة على مثال.
abstract class Sportsman { void readySteadyGo(); } mixin SkiRunner { void run() { print(“Ski, ski, ski”); } } mixin RifleShooter { void shot() { print(“Pew, pew, pew”); } } class Shooter() extends Sportsman with RifleShooter { void readySteadyGo() { shot(); } } class Skier() extends Sportsman with SkiRunner { void readySteadyGo() { run(); } } class Biathlete() extends Sportsman with SkiRunner, RifleShooter { void readySteadyGo() { run(); shot(); } }
كما ترون ، قمنا بتوزيع جميع الشفرة المكررة عن طريق الشوائب واستخدمنا فقط الرموز الضرورية في كل تطبيق.
أثناء التطوير ، قد ينشأ موقف عندما لا تكون وظيفة أي من الشوائب متاحة للجمهور لإدراجها من قبل جميع الفئات. وتتوفر أيضًا آلية تسمح لنا بفرض هذه القيود. هذه هي الكلمة الأساسية في إعلان الاختلاط جنبًا إلى جنب مع اسم الفصل. لذلك سنقصر استخدام الشوائب فقط على الفئات التي تنفذ المحدد أو الموروث منه.
على سبيل المثال:
class A { } abstract class B { } mixin M1 on A { } mixin M2 on B { }
ثم يمكننا أن نعلن فئات مماثلة:
class C extends A with M1 { } class D implements B with M2 { }
لكن حصلنا على خطأ في محاولة إعلان شيء مثل هذا:
class E with M1, M2 { }
الاستخدام في تطبيق الرفرفة
كما ذكرت أعلاه ، الشوائب تسمح لك بالتخلص من ازدواجية الكود وعمل أجزاء منطقية منفصلة يمكن إعادة استخدامها. ولكن كيف ينطبق هذا بشكل عام على Flutter ، حيث يكون كل شيء ذريًا وينقسم إلى أدوات مصغّرة مسؤولة عن وظيفة معينة؟ على سبيل المثال ، تخيلت فورًا موقفًا يستخدم فيه المشروع العديد من عناصر واجهة المستخدم ، حيث يختلف عرضه تبعًا لحالة داخلية معينة. سأنظر في هذا المثال في بنية BLoC واستخدم الكيانات من مكتبة rxDart.
نحن بحاجة إلى واجهة لإغلاق وحدة تحكم التدفق.
اختلاط ننفذ به دعم الدولة.
الجزء المنطقي الذي سيتحكم في حالة عنصر واجهة المستخدم. اسمح لها بتعيين حالة من خلال استدعاء الأسلوب وبعد 3 ثوان تغييره إلى آخر.
والقطعة نفسها التي سوف تستجيب لتغيير الدولة. تخيل الحصول على المكون المنطقي المطلوب باستخدام Dependency Injection.
class ExampleWidget extends StatelessWidget { final bloc = di<HomePageBloc>(); @override Widget build(BuildContext context) { return StreamBuilder( stream: bloc.stateOut, builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
إذا كنت ترغب في ذلك ، فيمكننا أيضًا إضافة ما تمت كتابته إلى المزيج والمطالبة فقط بتنفيذ طريقة البناء باستخدام الواجهة ، لكن يبدو لي أن هذا الأمر غير ضروري بالفعل ، لأنه من غير المحتمل أن يكون هناك العديد من الأدوات المصغرة البسيطة في المشروع ، لأنه كان مجرد مثال. ومع ذلك ، سيتم إضافة الجزء المنطقي من وظيفة دعم الحالة بسهولة إلى أي من مراكز الرعاية الصحية باستخدام هذا المزيج.
استنتاج
بدت لي آلية استخدام الشوائب أداة تطوير مثيرة للاهتمام إلى حد ما ، مما يجعل من الممكن بناء بنية بسيطة ومفهومة ومريحة. بالنسبة لي ، قررت أن هذه الأداة في مجموعتي لن تكون زائدة عن الحاجة ، وآمل أن تكون مفيدة لك أيضًا.
الموارد:
جولة في اللغة السهامويكيبيديا