حالة النمط جافا ولاية

يسمح للكائن بتغيير سلوكه اعتمادًا على حالته الداخلية. من الخارج يبدو أن فئة الكائن قد تغيرت.

يتضمن نمط "الحالة" تخصيص فئة أساسية أو واجهة لجميع العمليات الصالحة ووريثًا لكل حالة محتملة

متى يتم استخدام نمط الحالة

    عندما يجب أن يعتمد سلوك الكائن على حالته ويمكن أن يتغير ديناميكيًا في وقت التشغيل

    عندما يستخدم رمز أساليب الكائن العديد من البنيات الشرطية، يعتمد اختيارها على الحالة الحالية للكائن

مخطط UML لنمط "الحالة":

تنفيذ نمط "الحالة" في C#

باستخدام النظام؛ مساحة الاسم DoFactory.GangOfFour.State.Structural ( /// /// فئة بدء التشغيل MainApp للهيكلية /// نمط تصميم الحالة. ///فئة التطبيق الرئيسي ( /// /// نقطة الدخول إلى تطبيق وحدة التحكم. /// static void Main() ( // سياق الإعداد في حالة سياق c = سياق جديد (new ConcreteStateA()); // إصدار الطلبات، الذي يقوم بتبديل الحالة c.Request(); c.Request(); c.Request() c.Request(); // انتظر المستخدم Console.ReadKey() ) /// /// فئة مجردة "الدولة" ///حالة فئة مجردة (مقبض باطلة مجردة عامة (سياق السياق)؛) /// فئة ConcreteStateA: الحالة (تجاوز عام void Handle(Context context) ( context.State = new ConcreteStateB(); ) ) /// /// فئة "ConcreteState" ///فئة ConcreteStateB: الحالة (تجاوز عام void Handle(Context context) ( context.State = new ConcreteStateA(); ) ) /// /// فئة "السياق" ///فئة السياق (حالة خاصة _state; // المُنشئ public context(حالة الحالة) ( this.State = State; ) // الحصول على الحالة أو تعيينها حالة الحالة العامة ( get ( return _state; ) set ( _state = value; Console.WriteLine ("الحالة: " + _state.GetType().Name)؛ طلب الفراغ العام () _state.Handle(this); ) )

مثال على نمط الدولة من واقع الحياة

أمثلة في .NET Framework

  • يقوم CommunicationObject بتنفيذ جهاز حالة للانتقال بين حالات عميل WCF: تم الإنشاء، والفتح، والمفتوح، والإغلاق، والمغلق، والخطأ.
  • تنفذ المهمة جهاز حالة محدود للانتقال بين حالات المهمة: تم الإنشاء، WaitingForActivation، WaitingToRun، Running، Run ToCompletion، Canceled، Faulted.

في نظام الدولة (نموذج الدولة)، يعتمد سلوك الطبقة على حالتها المتغيرة. يشير هذا النوع من أنماط التصميم إلى النماذج السلوكية.

في نموذج الحالة، نقوم بإنشاء كائنات وحالات سلوكية مختلفة جنبًا إلى جنب مع حالة الكائن التي يتم تعديلها عن طريق تمثيل معدل لسياق الكائن.

مقدمة

النية: السماح للكائن بتغيير سلوكه عندما تتغير الحالة الداخلية، ثم يظهر الكائن ليغير فئته.

الحل بشكل أساسي: سلوك الكائن يعتمد على حالته (سماته) ويمكنك تغييره وفقًا لحالته المتعلقة بتغير السلوك.

متى يتم الاستخدام: يحتوي الكود على عدد كبير من الكائنات المتعلقة بحالة العبارات الشرطية.

كيفية الإصلاح: انتهت حالة الفئات المجردة الملموسة.

رمز المفتاح: وضع واجهة الأوامر، عادةً ما يكون طريقة واحدة فقط.حالة الواجهة التي تحتوي على طريقة واحدة أو أكثر. بالإضافة إلى ذلك، عادةً ما تقوم طريقة وضع الحالة الخاصة بفئة التنفيذ بإرجاع قيمة أو تغيير قيمة متغير مثيل. أي أن حالة وحالة نموذج الكائن عادة ما تكون محدثة. أساليب فئة التنفيذ لها وظائف مختلفة، ويتم تغطية أساليب الواجهة. يمكن استخدام وضع الشرط ووضع الأوامر بنفس الطريقة للتخلص من الشروط الأخرى في حالة... اختيار آخر.

أمثلة التطبيق: 1، لعب كرة السلة، يمكن أن يكون لدى اللاعب حالة طبيعية، وليس حالة طبيعية وحالة غير طبيعية. 2، أجراس ماركيز يي تسنغ، ثم "واجهة مجردة على مدار الساعة"، و"الساعة أ" وغيرها من الحالات الملموسة، وبيئة محددة "" الأجراس الصينية (السياق).

المزايا: 1، بتغليف قواعد التحويل. 2، قائمة الحالات المحتملة قبل إدراج الدولة تحتاج إلى تحديد حالة الأنواع. 3. كل شيء يتعلق بسلوك الحالة مرتبط بالفصل، ويمكنك بسهولة إضافة حالة جديدة، ما عليك سوى تغيير حالة الكائن الذي يمكنه تغيير سلوك الكائنات. 4، مما يجعل من الممكن إجراء انتقال الحالة - الحالة المنطقية للكائن في كتلة واحدة ضخمة من البيانات الشرطية. 5، يسمح لكائنات متعددة بمشاركة بيئة حالة الكائن، وبالتالي تقليل عدد الكائنات في النظام.

العيوب: 1، يرتبط نمط حالة الاستخدام بزيادة في عدد فئات النظام وكائناته. 2، هيكل وتنفيذ نموذج الحالة أكثر تعقيدًا، إذا تم استخدامه بشكل غير صحيح، فقد يسبب ارتباكًا في بنية البرنامج والتعليمات البرمجية. 3. دعم نموذج الحالة "المبدأ المفتوح والمغلق" ليس جيدًا جدًا، يمكنك تبديل حالة نموذج الحالة عن طريق إضافة فئات جديدة، وتحتاج إلى تغيير حالة المسؤولين عن انتقالات حالة الكود المصدري، أو لا يمكن التبديل إلى حالة جديدة، وتغيير حالة الفصل للعمل أيضًا، من الضروري تعديل الكود المصدري للفئة المقابلة.

حالات الاستخدام: 1، مع تغيير الحالة وسلوك تغيير المشهد. 2، تأكيد الانتقال المشروط بالاستبدال.

ملحوظة: عند استخدام سلوك الحالة المحدود حسب وضع الحالة، ولا تزيد الحالة عن خمسة.

تطبيق

سنقوم بإنشاء واجهة الحالة والكيان ولايةفئة تنفيذ الواجهة ولاية.سياقيمثل فئة ذات حالة محددة.

ستاتباترنديمو,نعرض استخدام الأشياء سياقسياق الطبقة والحالة لإثبات التغيير السلوكي في حالة التغيير.

الخطوة 1

إنشاء واجهة.

State.java

حالة الواجهة العامة (doAction الفراغ العام (سياق السياق)؛)

الخطوة 2

قم بإنشاء فئة كيان تقوم بتنفيذ الواجهة.

StartState.java

تنفذ الطبقة العامة StartState الحالة ( public void DoAction(context context) ( System.out.println("اللاعب في حالة البداية"); context.setState(this);) String ToString() العامة (إرجاع "حالة البداية";) )

StopState.java

تقوم الطبقة العامة StopState بتنفيذ الحالة ( public void doAction(Context context) ( System.out.println("اللاعب في حالة التوقف"); context.setState(this); ) public String toString())( return "Stop State"; ))

