Mobius هو إطار عمل تفاعلي وظيفي لإدارة تطور الحالة والآثار الجانبية، مع وظائف إضافية للاتصال بواجهات مستخدم Android وRxJava Observables. ويؤكد على فصل الاهتمامات وقابلية الاختبار وعزل الأجزاء ذات الحالة من الكود.
لمعرفة المزيد، قم بزيارة الموقع الإلكتروني للحصول على دليل المستخدم. لرؤية Mobius أثناء العمل، تحقق من نموذج تطبيق TODO استنادًا إلى التطبيق من Android Architecture Blueprints. يمكنك أيضًا مشاهدة محادثة من Android @Scale للتعريف بـ Mobius.
Mobius في حالة الإنتاج، مما يعني أنه يتم استخدامه في الإنتاج في تطبيقات Spotify Android، ونحن نعتبر واجهات برمجة التطبيقات مستقرة وخالية من الأخطاء في التنفيذ. لن نقوم بإجراء تغييرات تنتهك التوافق مع الإصدارات السابقة.
تم تصميم Mobius حاليًا لـ Java 7 (نظرًا لأن Java 8 غير مدعوم بشكل كامل في جميع إصدارات Android)، ومن ثم تكرار بعض المفاهيم المحددة في java.util.function
(راجع com.spotify.mobius.functions
).
عند استخدام Mobius، نوصي باستخدام Kotlin أو Java 8 أو الإصدارات الأحدث، وذلك في المقام الأول بسبب تحسين استنتاج النوع ولأن استخدام lambdas يعمل بشكل كبير على تحسين إمكانية القراءة وإيجاز التعليمات البرمجية.
يتوفر أحدث إصدار من Mobius من خلال Maven Central (الإصدار الأخير أدناه هو ):
implementation ' com.spotify.mobius:mobius-core:LATEST_RELEASE '
testImplementation ' com.spotify.mobius:mobius-test:LATEST_RELEASE '
implementation ' com.spotify.mobius:mobius-rx:LATEST_RELEASE ' // only for RxJava 1 support
implementation ' com.spotify.mobius:mobius-rx2:LATEST_RELEASE ' // only for RxJava 2 support
implementation ' com.spotify.mobius:mobius-rx3:LATEST_RELEASE ' // only for RxJava 3 support
implementation ' com.spotify.mobius:mobius-android:LATEST_RELEASE ' // only for Android support
implementation ' com.spotify.mobius:mobius-extras:LATEST_RELEASE ' // utilities for common patterns
هذا هو جوهر Mobius، الذي تعتمد عليه جميع الوحدات الأخرى. إنها مكتبة Java خالصة ومكتفية بذاتها تمامًا. هذه هي الوحدة الوحيدة التي تحتاجها عند استخدام Mobius، لأن الوحدات الأخرى عبارة عن امتدادات اختيارية للنواة.
تحتوي وحدة الاختبار على أدوات مساعدة تساعدك على كتابة اختبارات لتطبيقات Mobius. يجب استخدامه فقط باعتباره تبعية اختبار.
تحتوي وحدات rx على امتدادات لـ RxJava. يجب عليك استخدام أحدها في تطبيقات Mobius الخاصة بك لأنها تبسط عملية إنشاء معالجات التأثير ومصادر الأحداث. تشترك كلتا وحدتي RxJava في نفس واجهة برمجة التطبيقات (API)، والفرق الوحيد هو أن إحداهما مصممة لـ RxJava 1.x والأخرى لـ RxJava 2.x.
تحتوي وحدة android بشكل أساسي على فئات لتوصيل MobiusLoop بنظام Android.
تحتوي وحدة الإضافات على أدوات مساعدة وفئات تساعد على تقليل النمط المعياري لبعض أنماط الاستخدام الأكثر تقدمًا (على سبيل المثال، وظائف التحديث المتداخلة).
الهدف من Mobius هو منحك تحكمًا أفضل في حالة التطبيق الخاص بك. يمكنك التفكير في حالتك باعتبارها لقطة لجميع القيم الحالية للمتغيرات في تطبيقك. في Mobius، نقوم بتغليف الحالة بأكملها في بنية بيانات نسميها النموذج .
يمكن تمثيل النموذج بأي نوع تريده. في هذا المثال، سنقوم ببناء عداد بسيط، بحيث يمكن احتواء كل حالتنا في Integer
:
لا يسمح لك Mobius بالتلاعب بالدولة بشكل مباشر. من أجل تغيير الحالة، يجب عليك إرسال رسائل إطارية توضح ما تريد القيام به. نحن نسمي هذه الرسائل الأحداث . في حالتنا، سنرغب في زيادة العداد وتقليله. دعونا نستخدم enum
لتحديد هذه الحالات:
enum CounterEvent {
INCREMENT ,
DECREMENT ,
}
الآن بعد أن أصبح لدينا نموذج وبعض الأحداث ، سنحتاج إلى إعطاء Mobius مجموعة من القواعد التي يمكنه استخدامها لتحديث الحالة نيابة عنا. نقوم بذلك عن طريق إعطاء إطار العمل وظيفة سيتم استدعاؤها بشكل تسلسلي مع كل حدث وارد وأحدث نموذج ، من أجل إنشاء النموذج التالي:
class CounterLogic {
static Integer update ( Integer model , CounterEvent event ) {
switch ( event ) {
case INCREMENT : return model + 1 ;
case DECREMENT : return model - 1 ;
}
}
}
باستخدام هذه اللبنات الأساسية، يمكننا أن نبدأ في التفكير في تطبيقاتنا باعتبارها انتقالات بين الحالات المنفصلة استجابةً للأحداث. ولكننا نعتقد أنه لا تزال هناك قطعة واحدة مفقودة من اللغز، وهي الآثار الجانبية المرتبطة بالتنقل بين الحالات. على سبيل المثال، قد يؤدي الضغط على زر "تحديث" إلى وضع تطبيقنا في حالة "تحميل"، مع ما يؤدي أيضًا إلى جلب أحدث البيانات من الواجهة الخلفية لدينا.
في Mobius، نطلق على هذه الآثار الجانبية اسم " التأثيرات ". في حالة العداد الخاص بنا، لنفترض أنه عندما يحاول المستخدم التناقص إلى أقل من 0، فإننا نشغل مؤثرًا صوتيًا بدلاً من ذلك. لنقم بإنشاء enum
يمثل جميع التأثيرات المحتملة (والتي في هذه الحالة هي واحدة فقط):
enum CounterEffect {
PLAY_SOUND ,
}
سنحتاج الآن إلى زيادة وظيفة update
لدينا لإرجاع مجموعة من التأثيرات المرتبطة بانتقالات معينة للحالة أيضًا. للقيام بذلك، سنقوم بتنفيذ واجهة Update
كما يلي:
class CounterLogic implements Update < Integer , CounterEvent , CounterEffect > {
public Next < Integer , CounterEffect > update ( Integer model , CounterEvent event ) {
switch ( event ) {
case INCREMENT :
return next ( model + 1 );
case DECREMENT :
if ( model == 0 ) {
Set < CounterEffect > soundEffect = effects ( CounterEffect . PLAY_SOUND );
return dispatch ( soundEffect );
}
return next ( model - 1 );
}
throw new IllegalStateException ( "Unhandled event: " + event );
}
}
يرسل Mobius كل التأثيرات التي تعود بها في أي حالة انتقالية إلى شيء يسمى Effect Handler . لنقم بإنشاء واحدة منها الآن من خلال تنفيذ الواجهة Connectable
:
class CounterEffectHandler implements Connectable < CounterEffect , CounterEvent > {
public Connection < CounterEffect > connect ( Consumer < CounterEvent > output ) {
return new Connection < CounterEffect >() {
@ Override
public void accept ( CounterEffect effect ) {
if ( effect == CounterEffect . PLAY_SOUND ) {
Toolkit . getDefaultToolkit (). beep ();
}
}
@ Override
public void dispose () {}
};
}
}
الآن بعد أن أصبح لدينا كل القطع في مكانها الصحيح، دعونا نربطها معًا:
public static void main ( String [] args ) {
// Let's make a Mobius Loop
MobiusLoop < Integer , CounterEvent , CounterEffect > loop = Mobius
. loop ( new CounterLogic (), new CounterEffectHandler ())
. startFrom ( 0 );
// And start using our loop
loop . dispatchEvent ( CounterEvent . INCREMENT ); // Model is now 1
loop . dispatchEvent ( CounterEvent . DECREMENT ); // Model is now 0
loop . dispatchEvent ( CounterEvent . DECREMENT ); // Sound effect plays! Model is still 0
}
يغطي هذا أساسيات Mobius. لمعرفة المزيد، توجه إلى موقعنا.
نحن نستخدم أداة التنسيق التلقائي من Google لتنسيق الرمز. تم إعداد مسار الإنشاء لفشل عمليات الإنشاء التي لم يتم تنسيقها بشكل صحيح. للتأكد من التنسيق الصحيح، قم بتشغيل
./gradlew format
يلتزم هذا المشروع بمدونة قواعد السلوك المفتوحة. من خلال المشاركة، يتوقع منك احترام هذا الرمز.