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

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

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

ميزات النمط في جافا

تعقيد:

شعبية:

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

أمثلة على الحالة في مكتبات Java القياسية:

  • javax.faces.lifecycle.LifeCycle#execute() (يتم التحكم فيه من FacesServlet: يعتمد السلوك على مرحلة JSF الحالية)

علامات استخدام النمط:تقوم أساليب الفصل بتفويض العمل إلى كائن واحد متداخل.

مشغل الصوت

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

تنص على

الدول/State.java:واجهة الحالة المشتركة

package site.state.example..state.example.ui.Player; /** * واجهة مشتركة لجميع الدول. */ public Abstract class State ( Player player; /** * يمرر السياق نفسه إلى مُنشئ الحالة حتى تتمكن الدولة من * الوصول إلى بياناتها وأساليبها في المستقبل إذا لزم الأمر. */ State(Player player) ( this.player = player ;) سلسلة مجردة عامة onLock(); سلسلة مجردة عامة onPlay(); سلسلة مجردة عامة onNext(); سلسلة مجردة عامة onPrevious();)

الدول/LockedState.java:الدولة "مقفلة"

package site.state.example..state.example.ui.Player; /** * تطبق الحالات الملموسة أساليب الحالة المجردة بطريقتها الخاصة. */ الطبقة العامة LockedState تمتد الحالة ( LockedState(Player player) ( super(player); player.setPlaying(false); ) @Override public String onLock() ( if (player.isPlaying()) ( player.changeState(new ReadyState (لاعب)); إرجاع "إيقاف التشغيل"; ) آخر ( إرجاع "مغلق..."; ) ) @Override public String onPlay() ( player.changeState(new ReadyState(player)); إرجاع "جاهز"; ) @ تجاوز السلسلة العامة onNext() ( إرجاع "مقفل..."; ) @Override السلسلة العامة onPrevious() ( إرجاع "مقفل..."; ) )

الدول/ReadyState.java:حالة الاستعداد

package site.state.example..state.example.ui.Player; /** * يمكنهم أيضًا نقل السياق إلى حالات أخرى. */ الطبقة العامة ReadyState توسع الحالة ( public ReadyState(Player player) ( super(player); ) @Override public String onLock() ( player.changeState(new LockedState(player)); return "Locked..."; ) @ تجاوز السلسلة العامة onPlay() (إجراء السلسلة = player.startPlayback(); player.changeState(new PlayingState(player)); إجراء الإرجاع;) @Override public String onNext() (إرجاع "Locked...";) @Override السلسلة العامة onPrevious() (إرجاع "مقفل..."؛))

الدول/PlayingState.java:حالة "اللعب".

package site.state.example..state.example.ui.Player; الطبقة العامة PlayingState توسع الحالة ( PlayingState(Player player) ( super(player); ) @Override public String onLock() ( player.changeState(new LockedState(player)); player.setCurrentTrackAfterStop(); إرجاع "توقف عن اللعب"; ) @Override public String onPlay() ( player.changeState(new ReadyState(player)); return "Paused..."; ) @Override public String onNext() ( return player.nextTrack(); ) @Override public String onPrevious( ) (إرجاع player.previousTrack(); ) )

ui

واجهة المستخدم/Player.java:لاعب

الحزمة site.state.example..state.example.states..state.example.states.State; import java.util.ArrayList; import java.util.List; مشغل الطبقة العامة (حالة الدولة الخاصة؛ اللعب المنطقي الخاص = خطأ؛ القائمة الخاصة قائمة التشغيل = ArrayList الجديدة<>()؛ الخاص int currentTrack = 0; public Player() ( this.state = new ReadyState(this); setPlaying(true); for (int i = 1; i<= 12; i++) { playlist.add("Track " + i); } } public void changeState(State state) { this.state = state; } public State getState() { return state; } public void setPlaying(boolean playing) { this.playing = playing; } public boolean isPlaying() { return playing; } public String startPlayback() { return "Playing " + playlist.get(currentTrack); } public String nextTrack() { currentTrack++; if (currentTrack >playlist.size() - 1) (currentTrack = 0;) إرجاع "التشغيل" + playlist.get(currentTrack); ) سلسلة عامة PreviousTrack () (currentTrack--؛ إذا (currentTrack< 0) { currentTrack = playlist.size() - 1; } return "Playing " + playlist.get(currentTrack); } public void setCurrentTrackAfterStop() { this.currentTrack = 0; } }

واجهة المستخدم/UI.java:واجهة المستخدم الرسومية للمشغل