الخطوه 3

إنشاء فصل دراسي سياق.

سياق.java

فئة عامة (حالة حالة خاصة بالسياق؛ سياق عام () (حالة = NULL؛) SetState باطلة عامة (حالة الحالة) (this.state = State;) الحالة العامة GetState () (حالة الإرجاع؛))

الخطوة 4

يستخدم سياقلرؤية السلوك عندما تتغير حالة التغيير حالة.

StatePatternDemo.java

الطبقة العامة StatePatternDemo(state static force main(String)(agdz context context = سياق جديد(); StartState startState = new StartState(); startState.doAction(context); System.out.println(context.getState()) ToString( ) .); StopState stopState = new StopState(); stopState.doAction(context);

الخطوة 5

تحقق من الإخراج.

اللاعب في حالة البداية حالة البداية اللاعب في حالة التوقف

باستخدام النظام؛ حالة مساحة الاسم ( ///

/// حالة الحساب محظورة. ///الطبقة العامة محظورة: IState ( /// /// قم بتعبئة حسابك. /// /// حساب قابل لإعادة التعبئة. /// مبلغ التجديد. public void Deposit(Card Card, decimal money) ( // تحقق من صحة وسائط الإدخال. if (card == null) ( throw new ArgumentNullException(nameof(card)); ) if (money<= 0) { throw new ArgumentException("Вносимая сумма должна быть больше нуля.", nameof(money)); } // Вычисляем сумму сверхлимитной задолженности. var overdraft = card.CreditLimit - card.Credit; // Вычисляем насколько сумма пополнения перекрывает задолженность. var difference = money - overdraft; if (difference < 0) { // Если сумма пополнения не перекрывает задолженность, // то просто уменьшаем сумму задолженности. card.Credit += money; // Вычисляем процент оставшейся суммы на счете. var limit = card.Credit / card.CreditLimit * 100; if (limit < 10) { // Если после пополнения на счете все еще меньше десяти процентов от лимита, // то просто сообщаем об этом пользователю. Console.WriteLine($"Ваш счет пополнен на сумму {money}. " + $"Сумма на вашем счете все еще составляет менее 10%. Ваш счет остался заблокирован. Пополните счет на большую сумму. {card.ToString()}"); } else if (limit >= 10 && الحد< 100) { // Если задолженность перекрыта не полностью, то переводим в состояние расходования кредитных средств. card.State = new UsingCreditFunds(); Console.WriteLine($"Ваш счет пополнен на сумму {money}. Задолженность частично погашена. " + $"Погасите задолженность в размере {Math.Abs(difference)} рублей. {card.ToString()}"); } else { // Иначе задолженность полностью погашена, переводим в состояние расходования собственных средств. card.State = new UsingOwnFunds(); Console.WriteLine($"Ваш счет пополнен на {money} рублей. Задолженность полностью погашена. {card.ToString()}"); } } else { // Иначе закрываем задолженность, а оставшиеся средства переводим в собственные средства. card.Credit = card.CreditLimit; card.Debit = difference; // Переводим карту в состояние использования собственных средств. card.State = new UsingOwnFunds(); Console.WriteLine($"Ваш счет пополнен на {money} рублей. " + $"Кредитная задолженность погашена. {card.ToString()}"); } } /// /// الإنفاق من الحساب. /// /// حساب الشطب. /// تكلفة الشراء. /// نجاح العملية. public bool Spend(بطاقة البطاقة، السعر العشري) ( // رفض العملية. Console.WriteLine($"حسابك محظور. قم بتعبئة حسابك. (card.ToString())"); return false; ) ) )

اسم النمط وتصنيفه

الحالة هي نمط من سلوك الأشياء.

الغرض من نمط الدولة

يسمح نمط الحالة للكائن بتغيير سلوكه اعتمادًا على حالته الداخلية. يبدو أن الكائن قد تغير فئته.

نمط الحالة هو تطبيق موجه للكائنات لآلة الحالة.

المشكلة التي يتعين حلها

يعتمد سلوك الكائن على حالته ويجب أن يتغير أثناء تنفيذ البرنامج. يمكن تنفيذ مثل هذا المخطط باستخدام العديد من العوامل الشرطية: بناءً على تحليل الحالة الحالية للكائن، يتم اتخاذ إجراءات معينة. ومع ذلك، مع وجود عدد كبير من الحالات، ستكون العبارات الشرطية متناثرة في جميع أنحاء الكود، وسيكون من الصعب صيانة مثل هذا البرنامج.

يحل نمط الحالة هذه المشكلة على النحو التالي:

  • يقدم فئة السياق، التي تحدد واجهة للعالم الخارجي؛
  • يقدم فئة الحالة المجردة؛
  • يمثل "الحالات" المختلفة لجهاز الدولة كفئات فرعية للدولة؛
  • تحتوي فئة السياق على مؤشر للحالة الحالية، والذي يتغير عندما تتغير حالة آلة الحالة.

لا يحدد نمط الحالة المكان الذي يتم فيه تحديد شرط الانتقال إلى حالة جديدة بالضبط. هناك خياران: فئة السياق أو الفئات الفرعية للحالة. ميزة الخيار الأخير هي أنه من السهل إضافة فئات مشتقة جديدة. العيب هو أن كل فئة فرعية من الدولة يجب أن تعرف عن جيرانها للانتقال إلى دولة جديدة، مما يؤدي إلى ظهور تبعيات بين الفئات الفرعية.

هناك أيضًا نهج بديل قائم على الجدول لتصميم أجهزة الحالة المحدودة، استنادًا إلى استخدام جدول يقوم بشكل فريد بتعيين بيانات الإدخال للانتقالات بين الحالات. ومع ذلك، فإن هذا النهج له عيوب: فمن الصعب إضافة تنفيذ الإجراءات عند تنفيذ التحولات. يستخدم أسلوب نمط الحالة التعليمات البرمجية (بدلاً من هياكل البيانات) لإجراء انتقالات بين الحالات، بحيث يسهل إضافة هذه الإجراءات.

هيكل نمط الدولة

تحدد فئة السياق الواجهة الخارجية للعملاء وتخزن مرجعًا للحالة الحالية لكائن الحالة. واجهة حالة الفئة الأساسية المجردة هي نفس واجهة السياق، باستثناء معلمة إضافية واحدة - مؤشر لمثيل السياق. تحدد الفئات المشتقة من الحالة السلوك الخاص بالحالة. تقوم فئة مجمّع السياق بتفويض جميع الطلبات المستلمة إلى كائن "الحالة الحالية"، والذي يمكنه استخدام المعلمة الإضافية المستلمة للوصول إلى مثيل السياق.

مخطط فئة UML لنمط الحالةيظهر هيكل نمط الحالة في الشكل. 71.

context.setState(StateTwo);

أرز. 71. مخطط UML لنمط الحالة

مشاركون

السياق - السياق:

  • يحدد الواجهة التي تهم العملاء؛
  • يخزن مثيل للفئة الفرعية ConcreteState التي تحدد الحالة الحالية.

الحالة: تحدد واجهة لتغليف السلوك المرتبط بحالة سياق معينة.

الفئات الفرعية StateOne وStateTwo وStateThree - حالة محددة: تقوم كل فئة فرعية بتنفيذ السلوك المرتبط ببعض حالات السياق.

علاقة

تقوم فئة السياق بتفويض الطلبات المعتمدة على الحالة إلى كائن ConcreteState الحالي.

يمكن للسياق تمرير نفسه كوسيطة إلى كائن الحالة الذي سيقوم بمعالجة الطلب. يسمح هذا لكائن الحالة بالوصول إلى السياق عند الحاجة.

السياق هو الواجهة الرئيسية للعملاء. يمكن للعملاء تكوين السياق باستخدام كائنات الحالة. بمجرد تكوين السياق، لم يعد العملاء بحاجة إلى التواصل مباشرة مع كائنات الحالة.

يمكن للفئات الفرعية للسياق أو ConcreteState أن تقرر تحت أي ظروف وبأي ترتيب تتغير الحالات.

مثال على نمط الدولة

يسمح نمط الحالة للكائن بتغيير سلوكه اعتمادًا على حالته الداخلية. ويمكن ملاحظة صورة مماثلة في تشغيل آلة البيع. يمكن أن يكون لآلات البيع حالات مختلفة اعتمادًا على توفر البضائع، وكمية العملات المعدنية المستلمة، وإمكانية تبادل الأموال، وما إلى ذلك. بعد أن يختار المشتري البضائع ويدفع ثمنها، تكون المواقف (الحالات) التالية ممكنة:

  • إعطاء البضائع للمشتري، ليست هناك حاجة لإعطاء التغيير؛
  • إعطاء المشتري البضائع والتغيير؛
  • لن يحصل المشتري على البضائع بسبب عدم وجود أموال كافية؛
  • لن يحصل المشتري على البضائع بسبب غيابها.

باستخدام نمط الدولة

حدد فئة مجمّع سياق موجودة أو أنشئ فئة جديدة سيستخدمها العميل كجهاز حالة.

قم بإنشاء فئة حالة أساسية تكرر واجهة فئة السياق. تأخذ كل طريقة معلمة إضافية واحدة: مثيل لفئة السياق. يمكن لفئة الحالة تحديد أي سلوك افتراضي مفيد.

إنشاء فئات مشتقة من الحالة لجميع الحالات الممكنة.

تقوم فئة السياق ببساطة بتفويض كافة الطلبات المستلمة من العميل إلى كائن "الحالة الحالية"، ويتم تمرير عنوان كائن السياق كمعلمة إضافية.

باستخدام هذا العنوان، يمكن لطرق فئة الحالة تغيير "الحالة الحالية" لفئة السياق إذا لزم الأمر.

تنفيذ نمط الدولة

دعونا نفكر في مثال لآلة الحالة المحدودة مع حالتين محتملتين وحدثين.

استخدام اسم للمحطة؛

حالة الفئة * الحالية؛ عام:

مجموعة باطلة الحالية (الحالة * s)

باطل على ()؛ باطل () ؛

الفراغ الظاهري على (الجهاز * م)

الفراغ الظاهري لـT(الجهاز *م)

آلة باطلة::on()

الحالي->على(هذا);

آلة باطلة::off()

الحالي->إيقاف(هذا);

فئة ON: الحالة العامة

باطل قبالة (الجهاز * م)؛

فئة OFF: الحالة العامة

باطلة على (الجهاز * م)

cout setCurrent(new ON()); امسح هذه؛

باطل على::إيقاف (الجهاز *م)

cout setCurrent(new OFF()); امسح هذه؛

آلة::آلة()

الحالي = إيقاف جديد()؛ cout

باطلة(الجهاز:: *ptrs)() =

الآلة::إيقاف، الآلة::تشغيل

آلة fsm. رقم كثافة العمليات؛ بينما (1)

(fsm.*ptrs)