English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
هذا المقال يشرح مثالًا على نموذج الملاحظة في تصميم البرمجة لأندرويد. أشارككم هذا للمراجعة، وهو كالتالي:
الجزء الأول: التعريف
نموذج الملاحظة هو نموذج يستخدم بكثرة، حيث يستخدم في أماكن متعددة مثل نظام واجهة المستخدم الرسومية، نظام الاشتراك-النشر. لأن أحد الأدوار الرئيسية لهذا النموذج هو فصل الملاحظة والملاحظ، مما يجعل الاعتماد بينهما أقل، حتى يمكن القول إنه لا يوجد اعتماد. بالنسبة لنظام واجهة المستخدم الرسومية، فإن واجهة المستخدم الخاصة بالتطبيق معرّضة للتغير، خاصة في المراحل الأولى مع تغيير الأعمال أو تعديل متطلبات المنتج، حيث تتغير واجهة التطبيق بشكل متكرر، ولكن لا تتغير ل逻辑 الأعمال بشكل كبير، في هذه الحالة، يحتاج نظام واجهة المستخدم الرسومية إلى ميكانيكية لمعالجة هذا السيناريو، مما يجعل الطبقة UI مفصولة عن لوجيك الأعمال المحدد، حيث يأتي دور نموذج الملاحظة في هذه الحالة.
الجزء الثاني: التعريف
تحديد علاقة إرتباط بين العناصر، بحيث عندما يتغير حالة واحدة، يتم إعلام جميع العناصر التي تعتمد عليها وتتم تحديثها تلقائيًا.
الجزء الثالث: سيناريوهات الاستخدام
ساحة السلوكيات المتعلقة، ويجب الانتباه إلى أن السلوكيات المتعلقة قابلة للفصل وليست علاقة "مجموعة".
ساحة تفجير الأحداث متعددة المستويات.
ساحة تبادل الرسائل بين النظامين، مثل آلية معالجة قوائم الرسائل أو شريط الأحداث.
الجزء الرابع: مخطط UML نموذج الملاحظة
مخطط UML للفئات:
تعريف الأدوار:
Subject: الموضوع المفهوم، أي دور الملاحظة (Observable)، حيث يحفظ دور الموضوع المفهوم جميع مراجع موضوعات الملاحظة في مجموعة، يمكن لكل موضوع أن يكون لديه أي عدد من الملاحظين. يقدم دور الموضوع المفهوم واجهة يمكن من خلالها إضافة أو حذف موضوعات الملاحظة.
ConcreteSubject: الموضوع المحدد، حيث يخزن هذا الدور الحالة ذات الصلة في موضوع الملاحظة المحدد، وعندما تتغير الحالة الداخلية للموضوع المحدد، يرسل إشعارات إلى جميع الملاحظين المسجلين، ويسمى دور موضوع الملاحظة المحدد أيضًا دور الملاحظة المحددة (ConcreteObservable).
Observer: المراقب التجريبي، هذا الدور هو فئة المراقب التجريبية، يحدد واجهة التحديث، مما يسمح له بتحديث نفسه عند تلقي إشعار التغيير من الموضوع.
ConcreteObserver: المراقب المحدد، هذا الدور يحقق واجهة المراقب التجريبية المحددة، حتى يتم تحديث حالة نفسه عند تغيير حالة الموضوع.
خامساً، التنفيذ البسيط
في هذا المثال، لنأخذ مثالاً على متابعة المسلسلات، عادةً لن نضيع أي جزء من المسلسل الجديد، سنقوم بالاشتراك أو متابعة هذا المسلسل، وعندما يتم تحديث المسلسل سيتم إرسال إشعار لنا في أسرع وقت، والآن دعونا نحاول تحقيق ذلك ببساطة.
فئة المراقب التجريبية:
/** * فئة المراقب التجريبية، تحدد واجهة لجميع المراقبين المحددين، وتحدد كيفية تحديث نفسها عند تلقي إشعار */ public interface Observer { /** * هناك تحديث * * @param message الرسالة */ public void update(String message); }
فئة المراقب التجريبية:
/** * فئة المراقب التجريبية */ public interface Observable { /** * إرسال رسالة * * @param message المحتوى */ void push(String message); /** * الاشتراك * * @param observer المشترك */ void register(Observer observer); }
فئة المراقب المحددة:
/** * فئة المراقب المحددة، أي المشترك */ public class User implements Observer { @Override public void update(String message) { System.out.println(name + "," + message + "تحديث!"); } //اسم المشترك private String name; public User(String name) { this.name = name; } }
فئة المراقب المحددة:
/** * فئة المراقب المحددة، أي البرنامج المشترك */ public class Teleplay implements Observable{ private List<Observer> قائمة = new ArrayList<Observer>();//تخزين المشتركين @Override public void push(String message) { لـ(مراقب observer:قائمة){ observer.update(message); } } @Override public void register(Observer observer) { list.add(observer); } }
التنفيذ:
public class Client { public static void main(String[] args) { //المُراقب، هنا هو مسلسل التلفزيون الذي اشترك فيه المستخدم Teleplay teleplay = new Teleplay(); //مراقب، هنا هو مستخدم الاشتراك User user1 = new User("الصغير"); User user2 = new User("الشعبي"); User user3 = new User("اللونغ"); //اشتراك teleplay.register(user1); teleplay.register(user2); teleplay.register(user3); //إرسال رسالة جديدة teleplay.push("xxx مسلسل التلفزيون"); } }
النتيجة:
الصغير، تم تحديث xxx مسلسل التلفزيون! الشعبي، تم تحديث xxx مسلسل التلفزيون! اللونغ، تم تحديث xxx مسلسل التلفزيون!
من الرمز أعلاه يمكن رؤية تنفيذ إرسال رسائل متعددة إلى موجهة، حيث تعتمد إرسال الرسائل على كلاً من Observer وObservable هذه الفئات التجريدية، بينما لا يوجد أي توتر بين User وTeleplay، مما يضمن مرونة النظام المُشترك وواسعته.
الجزء السادس: نموذج المراقب في رمز Android
1、BaseAdapter
BaseAdapter أعتقد أن الجميع لا يترددون في التعرف عليه، في ListView adapter نرثه. دعونا نحلل بسرعة.
BaseAdapter 部分代码:
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter { //数据集观察者 private final DataSetObservable mDataSetObservable = new DataSetObservable(); public boolean hasStableIds() { return false; } public void registerDataSetObserver(DataSetObserver observer) { mDataSetObservable.registerObserver(observer);} } public void unregisterDataSetObserver(DataSetObserver observer) { mDataSetObservable.unregisterObserver(observer); } /** * يتم إعلام جميع المشاهدين عندما تتغير مجموعة البيانات. */ public void notifyDataSetChanged() { mDataSetObservable.notifyChanged(); } }
انظر إلى طريقة mDataSetObservable.notifyChanged():
public class DataSetObservable extends Observable<DataSetObserver> { /** * يدعو إلى {@link DataSetObserver#onChanged} لكل مشاهد. * يتم استدعاؤه عندما تتغير محتويات مجموعة البيانات. المستلم * سيحصل على المحتويات الجديدة في المرة القادمة التي يستخدم فيها مجموعة البيانات. */ public void notifyChanged() { synchronized(mObservers) { // لأن onChanged() تم تنفيذه من قبل التطبيق، يمكنه القيام بأي شيء، بما في ذلك // إزالة نفسه من {@link mObservers} - وقد يسبب مشاكل إذا // يتم استخدام معادلة على ArrayList {@link mObservers}. // لتجنب مثل هذه المشاكل، قم بالتحرك عبر القائمة بالترتيب المعكوس فقط. للدوران من خلال القائمة بالترتيب المعكوس؛ mObservers.get(i).onChanged(); } } } }
يبدو أنه في mDataSetObservable.notifyChanged() يتم مرور جميع المراقبين، وتطبيق طريقة onChanged() عليهم، مما يخبر المراقبين بما حدث.
إذن كيف يأتي المراقب، وهو دالة setAdapter، الكود التالي:
@Override public void setAdapter(ListAdapter adapter) { إذا (mAdapter != null && mDataSetObserver != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver); } resetList(); mRecycler.clear(); إذا (mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0) { mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); } آخره { mAdapter = adapter; } mOldSelectedPosition = INVALID_POSITION; mOldSelectedRowId = INVALID_ROW_ID; // AbsListView#setAdapter سيحدث تحديث للوضع الخاص بالخيار super.setAdapter(adapter); إذا (mAdapter != null) { mAreAllItemsSelectable = mAdapter.areAllItemsEnabled(); mOldItemCount = mItemCount; mItemCount = mAdapter.getCount(); تحقق من التركيز(); mDataSetObserver = new AdapterDataSetObserver(); mAdapter.registerDataSetObserver(mDataSetObserver); // تسجيل المراقب ......تم إغضاره } }
AdapterDataSetObserver定义在ListView的والد AbsListView، وهومراقب مجموعة البيانات، الكود:
class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver { @Override public void onChanged() { super.onChanged(); إذا (mFastScroller != null) { mFastScroller.onSectionsChanged(); } } @Override public void onInvalidated() { super.onInvalidated(); إذا (mFastScroller != null) { mFastScroller.onSectionsChanged(); } } }
إنه من DataSetObserver الذي يرث من父类 AdapterView الذي يرث من AbsListView، والذي يظهر في الكود التالي:
class AdapterDataSetObserver extends DataSetObserver { private Parcelable mInstanceState = null; // كما ذكرت في المقطع السابق، عند استدعاء Adapter's notifyDataSetChanged سيتم استدعاء method onChanged لكل المراقبين، التنفيذ الأساسي هنا @Override public void onChanged() { mDataChanged = true; mOldItemCount = mItemCount; // الحصول على عدد النقاط البيانية في Adapter mItemCount = getAdapter().getCount(); // اكتشف حالة البحث التي تم إبطال صلاحيتها من قبل // تم إعادة تعبئة بالنقاط البيانية الجديدة. إذا (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null && mOldItemCount == 0 && mItemCount > 0) { AdapterView.this.onRestoreInstanceState(mInstanceState); mInstanceState = null; } آخره { تذكر حالة التواصل(); } تحقق من التركيز(); // إعادة ترتيب مكونات AdapterView مثل ListView و GridView وغيرها طلب ترتيب المخطط(); } // الكود تم حذفه public void clearSavedState() { mInstanceState = null; } }
عندما يتغير بيانات ListView، يتم استدعاء دالة notifyDataSetChanged في Adapter، وتقوم هذه الدالة باستدعاء دالة notifyChanged في DataSetObservable، وتقوم هذه الدالة باستدعاء دالة onChanged لكل مراقب (AdapterDataSetObserver). هذا هو نموذج المراقب!
بند السابع: الخاتمة
مزايا:
يوجد تواصل تعريفي بين المراقب والمراقب المطلوب، لتحسين استجابة التغييرات التجارية.
زيادة مرونة النظام و expandability.
عيوب:
عند استخدام نموذج المراقب، يجب النظر في كفاءة التطوير وكفاءة التشغيل، حيث تتكون البرنامج من مراقب واحد، ومجموعة من المراقبين، وتحتوي عملية التطوير والتحقق من الخطأ على تعقيد، وعمومًا يتم تنفيذ إشعارات الرسائل في Java بشكل متسلسل، لذا إذا تأخر مراقب واحد، سيؤثر ذلك على كفاءة التنفيذ الكلية، وفي هذه الحالة، يتم عادة استخدام التنفيذ المتسلسل.
بالنسبة للمقربين من محتوى Android، يمكنهم التحقق من مواضيع هذا الموقع: 'تدريب بداية وتطوير Android'، 'نصائح الت调试 وطرق حل المشاكل الشائعة في Android'، 'تجميع استخدامات العناصر الأساسية في Android'، 'تجميع نصائح حول كيفية استخدام Android View'، 'تجميع نصائح حول كيفية استخدام Android layout'، وكذلك 'تجميع استخدامات التحكمات في Android'.
نتمنى أن يكون هذا المقال قد ساعد الجميع في تصميم برمجيات Android.
بيان: محتوى هذا المقال تم جمعه من الإنترنت، يحق لصاحب الحقوق أن يكون هو المالك، يتم جمع المحتوى بواسطة المساهمين في الإنترنت بطرقهم الخاصة، هذا الموقع لا يمتلك الحقوق، ولا يتم تعديل المحتوى بشكل يدوي، ولا يتحمل أي مسؤولية قانونية ذات صلة. إذا اكتشفتم محتوى يخالف حقوق النسخ، الرجاء إرسال بريد إلكتروني إلى: notice#oldtoolbag.com (الرجاء استبدال # ب @ عند إرسال البريد الإلكتروني) لإبلاغنا، وتقديم الدليل ذات الصلة، إذا تم التحقق من ذلك، سيتم حذف المحتوى المزعج فورًا.