package site.state.example.ui; استيراد javax.swing.*; import java.awt.*; واجهة مستخدم فئة عامة (مشغل خاص؛ JTextField textField ثابت خاص = JTextField () جديد؛ واجهة مستخدم عامة (مشغل لاعب) (this.player = player؛) init باطل عام () (إطار JFrame = JFrame جديد ("مشغل اختبار")؛ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); سياق JPanel = new JPanel(); context.setLayout(new BoxLayout(context, BoxLayout.Y_AXIS));frame.getContentPane().add(context); أزرار JPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); context.add(textField); context.add(buttons); // يتسبب السياق في استجابة الحالة لإدخال المستخدم // بدلاً من الاستجابة نفسها. قد يختلف التفاعل اعتمادًا على الحالة // موجود حاليًا. نشط. JButton play = new JButton("Play"); play.addActionListener(e -> textField.setText(player.getState().onPlay())); JButton stop = new JButton("Stop") ; stop.addActionListener (e -> textField.setText(player.getState().onLock())); JButton next = new JButton("Next"); next.addActionListener(e -> textField.setText(player.getState( ).على التالي( )))؛ JButton prev = new JButton("السابق"); prev.addActionListener(e -> textField.setText(player.getState().onPrevious())); frame.setVisible(true); frame.setSize(300, 100); Buttons.add(play); Buttons.add(stop); Buttons.add(next); Buttons.add(prev); ))

جافا التجريبي:رمز العميل

package refactoring_guru.state..state.example.ui..state.example.ui.UI; /** * فئة تجريبية. هذا هو المكان الذي يأتي كل ذلك معا. */ عرض توضيحي للفئة العامة ( public static void main(String args) ( Player player = new Player(); UI ui = new UI(player); ui.init(); ) ) "النمطولاية"مصدر .ru

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

الشروط، المهمة، الغرض

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

تحفيز

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

الفكرة الرئيسية لهذا النمط هي تقديم فئة مجردة TCPStateلتمثيل حالات الاتصال المختلفة. تعلن هذه الفئة عن واجهة مشتركة لجميع الفئات التي تصف مصادر العمل المختلفة.ru

حالة. في هذه الفئات الفرعية TCPStateيتم تنفيذ السلوك الخاص بالدولة. على سبيل المثال، في الفصول الدراسية تم إنشاء TCPEو TPCمغلقتم تنفيذ السلوك الخاص بالدولة مقررو مغلقعلى التوالى. موقع الويب المصدر الأصلي

موقع الموقع المصدر الأصلي

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

وفي كل مرة تتغير حالة الاتصالاتصال TCPيغير كائن حالته. على سبيل المثال، عند إغلاق الاتصال القائم، اتصال TCPيستبدل مثيل فئة تم إنشاء TCPEينسخ TPCمغلق. موقع الموقع المصدر الأصلي

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

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

حل

موقع مصدر الموقع الأصلي

original.ru

المشاركون في نمط الدولة

المصدر original.ru
  1. سياق(TCPConnection) - السياق.
    يحدد واجهة واحدة للعملاء.
    يخزن مثيل فئة فرعية حالة الخرسانةالذي يحدد الوضع الحالي. original.ru
  2. ولاية(TCPState) - الحالة.
    يحدد واجهة لتغليف السلوك المرتبط بحالة سياق معينة. المصدر original.ru
  3. الفئات الفرعية حالة الخرسانة(TCPEstablished، TCPListen، TCPClosed) - حالة محددة.
    تقوم كل فئة فرعية بتنفيذ السلوك المرتبط ببعض حالات السياق سياق. موقع الويب المصدر الأصلي

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

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

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

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

وفي هذه الحالة أيضاً سياقأو الفئات الفرعية نفسها حالة الخرسانةيمكنه أن يقرر تحت أي ظروف وبأي ترتيب يحدث تغيير الحالات. مصدر .ru

أسئلة بخصوص تنفيذ نمط الدولة

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

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

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

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

    موقع مصدر الموقع الأصلي
  4. باستخدام التغيير الديناميكي.
    من الممكن تغيير السلوك حسب الطلب عن طريق تغيير فئة الكائن في وقت التشغيل، ولكن معظم اللغات الموجهة للكائنات لا تدعم ذلك. الاستثناء هو Perl وJavaScript واللغات الأخرى المستندة إلى محرك البرمجة النصية والتي توفر مثل هذه الآلية وبالتالي تدعم حالة النمط مباشرة. يسمح هذا للكائنات بتغيير سلوكها عن طريق تغيير رمز الفصل الخاص بها. source.ru الأصلي

    المصدر الأصلي.ru

نتائج

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

مثال

دعونا نلقي نظرة على تنفيذ المثال من القسم ""، أي. بناء بعض بنية اتصال TCP البسيطة. هذه نسخة مبسطة من بروتوكول TCP، وهي بالطبع لا تمثل البروتوكول بأكمله أو حتى جميع حالات اتصالات TCP. الموقع مصدر الموقع الأصلي

أولا وقبل كل شيء، دعونا نحدد الفئة اتصال TCP، والذي يوفر واجهة لنقل البيانات ويتعامل مع طلبات تغيير الحالة: TCPConnection. source.ru الأصلي

في متغير الأعضاء ولايةفصل اتصال TCPيتم تخزين مثيل للفئة TCPState. تقوم هذه الفئة بتكرار واجهة تغيير الحالة المحددة في الفئة اتصال TCP. موقع مصدر الموقع الأصلي

المصدر original.ru

اتصال TCPيفوض جميع الطلبات المعتمدة على الحالة إلى المثيل المخزن في الحالة TCPState. أيضا في الصف اتصال TCPهناك عملية دولة التغيير، والذي يمكنك من خلاله كتابة مؤشر إلى كائن آخر في هذا المتغير TCPState. منشئ الطبقة اتصال TCPتهيئة ولايةمؤشر إلى حالة مغلقة TPCمغلق(سنقوم بتعريفه أدناه). source.ru

موقع مصدر الموقع الأصلي

كل عملية TCPStateيقبل المثال اتصال TCPكمعلمة، وبالتالي السماح للكائن TCPStateالوصول إلى بيانات الكائن اتصال TCPوتغيير حالة الاتصال. .ru

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

source.ru

في الفئات الفرعية TCPStateيتم تنفيذ السلوك المعتمد على الدولة. يمكن أن يكون اتصال TCP في العديد من الحالات: مقرر(المثبتة)، الاستماع(الاستماع)، مغلق(مغلق)، وما إلى ذلك، ولكل منهم فئة فرعية خاصة به TCPState. للتبسيط، سننظر بالتفصيل في 3 فئات فرعية فقط - تم إنشاء TCPE, TCPListenو TPCمغلق. موقع الويب مصدر الموقع الأصلي

المصدر الأصلي.ru

في الفئات الفرعية TCPStateينفذ السلوك المعتمد على الحالة لتلك الطلبات الصالحة في تلك الحالة. المصدر original.ru

الموقع مصدر الموقع الأصلي

بعد تنفيذ الإجراءات الخاصة بالدولة، يتم تنفيذ هذه العمليات موقع الموقع المصدر الأصلي

سبب دولة التغييرلتغيير حالة الكائن اتصال TCP. هو نفسه ليس لديه معلومات حول بروتوكول TCP. إنها فئات فرعية TCPStateتحديد التحولات بين الدول والإجراءات التي يمليها البروتوكول. موقع الويب المصدر الأصلي

رو الأصلي

التطبيقات المعروفة لنمط الدولة

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

لتعكس اعتماد سلوك المحرر على الأداة الحالية، يمكنك استخدام نمط الحالة. موقع الويب المصدر الأصلي

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

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

موقع مصدر الموقع الأصلي

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

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

مقدمة

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

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

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

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

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

أمثلة التطبيق: 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); System.out.println(context.getState().ToString()); ) )

الخطوة 5

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

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

آخر تحديث: 31/10/2015

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

متى يتم استخدام هذا النمط؟

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

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

يقترح مخطط UML لنمط التصميم هذا النظام التالي:

التعريف الرسمي للنمط في C#:

برنامج الفصل ( static void Main() ( سياق السياق = سياق جديد (new StateA()); context.Request(); // اذهب إلى StateB context.Request(); // اذهب إلى StateA ) ) حالة فئة مجردة ( عامة مجردة مقبض باطلة (سياق السياق)؛) فئة StateA: الحالة (تجاوز عام مقبض باطلة (سياق السياق) ( context.State = new StateB(); ) ) فئة StateB: الحالة (تجاوز عام مقبض باطلة (سياق السياق) ( context. State = new StateA(); ) فئة السياق (حالة الحالة العامة ( get; set; ) سياق عام (حالة الحالة) ( this.State = State; ) طلب باطلة عامة () ( this.State.Handle(this ); ) )

المشاركون في النموذج

    الحالة: تحدد واجهة الحالة

    الفئتان StateA وStateB هما تطبيقان ملموسان للحالات

    السياق: يمثل كائنًا يجب أن يتغير سلوكه ديناميكيًا وفقًا للحالة. يتم تفويض تنفيذ إجراءات محددة إلى كائن الحالة

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

برنامج الفصل ( static void Main(string args) ( Water water = new Water(WaterState.LIQUID); water.Heat(); water.Frost(); water.Frost(); Console.Read(); ) ) تعداد WaterState (SOLID، LIQUID، GAS) فئة المياه (حالة WaterState العامة (get؛ set؛) المياه العامة (WaterState ws) (الحالة = ws؛) الحرارة باطلة عامة () (if(State==WaterState.SOLID) (Console.WriteLine ("تحويل الجليد إلى سائل"); الحالة = WaterState.LIQUID; ) وإلا إذا (الحالة == WaterState.LIQUID) ( Console.WriteLine("تحويل السائل إلى بخار"); ​​State = WaterState.GAS; ) وإلا إذا (State == WaterState.GAS) ( Console.WriteLine("زيادة درجة حرارة بخار الماء"); ) ) الفراغ العام Frost() ( if (State == WaterState.LIQUID) ( Console.WriteLine("تحويل السائل إلى ثلج" "); الحالة = WaterState.SOLID; ) else if (State == WaterState.GAS) ( Console.WriteLine("تحويل بخار الماء إلى سائل"); State = WaterState.LIQUID; ) ) )

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

برنامج الفصل (الفراغ الثابت الرئيسي (وسائط السلسلة) ( ماء الماء = ماء جديد (جديد LiquidWaterState ()) ؛ water.Heat ()؛ water.Frost ()؛ water.Frost ()؛ Console.Read ()؛ ) ) فئة الماء (حالة IWaterState العامة ( get; set; ) المياه العامة (IWaterState ws) ( State = ws; ) الحرارة باطلة عامة () ( State.Heat(this); ) العامة باطلة Frost() ( State.Frost(this); ) ) واجهة IWaterState ( الحرارة باطلة (ماء الماء)؛ باطلة الصقيع (ماء الماء)؛ ) فئة SolidWaterState: IWaterState ( الحرارة باطلة عامة (ماء الماء) ( Console.WriteLine ("تحويل الجليد إلى سائل")؛ water.State = جديد LiquidWaterState();) الفراغ العام Frost(ماء الماء) ( Console.WriteLine("مواصلة تجميد الجليد"); ) ) فئة LiquidWaterState: IWaterState (الحرارة الفراغية العامة(ماء الماء) ( Console.WriteLine("تحويل السائل إلى بخار" ) ؛ water.State = new GasWaterState(); ) الفراغ العام Frost(ماء الماء) ( Console.WriteLine("تحويل السائل إلى جليد"); water.State = new SolidWaterState(); ) ) فئة GasWaterState: IWaterState (الفراغ العام الحرارة (ماء الماء) ( Console.WriteLine("زيادة درجة حرارة بخار الماء"); ) الفراغ العام Frost(ماء الماء) ( Console.WriteLine("تحويل بخار الماء إلى سائل"); water.State = new LiquidWaterState(); ) )

وبالتالي، فإن تنفيذ نمط الحالة يسمح لك بنقل السلوك الذي يعتمد على الحالة الحالية للكائن إلى فئات منفصلة، ​​وتجنب التحميل الزائد لطرق الكائن باستخدام بنيات شرطية مثل if..else أو Switch. بالإضافة إلى ذلك، إذا لزم الأمر، يمكننا إدخال فئات جديدة من الحالات في النظام، واستخدام فئات الحالات الموجودة في كائنات أخرى.

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

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

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

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

مناقشة نمط الدولة

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

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

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

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

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

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

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

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

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

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

ملامح نمط الدولة

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

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

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

#يشمل استخدام اسم للمحطة؛ آلة الفئة (حالة الفئة * الحالية؛ العامة: آلة ()؛ باطلة setCurrent(State *s) (current = s;) void on(); void off(); ); حالة الفصل (عام: الفراغ الظاهري on(Machine *m) (cout<< " already ON\n"; } virtual void off(Machine *m) { cout << " already OFF\n"; } }; void Machine::on() { current->على هذا)؛ ) آلة باطلة::off() (current->off(this);) فئة ON: الحالة العامة ( public: ON() ( cout<< " ON-ctor "; }; ~ON() { cout << " dtor-ON\n"; }; void off(Machine *m); }; class OFF: public State { public: OFF() { cout << " OFF-ctor "; }; ~OFF() { cout << " dtor-OFF\n"; }; void on(Machine *m) { cout << " going from OFF to ON"; m->setCurrent(new ON()); امسح هذه؛ ))); باطلة ON::off(Machine *m) (cout<< " going from ON to OFF"; m->setCurrent(new OFF()); امسح هذه؛ ) Machine::Machine() (current = new OFF(); cout<< "\n"; } int main() { void(Machine:: *ptrs)() = { Machine::off, Machine::on }; Machine fsm; int num; while (1) { cout << "Enter 0/1: "; cin >> الأعداد؛ (fsm.*ptrs)(); ))