---
title: "الحالة"
type: "design-pattern"
slug: "state"
url: "http://localhost:3000/ar/design-patterns/state.md"
category: "الأنماط السلوكية"
description: "الحالة (State) هو نمط تصميم سلوكي يتيح لكائنٍ تغيير سلوكه عند تغيّر حالته الداخلية. ويبدو الأمر كما لو أنّ الكائن قد غيّر فئته."
languages: ["java", "csharp", "cpp", "go", "php", "python", "ruby", "rust", "swift", "typescript"]
---
# الحالة

> الحالة (State) هو نمط تصميم سلوكي يتيح لكائنٍ تغيير سلوكه عند تغيّر حالته الداخلية. ويبدو الأمر كما لو أنّ الكائن قد غيّر فئته.

## Intent

**الحالة (State)** هو نمط تصميم سلوكي يتيح لكائنٍ تغيير سلوكه عند تغيّر حالته الداخلية. ويبدو الأمر كما لو أنّ الكائن قد غيّر فئته.

## Problem

يرتبط نمط الحالة ارتباطاً وثيقاً بمفهوم _آلة الحالات المنتهية (Finite-State Machine)_ آلة الحالات المنتهية: <https://refactoring.guru/fsm>.

آلة الحالات المنتهية.

الفكرة الأساسية هي أنه، في أي لحظة معيّنة، يوجد عدد _منتهٍ_ من _الحالات_ التي يمكن أن يكون البرنامج فيها. وضمن أي حالة فريدة، يتصرّف البرنامج بشكل مختلف، ويمكن تبديل البرنامج من حالة إلى أخرى في الحال. غير أنه، تبعاً للحالة الراهنة، قد ينتقل البرنامج أو لا ينتقل إلى حالات أخرى معيّنة. وهذه القواعد للتبديل، التي تُسمّى _الانتقالات (transitions)_، منتهية ومحدّدة سلفاً أيضاً.

يمكنك تطبيق هذا الأسلوب على الكائنات أيضاً. تخيّل أن لدينا فئة `Document`. يمكن أن يكون المستند في إحدى ثلاث حالات: `Draft` و`Moderation` و`Published`. ويعمل الأسلوب `publish` الخاص بالمستند بشكل مختلف قليلاً في كل حالة:

* في `Draft`، ينقل المستند إلى المراجعة.
* في `Moderation`، يجعل المستند علنياً، لكن فقط إذا كان المستخدم الحالي مسؤولاً (administrator).
* في `Published`، لا يفعل أي شيء على الإطلاق.

الحالات والانتقالات الممكنة لكائن المستند.

عادةً ما تُطبَّق آلات الحالات باستخدام الكثير من عبارات الشرط (`if` أو `switch`) التي تختار السلوك المناسب تبعاً للحالة الراهنة للكائن. وغالباً ما تكون هذه «الحالة» مجرّد مجموعة من قيم حقول الكائن. وحتى لو لم تكن قد سمعت من قبل عن آلات الحالات المنتهية، فمن المرجّح أنك طبّقت حالةً مرة واحدة على الأقل. ألا يذكّرك هيكل الكود التالي بشيء؟

class Document is
    field state: string
    // ...
    method publish() is
        switch (state)
            "draft":
                state = "moderation"
                break
            "moderation":
                if (currentUser.role == "admin")
                    state = "published"
                break
            "published":
                // لا تفعل شيئاً.
                break
    // ...

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

وتميل المشكلة إلى التفاقم مع تطوّر المشروع. فمن الصعب جداً التنبّؤ بجميع الحالات والانتقالات الممكنة في مرحلة التصميم. ومن ثمّ، يمكن لآلة حالات رشيقة بُنيت بمجموعة محدودة من الشروط أن تتحوّل بمرور الوقت إلى فوضى متضخّمة.

## Solution

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

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

المستند يفوّض العمل إلى كائن حالة.

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

قد تبدو هذه البنية شبيهة بنمط [الاستراتيجية (Strategy)](/ar/design-patterns/strategy)، لكن هناك فرقاً جوهرياً واحداً. ففي نمط الحالة، قد تكون الحالات المعيّنة مدركة لبعضها وتبادر إلى الانتقالات من حالة إلى أخرى، في حين أن الاستراتيجيات لا تعرف بعضها تقريباً أبداً.

## Structure

1. **السياق (Context)** يحتفظ بمرجع إلى أحد كائنات الحالة المحسوسة ويفوّض إليه كل العمل الخاص بالحالة. يتواصل السياق مع كائن الحالة عبر واجهة الحالة. ويعرّض السياق دالة ضبط (setter) لتمرير كائن حالة جديد إليه.
2. **واجهة الحالة (State)** تُعلِن عن الأساليب الخاصة بالحالة. وينبغي أن تكون هذه الأساليب منطقية بالنسبة لجميع الحالات المحسوسة، لأنك لا تريد أن تحتوي بعض حالاتك على أساليب عديمة الفائدة لن تُستدعى أبداً.
3. **الحالات المحسوسة (Concrete States)** توفّر تطبيقاتها الخاصة للأساليب الخاصة بالحالة. ولتجنّب تكرار كود متشابه عبر حالات متعدّدة، يمكنك توفير فئات مجرّدة وسيطة تغلّف بعض السلوك المشترك.
قد تخزّن كائنات الحالة مرجعاً عكسياً إلى كائن السياق. ومن خلال هذا المرجع، يمكن للحالة جلب أي معلومات مطلوبة من كائن السياق، فضلاً عن بدء انتقالات الحالة.
4. يمكن لكلٍّ من السياق والحالات المحسوسة ضبط الحالة التالية للسياق وتنفيذ انتقال الحالة الفعلي باستبدال كائن الحالة المرتبط بالسياق.

## Pseudocode

في هذا المثال، يتيح نمط **الحالة (State)** لعناصر التحكّم نفسها في مشغّل الوسائط أن تتصرّف بشكل مختلف، تبعاً لحالة التشغيل الراهنة.

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

يكون الكائن الرئيسي للمشغّل مرتبطاً دائماً بكائن حالة يؤدّي معظم العمل نيابةً عن المشغّل. وتستبدل بعض الإجراءات كائن الحالة الحالي للمشغّل بآخر، مما يغيّر طريقة استجابة المشغّل لتفاعلات المستخدم.

// The AudioPlayer class acts as a context. It also maintains a
// reference to an instance of one of the state classes that
// represents the current state of the audio player.
class AudioPlayer is
    field state: State
    field UI, volume, playlist, currentSong

    constructor AudioPlayer() is
        this.state = new ReadyState(this)

        // يفوّض السياق معالجة مُدخلات المستخدم إلى كائن
        // حالة. وبطبيعة الحال، تعتمد النتيجة على الحالة
        // النشطة حالياً، لأن كل حالة يمكنها معالجة
        // المُدخلات بشكل مختلف.
        UI = new UserInterface()
        UI.lockButton.onClick(this.clickLock)
        UI.playButton.onClick(this.clickPlay)
        UI.nextButton.onClick(this.clickNext)
        UI.prevButton.onClick(this.clickPrevious)

    // يجب أن تتمكّن الكائنات الأخرى من تبديل الحالة
    // النشطة لمشغّل الصوت.
    method changeState(state: State) is
        this.state = state

    // تفوّض أساليب واجهة المستخدم التنفيذ إلى الحالة النشطة.
    method clickLock() is
        state.clickLock()
    method clickPlay() is
        state.clickPlay()
    method clickNext() is
        state.clickNext()
    method clickPrevious() is
        state.clickPrevious()

    // قد تستدعي الحالة بعض أساليب الخدمة على السياق.
    method startPlayback() is
        // ...
    method stopPlayback() is
        // ...
    method nextSong() is
        // ...
    method previousSong() is
        // ...
    method fastForward(time) is
        // ...
    method rewind(time) is
        // ...

// تُعلِن فئة الحالة الأساسية عن الأساليب التي ينبغي أن
// تنفّذها جميع الحالات المحسوسة، كما توفّر مرجعاً عكسياً إلى
// كائن السياق المرتبط بالحالة. ويمكن للحالات استخدام المرجع
// العكسي لنقل السياق إلى حالة أخرى.
abstract class State is
    protected field player: AudioPlayer

    // يمرّر السياق نفسه عبر مُنشئ الحالة. وقد يساعد ذلك
    // الحالة على جلب بعض بيانات السياق المفيدة إذا
    // لزم الأمر.
    constructor State(player) is
        this.player = player

    abstract method clickLock()
    abstract method clickPlay()
    abstract method clickNext()
    abstract method clickPrevious()

// تُنفّذ الحالات المحسوسة سلوكيات متنوعة مرتبطة بحالة
// معيّنة من حالات السياق.
class LockedState extends State is

    // عند إلغاء قفل مشغّل مقفل، قد يتّخذ إحدى
    // حالتين.
    method clickLock() is
        if (player.playing)
            player.changeState(new PlayingState(player))
        else
            player.changeState(new ReadyState(player))

    method clickPlay() is
        // مقفل، لذا لا تفعل شيئاً.

    method clickNext() is
        // مقفل، لذا لا تفعل شيئاً.

    method clickPrevious() is
        // مقفل، لذا لا تفعل شيئاً.

// يمكنها أيضاً إطلاق انتقالات الحالة في السياق.
class ReadyState extends State is
    method clickLock() is
        player.changeState(new LockedState(player))

    method clickPlay() is
        player.startPlayback()
        player.changeState(new PlayingState(player))

    method clickNext() is
        player.nextSong()

    method clickPrevious() is
        player.previousSong()

class PlayingState extends State is
    method clickLock() is
        player.changeState(new LockedState(player))

    method clickPlay() is
        player.stopPlayback()
        player.changeState(new ReadyState(player))

    method clickNext() is
        if (event.doubleclick)
            player.nextSong()
        else
            player.fastForward(5)

    method clickPrevious() is
        if (event.doubleclick)
            player.previous()
        else
            player.rewind(5)

## Applicability

استخدم نمط الحالة (State) عندما يكون لديك كائن يتصرّف بشكل مختلف تبعاً لحالته الحالية، ويكون عدد الحالات هائلاً، ويتغيّر الكود الخاص بكل حالة بشكل متكرّر.

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

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

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

 استخدم نمط الحالة عندما يكون لديك الكثير من الكود المكرّر عبر حالات وانتقالات متشابهة في آلة حالات قائمة على الشروط.

 يتيح لك نمط الحالة تأليف تسلسلات هرمية من فئات الحالة وتقليل التكرار باستخراج الكود المشترك إلى فئات أساسية مجرّدة.

## How to Implement

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

  * اجعل هذه الحقول أو الأساليب عامّة (public).
  * حوّل السلوك الذي تستخرجه إلى أسلوب عام في السياق واستدعِه من فئة الحالة. هذه الطريقة غير أنيقة لكنها سريعة، ويمكنك دائماً إصلاحها لاحقاً.
  * ضمّن فئات الحالة داخل فئة السياق، لكن فقط إذا كانت لغة البرمجة لديك تدعم تضمين الفئات.
4. في فئة السياق، أضِف حقل مرجع من نوع واجهة الحالة ودالة ضبط عامّة تسمح بإعادة كتابة قيمة ذلك الحقل.
5. تصفّح أسلوب السياق مرة أخرى واستبدل شروط الحالة الفارغة باستدعاءات للأساليب المقابلة في كائن الحالة.
6. لتبديل حالة السياق، أنشئ نسخة من إحدى فئات الحالة ومرّرها إلى السياق. يمكنك القيام بذلك داخل السياق نفسه، أو في حالات مختلفة، أو في العميل. وأينما جرى ذلك، تصبح الفئة معتمِدة على فئة الحالة المحسوسة التي تنشئها.

## Pros

* _مبدأ المسؤولية الواحدة (Single Responsibility Principle)_. تنظيم الكود المتعلّق بحالات معيّنة في فئات منفصلة.
* _مبدأ الفتح/الإغلاق (Open/Closed Principle)_. إدخال حالات جديدة دون تغيير فئات الحالة القائمة أو السياق.
* تبسيط كود السياق بإزالة شروط آلة الحالات الضخمة.

## Cons

* قد يكون تطبيق النمط مبالغة إذا كانت آلة الحالات تحتوي على عدد قليل فقط من الحالات أو نادراً ما تتغيّر.

## Relations with Other Patterns

* تتشارك أنماط [الجسر (Bridge)](/ar/design-patterns/bridge) و[الحالة (State)](/ar/design-patterns/state) و[الاستراتيجية (Strategy)](/ar/design-patterns/strategy) (وإلى حدٍّ ما [المُكيِّف (Adapter)](/ar/design-patterns/adapter)) في بنى متشابهة جداً. فجميع هذه الأنماط تقوم على التركيب (composition)، أي تفويض العمل إلى كائنات أخرى. غير أنها جميعاً تحلّ مشكلات مختلفة. فالنمط ليس مجرّد وصفة لهيكلة كودك بطريقة معيّنة، بل يمكنه أيضاً أن ينقل إلى المطوّرين الآخرين المشكلة التي يحلّها النمط.
* يمكن اعتبار نمط [الحالة (State)](/ar/design-patterns/state) امتداداً لنمط [الاستراتيجية (Strategy)](/ar/design-patterns/strategy). فكلا النمطين يقوم على التركيب: إذ يغيّران سلوك السياق بتفويض بعض العمل إلى كائنات مساعدة. تجعل _الاستراتيجية_ هذه الكائنات مستقلّة تماماً وغير مدركة لبعضها. أما _الحالة_ فلا تقيّد الاعتماديات بين الحالات المحسوسة، إذ تتيح لها تغيير حالة السياق كما تشاء.
## Relations

**Related patterns**

- [الجسر](/ar/design-patterns/bridge.md)
- [الاستراتيجية](/ar/design-patterns/strategy.md)
- [المهايئ (Adapter)](/ar/design-patterns/adapter.md)

## Code Examples

### java

```java
package refactoring_guru.state.example.states;

import refactoring_guru.state.example.ui.Player;

/**
 * Common interface for all states.
 */
public abstract class State {
    Player player;

    /**
     * يمرّر السياق نفسه عبر مُنشئ الحالة. وقد يساعد ذلك
     * الحالة على جلب بعض بيانات السياق المفيدة عند الحاجة.
     */
    State(Player player) {
        this.player = player;
    }

    public abstract String onLock();
    public abstract String onPlay();
    public abstract String onNext();
    public abstract String onPrevious();
}

package refactoring_guru.state.example.states;

import refactoring_guru.state.example.ui.Player;

/**
 * توفّر الحالات المحسوسة التطبيق الخاص لجميع أساليب الواجهة.
 */
public class LockedState extends State {

    LockedState(Player player) {
        super(player);
        player.setPlaying(false);
    }

    @Override
    public String onLock() {
        if (player.isPlaying()) {
            player.changeState(new ReadyState(player));
            return "Stop playing";
        } else {
            return "Locked...";
        }
    }

    @Override
    public String onPlay() {
        player.changeState(new ReadyState(player));
        return "Ready";
    }

    @Override
    public String onNext() {
        return "Locked...";
    }

    @Override
    public String onPrevious() {
        return "Locked...";
    }
}

package refactoring_guru.state.example.states;

import refactoring_guru.state.example.ui.Player;

/**
 * يمكنها أيضاً إطلاق انتقالات الحالة في السياق.
 */
public class ReadyState extends State {

    public ReadyState(Player player) {
        super(player);
    }

    @Override
    public String onLock() {
        player.changeState(new LockedState(player));
        return "Locked...";
    }

    @Override
    public String onPlay() {
        String action = player.startPlayback();
        player.changeState(new PlayingState(player));
        return action;
    }

    @Override
    public String onNext() {
        return "Locked...";
    }

    @Override
    public String onPrevious() {
        return "Locked...";
    }
}

package refactoring_guru.state.example.states;

import refactoring_guru.state.example.ui.Player;

public class PlayingState extends State {

    PlayingState(Player player) {
        super(player);
    }

    @Override
    public String onLock() {
        player.changeState(new LockedState(player));
        player.setCurrentTrackAfterStop();
        return "Stop playing";
    }

    @Override
    public String onPlay() {
        player.changeState(new ReadyState(player));
        return "Paused...";
    }

    @Override
    public String onNext() {
        return player.nextTrack();
    }

    @Override
    public String onPrevious() {
        return player.previousTrack();
    }
}

package refactoring_guru.state.example.ui;

import refactoring_guru.state.example.states.ReadyState;
import refactoring_guru.state.example.states.State;

import java.util.ArrayList;
import java.util.List;

public class Player {
    private State state;
    private boolean playing = false;
    private List<String> playlist = new ArrayList<>();
    private 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;
        }
        return "Playing " + playlist.get(currentTrack);
    }

    public String previousTrack() {
        currentTrack--;
        if (currentTrack < 0) {
            currentTrack = playlist.size() - 1;
        }
        return "Playing " + playlist.get(currentTrack);
    }

    public void setCurrentTrackAfterStop() {
        this.currentTrack = 0;
    }
}

package refactoring_guru.state.example.ui;

import javax.swing.*;
import java.awt.*;

public class UI {
    private Player player;
    private static JTextField textField = new JTextField();

    public UI(Player player) {
        this.player = player;
    }

    public void init() {
        JFrame frame = new JFrame("Test player");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel context = new JPanel();
        context.setLayout(new BoxLayout(context, BoxLayout.Y_AXIS));
        frame.getContentPane().add(context);
        JPanel buttons = 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().onNext()));
        JButton prev = new JButton("Prev");
        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.example;

import refactoring_guru.state.example.ui.Player;
import refactoring_guru.state.example.ui.UI;

/**
 * فئة العرض التوضيحي. كل شيء يجتمع هنا.
 */
public class Demo {
    public static void main(String[] args) {
        Player player = new Player();
        UI ui = new UI(player);
        ui.init();
    }
}
```

### csharp

```csharp
using System;

namespace RefactoringGuru.DesignPatterns.State.Conceptual
{
    // The Context defines the interface of interest to clients. It also
    // maintains a reference to an instance of a State subclass, which
    // represents the current state of the Context.
    class Context
    {
        // مرجع إلى الحالة الراهنة للسياق.
        private State _state = null;

        public Context(State state)
        {
            this.TransitionTo(state);
        }

        // يسمح السياق بتغيير كائن الحالة في وقت التشغيل.
        public void TransitionTo(State state)
        {
            Console.WriteLine($"Context: Transition to {state.GetType().Name}.");
            this._state = state;
            this._state.SetContext(this);
        }

        // يفوّض السياق جزءاً من سلوكه إلى كائن الحالة
        // الحالي.
        public void Request1()
        {
            this._state.Handle1();
        }

        public void Request2()
        {
            this._state.Handle2();
        }
    }
    
    // تُعلِن فئة الحالة الأساسية عن الأساليب التي ينبغي أن تنفّذها جميع
    // الحالات المحسوسة، كما توفّر مرجعاً عكسياً إلى كائن السياق المرتبط
    // بالحالة. ويمكن للحالات استخدام هذا المرجع العكسي لنقل السياق
    // إلى حالة أخرى.
    abstract class State
    {
        protected Context _context;

        public void SetContext(Context context)
        {
            this._context = context;
        }

        public abstract void Handle1();

        public abstract void Handle2();
    }

    // تُنفّذ الحالات المحسوسة سلوكيات متنوعة مرتبطة بحالة معيّنة من
    // حالات السياق.
    class ConcreteStateA : State
    {
        public override void Handle1()
        {
            Console.WriteLine("ConcreteStateA handles request1.");
            Console.WriteLine("ConcreteStateA wants to change the state of the context.");
            this._context.TransitionTo(new ConcreteStateB());
        }

        public override void Handle2()
        {
            Console.WriteLine("ConcreteStateA handles request2.");
        }
    }

    class ConcreteStateB : State
    {
        public override void Handle1()
        {
            Console.Write("ConcreteStateB handles request1.");
        }

        public override void Handle2()
        {
            Console.WriteLine("ConcreteStateB handles request2.");
            Console.WriteLine("ConcreteStateB wants to change the state of the context.");
            this._context.TransitionTo(new ConcreteStateA());
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // كود العميل.
            var context = new Context(new ConcreteStateA());
            context.Request1();
            context.Request2();
        }
    }
}

Context: Transition to ConcreteStateA.
ConcreteStateA handles request1.
ConcreteStateA wants to change the state of the context.
Context: Transition to ConcreteStateB.
ConcreteStateB handles request2.
ConcreteStateB wants to change the state of the context.
Context: Transition to ConcreteStateA.
```

### cpp

```cpp
#include <iostream>
#include <typeinfo>
/**
 * تُعلِن فئة الحالة الأساسية عن الأساليب التي ينبغي أن تنفّذها جميع
 * الحالات المحسوسة، كما توفّر مرجعاً عكسياً إلى كائن السياق المرتبط
 * بالحالة. ويمكن للحالات استخدام هذا المرجع العكسي لنقل
 * السياق إلى حالة أخرى.
 */

class Context;

class State {
  /**
   * @var Context
   */
 protected:
  Context *context_;

 public:
  virtual ~State() {
  }

  void set_context(Context *context) {
    this->context_ = context;
  }

  virtual void Handle1() = 0;
  virtual void Handle2() = 0;
};

/**
 * يُعرّف السياق الواجهة التي تهمّ العملاء. كما يحتفظ بمرجع
 * إلى نسخة من إحدى الفئات الفرعية للحالة، التي تمثّل الحالة
 * الراهنة للسياق.
 */
class Context {
  /**
   * @var State مرجع إلى الحالة الراهنة للسياق.
   */
 private:
  State *state_;

 public:
  Context(State *state) : state_(nullptr) {
    this->TransitionTo(state);
  }
  ~Context() {
    delete state_;
  }
  /**
   * يسمح السياق بتغيير كائن الحالة في وقت التشغيل.
   */
  void TransitionTo(State *state) {
    std::cout << "Context: Transition to " << typeid(*state).name() << ".\n";
    if (this->state_ != nullptr)
      delete this->state_;
    this->state_ = state;
    this->state_->set_context(this);
  }
  /**
   * يفوّض السياق جزءاً من سلوكه إلى كائن الحالة الحالي.
   */
  void Request1() {
    this->state_->Handle1();
  }
  void Request2() {
    this->state_->Handle2();
  }
};

/**
 * تُنفّذ الحالات المحسوسة سلوكيات متنوعة مرتبطة بحالة معيّنة من
 * حالات السياق.
 */

class ConcreteStateA : public State {
 public:
  void Handle1() override;

  void Handle2() override {
    std::cout << "ConcreteStateA handles request2.\n";
  }
};

class ConcreteStateB : public State {
 public:
  void Handle1() override {
    std::cout << "ConcreteStateB handles request1.\n";
  }
  void Handle2() override {
    std::cout << "ConcreteStateB handles request2.\n";
    std::cout << "ConcreteStateB wants to change the state of the context.\n";
    this->context_->TransitionTo(new ConcreteStateA);
  }
};

void ConcreteStateA::Handle1() {
  {
    std::cout << "ConcreteStateA handles request1.\n";
    std::cout << "ConcreteStateA wants to change the state of the context.\n";

    this->context_->TransitionTo(new ConcreteStateB);
  }
}

/**
 * كود العميل.
 */
void ClientCode() {
  Context *context = new Context(new ConcreteStateA);
  context->Request1();
  context->Request2();
  delete context;
}

int main() {
  ClientCode();
  return 0;
}

Context: Transition to 14ConcreteStateA.
ConcreteStateA handles request1.
ConcreteStateA wants to change the state of the context.
Context: Transition to 14ConcreteStateB.
ConcreteStateB handles request2.
ConcreteStateB wants to change the state of the context.
Context: Transition to 14ConcreteStateA.
```

### go

```go
package main

import "fmt"

type VendingMachine struct {
	hasItem       State
	itemRequested State
	hasMoney      State
	noItem        State

	currentState State

	itemCount int
	itemPrice int
}

func newVendingMachine(itemCount, itemPrice int) *VendingMachine {
	v := &VendingMachine{
		itemCount: itemCount,
		itemPrice: itemPrice,
	}
	hasItemState := &HasItemState{
		vendingMachine: v,
	}
	itemRequestedState := &ItemRequestedState{
		vendingMachine: v,
	}
	hasMoneyState := &HasMoneyState{
		vendingMachine: v,
	}
	noItemState := &NoItemState{
		vendingMachine: v,
	}

	v.setState(hasItemState)
	v.hasItem = hasItemState
	v.itemRequested = itemRequestedState
	v.hasMoney = hasMoneyState
	v.noItem = noItemState
	return v
}

func (v *VendingMachine) requestItem() error {
	return v.currentState.requestItem()
}

func (v *VendingMachine) addItem(count int) error {
	return v.currentState.addItem(count)
}

func (v *VendingMachine) insertMoney(money int) error {
	return v.currentState.insertMoney(money)
}

func (v *VendingMachine) dispenseItem() error {
	return v.currentState.dispenseItem()
}

func (v *VendingMachine) setState(s State) {
	v.currentState = s
}

func (v *VendingMachine) incrementItemCount(count int) {
	fmt.Printf("Adding %d items\n", count)
	v.itemCount = v.itemCount + count
}

package main

type State interface {
	addItem(int) error
	requestItem() error
	insertMoney(money int) error
	dispenseItem() error
}

package main

import "fmt"

type NoItemState struct {
	vendingMachine *VendingMachine
}

func (i *NoItemState) requestItem() error {
	return fmt.Errorf("Item out of stock")
}

func (i *NoItemState) addItem(count int) error {
	i.vendingMachine.incrementItemCount(count)
	i.vendingMachine.setState(i.vendingMachine.hasItem)
	return nil
}

func (i *NoItemState) insertMoney(money int) error {
	return fmt.Errorf("Item out of stock")
}
func (i *NoItemState) dispenseItem() error {
	return fmt.Errorf("Item out of stock")
}

package main

import "fmt"

type HasItemState struct {
	vendingMachine *VendingMachine
}

func (i *HasItemState) requestItem() error {
	if i.vendingMachine.itemCount == 0 {
		i.vendingMachine.setState(i.vendingMachine.noItem)
		return fmt.Errorf("No item present")
	}
	fmt.Printf("Item requestd\n")
	i.vendingMachine.setState(i.vendingMachine.itemRequested)
	return nil
}

func (i *HasItemState) addItem(count int) error {
	fmt.Printf("%d items added\n", count)
	i.vendingMachine.incrementItemCount(count)
	return nil
}

func (i *HasItemState) insertMoney(money int) error {
	return fmt.Errorf("Please select item first")
}
func (i *HasItemState) dispenseItem() error {
	return fmt.Errorf("Please select item first")
}

package main

import "fmt"

type ItemRequestedState struct {
	vendingMachine *VendingMachine
}

func (i *ItemRequestedState) requestItem() error {
	return fmt.Errorf("Item already requested")
}

func (i *ItemRequestedState) addItem(count int) error {
	return fmt.Errorf("Item Dispense in progress")
}

func (i *ItemRequestedState) insertMoney(money int) error {
	if money < i.vendingMachine.itemPrice {
		return fmt.Errorf("Inserted money is less. Please insert %d", i.vendingMachine.itemPrice)
	}
	fmt.Println("Money entered is ok")
	i.vendingMachine.setState(i.vendingMachine.hasMoney)
	return nil
}
func (i *ItemRequestedState) dispenseItem() error {
	return fmt.Errorf("Please insert money first")
}

package main

import "fmt"

type HasMoneyState struct {
	vendingMachine *VendingMachine
}

func (i *HasMoneyState) requestItem() error {
	return fmt.Errorf("Item dispense in progress")
}

func (i *HasMoneyState) addItem(count int) error {
	return fmt.Errorf("Item dispense in progress")
}

func (i *HasMoneyState) insertMoney(money int) error {
	return fmt.Errorf("Item out of stock")
}
func (i *HasMoneyState) dispenseItem() error {
	fmt.Println("Dispensing Item")
	i.vendingMachine.itemCount = i.vendingMachine.itemCount - 1
	if i.vendingMachine.itemCount == 0 {
		i.vendingMachine.setState(i.vendingMachine.noItem)
	} else {
		i.vendingMachine.setState(i.vendingMachine.hasItem)
	}
	return nil
}

package main

import (
	"fmt"
	"log"
)

func main() {
	vendingMachine := newVendingMachine(1, 10)

	err := vendingMachine.requestItem()
	if err != nil {
		log.Fatalf(err.Error())
	}

	err = vendingMachine.insertMoney(10)
	if err != nil {
		log.Fatalf(err.Error())
	}

	err = vendingMachine.dispenseItem()
	if err != nil {
		log.Fatalf(err.Error())
	}

	fmt.Println()

	err = vendingMachine.addItem(2)
	if err != nil {
		log.Fatalf(err.Error())
	}

	fmt.Println()

	err = vendingMachine.requestItem()
	if err != nil {
		log.Fatalf(err.Error())
	}

	err = vendingMachine.insertMoney(10)
	if err != nil {
		log.Fatalf(err.Error())
	}

	err = vendingMachine.dispenseItem()
	if err != nil {
		log.Fatalf(err.Error())
	}
}

Item requestd
Money entered is ok
Dispensing Item

Adding 2 items

Item requestd
Money entered is ok
Dispensing Item
```

### php

```php
<?php

namespace RefactoringGuru\State\Conceptual;

/**
 * يُعرّف السياق الواجهة التي تهمّ العملاء. كما يحتفظ بمرجع إلى
 * نسخة من إحدى الفئات الفرعية للحالة، التي تمثّل الحالة الراهنة
 * للسياق.
 */
class Context
{
    /**
     * @var State مرجع إلى الحالة الراهنة للسياق.
     */
    private $state;

    public function __construct(State $state)
    {
        $this->transitionTo($state);
    }

    /**
     * يسمح السياق بتغيير كائن الحالة في وقت التشغيل.
     */
    public function transitionTo(State $state): void
    {
        echo "Context: Transition to " . get_class($state) . ".\n";
        $this->state = $state;
        $this->state->setContext($this);
    }

    /**
     * يفوّض السياق جزءاً من سلوكه إلى كائن الحالة الحالي.
     */
    public function request1(): void
    {
        $this->state->handle1();
    }

    public function request2(): void
    {
        $this->state->handle2();
    }
}

/**
 * تُعلِن فئة الحالة الأساسية عن الأساليب التي ينبغي أن تنفّذها جميع
 * الحالات المحسوسة، كما توفّر مرجعاً عكسياً إلى كائن السياق المرتبط
 * بالحالة. ويمكن للحالات استخدام هذا المرجع العكسي لنقل
 * السياق إلى حالة أخرى.
 */
abstract class State
{
    /**
     * @var Context
     */
    protected $context;

    public function setContext(Context $context)
    {
        $this->context = $context;
    }

    abstract public function handle1(): void;

    abstract public function handle2(): void;
}

/**
 * تُنفّذ الحالات المحسوسة سلوكيات متنوعة مرتبطة بحالة معيّنة من
 * حالات السياق.
 */
class ConcreteStateA extends State
{
    public function handle1(): void
    {
        echo "ConcreteStateA handles request1.\n";
        echo "ConcreteStateA wants to change the state of the context.\n";
        $this->context->transitionTo(new ConcreteStateB());
    }

    public function handle2(): void
    {
        echo "ConcreteStateA handles request2.\n";
    }
}

class ConcreteStateB extends State
{
    public function handle1(): void
    {
        echo "ConcreteStateB handles request1.\n";
    }

    public function handle2(): void
    {
        echo "ConcreteStateB handles request2.\n";
        echo "ConcreteStateB wants to change the state of the context.\n";
        $this->context->transitionTo(new ConcreteStateA());
    }
}

/**
 * كود العميل.
 */
$context = new Context(new ConcreteStateA());
$context->request1();
$context->request2();

Context: Transition to RefactoringGuru\State\Conceptual\ConcreteStateA.
ConcreteStateA handles request1.
ConcreteStateA wants to change the state of the context.
Context: Transition to RefactoringGuru\State\Conceptual\ConcreteStateB.
ConcreteStateB handles request2.
ConcreteStateB wants to change the state of the context.
Context: Transition to RefactoringGuru\State\Conceptual\ConcreteStateA.

<?php

namespace RefactoringGuru\State\RealWorld;

/**
 * نمط تصميم الحالة (State)
 *
 * الغرض: يتيح لكائنٍ تغيير سلوكه عند تغيّر حالته الداخلية. ويبدو
 * الأمر كما لو أن الكائن قد غيّر فئته.
 */

/**
 * واجهة حالة الفاتورة (Invoice State)
 *
 * تُعرّف هذه الواجهة العقد الذي يجب أن تنفّذه جميع حالات الفاتورة.
 * وهي تمثّل واجهة الحالة (State) في نمط الحالة، بما يضمن أن جميع
 * الحالات المحسوسة توفّر تطبيقات لكل الأحداث/الانتقالات الممكنة.
 *
 * تُعرّف الواجهة جميع الأحداث الممكنة التي قد تقع في دورة حياة
 * الفاتورة، بغضّ النظر عمّا إذا كانت حالة معيّنة قادرة على معالجتها. وهذا
 * الأسلوب يضمن الاتساق عبر جميع الحالات ويجعل النظام أكثر قابلية
 * للصيانة.
 */
interface InvoiceState
{
    public function finalize(): void;
    public function pay(): void;
    public function cancel(): void;
    public function void(): void;
    public function getName(): string;
}


/**
 * فئة الحالة الأساسية المجرّدة (Abstract Base State)
 *
 * تنفّذ هذه الفئة المجرّدة الواجهة InvoiceState وتوفّر تطبيقات
 * افتراضية لجميع أساليب انتقال الحالة. والسلوك الافتراضي هو إطلاق
 * استثناءات للانتقالات غير الصالحة، اتّباعاً لمبدأ «الفشل
 * السريع» (fail-fast).
 *
 * يتيح هذا الأسلوب للحالات المحسوسة أن تتجاوز فقط أساليب
 * الانتقالات التي تدعمها فعلاً، مما يبقي الكود نظيفاً ومركّزاً. وأي
 * محاولة لتنفيذ انتقال غير صالح ستؤدّي إلى استثناء واضح
 * بدلاً من فشل صامت.
 *
 * كما تحتفظ الفئة المجرّدة بمرجع إلى كائن السياق (Invoice)،
 * وهو لازم لتنفيذ انتقالات الحالة.
 */
abstract class BaseInvoiceState implements InvoiceState
{
     /**
      * مرجع إلى كائن السياق (Invoice)
      *
      * تحتاج كل حالة إلى الوصول إلى السياق لتنفيذ انتقالات الحالة.
      * وهذا يُنشئ علاقة ثنائية الاتجاه بين الحالة والسياق.
      */
    protected $invoice;

    public function __construct(Invoice $invoice)
    {
        $this->invoice = $invoice;
    }


    /**
     * التطبيق الافتراضي لحدث finalize
     *
     * افتراضياً، لا يُسمح بالإنهاء (finalize) في معظم الحالات. والحالات التي
     * تدعم هذا الانتقال هي وحدها التي ستتجاوز هذا الأسلوب.
     *
     * @throws InvalidStateTransitionException
     */
    public function finalize(): void
    {
        throw new InvalidStateTransitionException("Cannot finalize invoice in " . $this->getName() . " state");
    }

    /**
     * التطبيق الافتراضي لحدث pay
     *
     * افتراضياً، لا يُسمح بالدفع في معظم الحالات. والحالات التي
     * تدعم هذا الانتقال هي وحدها التي ستتجاوز هذا الأسلوب.
     *
     * @throws InvalidStateTransitionException
     */
    public function pay(): void
    {
        throw new InvalidStateTransitionException("Cannot pay invoice in " . $this->getName() . " state");
    }

    /**
     * التطبيق الافتراضي لحدث cancel
     *
     * افتراضياً، لا يُسمح بالإلغاء في معظم الحالات. والحالات التي
     * تدعم هذا الانتقال هي وحدها التي ستتجاوز هذا الأسلوب.
     *
     * @throws InvalidStateTransitionException
     */
    public function cancel(): void
    {
        throw new InvalidStateTransitionException("Cannot cancel invoice in " . $this->getName() . " state");
    }


    /**
     * التطبيق الافتراضي لحدث void
     *
     * افتراضياً، لا يُسمح بالإبطال في معظم الحالات. والحالات التي
     * تدعم هذا الانتقال هي وحدها التي ستتجاوز هذا الأسلوب.
     *
     * @throws InvalidStateTransitionException
     */
    public function void(): void
    {
        throw new InvalidStateTransitionException("Cannot void invoice in " . $this->getName() . " state");
    }

    /**
     * أسلوب مجرّد للحصول على اسم الحالة
     *
     * يجب أن تنفّذ كل حالة محسوسة هذا الأسلوب لإرجاع اسمها. ويُستخدم
     * هذا لأغراض التسجيل وتصحيح الأخطاء والعرض.
     *
     * @return string اسم الحالة الراهنة
     */
    abstract public function getName(): string;
}

/**
 * تقابل كل حالة محسوسة حالةً معيّنة.
 *
 * تمثّل هذه الحالة المحسوسة فاتورة مسوّدة (draft).
 *
 * هذه هي الحالة الأولية لكل فاتورة. وفي هذه الحالة، لا تزال الفاتورة
 * قيد الإعداد ولا يمكن سوى إنهاؤها للانتقال إلى حالة Open. ولا يُسمح
 * بأي عمليات أخرى في هذه الحالة.
 */
class DraftInvoiceState extends BaseInvoiceState
{
    /**
     * معالجة حدث finalize
     *
     * هذا هو الانتقال الصالح الوحيد من حالة Draft. فعند إنهاء
     * الفاتورة، تنتقل إلى حالة Open حيث يمكن دفعها أو إبطالها
     * أو إلغاؤها.
     */
    public function finalize(): void
    {
        echo "Invoice #{$this->invoice->getId()} finalized - changing from Draft to Open\n";
        $this->invoice->setState(new OpenInvoiceState($this->invoice));
    }

    public function getName(): string
    {
        return 'draft';
    }
}


/**
 * تمثّل هذه الحالة المحسوسة فاتورة مفتوحة (open).
 *
 * تمثّل هذه الحالة فاتورة جرى إنهاؤها وأصبحت جاهزة
 * للمعالجة. ومن هذه الحالة، يمكن للفاتورة أن:
 * - تُدفع (تنتقل إلى حالة Paid)
 * - تُبطَل (تنتقل إلى حالة Void)
 * - تُلغى (تنتقل إلى حالة Uncollectable)
 */
class OpenInvoiceState extends BaseInvoiceState
{
    /**
     * معالجة حدث pay
     *
     * عند استلام الدفعة، تنتقل الفاتورة إلى حالة Paid. وهذه
     * حالة نهائية - لا يُسمح بأي عمليات أخرى.
     */
    public function pay(): void
    {
        echo "Invoice #{$this->invoice->getId()} paid - changing from Open to Paid\n";
        $this->invoice->setState(new PaidInvoiceState($this->invoice));
    }

    /**
     * معالجة حدث void
     *
     * عند إبطال فاتورة، تنتقل إلى حالة Void. وهذه
     * حالة نهائية - لا يُسمح بأي عمليات أخرى.
     */
    public function void(): void
    {
        echo "Invoice #{$this->invoice->getId()} voided - changing from Open to Void\n";
        $this->invoice->setState(new VoidInvoiceState($this->invoice));
    }

    /**
     * معالجة حدث cancel
     *
     * عند إلغاء فاتورة، تنتقل إلى حالة Uncollectable.
     * ومن حالة Uncollectable، لا يزال بالإمكان دفع الفاتورة أو إبطالها.
     */
    public function cancel(): void
    {
        echo "Invoice #{$this->invoice->getId()} cancelled - changing from Open to Uncollectable\n";
        $this->invoice->setState(new UncollectableInvoiceState($this->invoice));
    }

    public function getName(): string
    {
        return 'open';
    }
}

/**
 * تمثّل هذه الحالة المحسوسة فاتورة مدفوعة (paid).
 *
 * هذه حالة نهائية تمثّل فاتورة مدفوعة. وبمجرّد دفع
 * الفاتورة، لا يُسمح بأي انتقالات حالة أخرى. وتستخدم جميع أساليب الأحداث
 * التطبيق الافتراضي الذي يطلق الاستثناءات.
 */
class PaidInvoiceState extends BaseInvoiceState
{
    public function getName(): string
    {
        return 'paid';
    }
}

/**
 * تمثّل هذه الحالة المحسوسة فاتورة مُبطَلة (void).
 *
 * هذه حالة نهائية تمثّل فاتورة مُبطَلة. وبمجرّد إبطال
 * الفاتورة، لا يُسمح بأي انتقالات حالة أخرى. وتستخدم جميع أساليب الأحداث
 * التطبيق الافتراضي الذي يطلق الاستثناءات.
 */
class VoidInvoiceState extends BaseInvoiceState
{
    public function getName(): string
    {
        return 'void';
    }
}

/**
 * تمثّل هذه الحالة المحسوسة فاتورة قابلة للتحصيل.
 *
 * تمثّل هذه الحالة فاتورة جرى إلغاؤها لكن لا يزال بالإمكان
 * استردادها. ومن هذه الحالة، يمكن للفاتورة أن:
 * - تُدفع (تنتقل إلى حالة Paid)
 * - تُبطَل (تنتقل إلى حالة Void)
 *
 * وهذا يوفّر طريقة للتعامل مع الفواتير التي أُلغيت لكن يمكن لاحقاً
 * تحصيلها أو شطبها نهائياً.
 */
class UncollectableInvoiceState extends BaseInvoiceState
{
    /**
     * Handle pay event
     *
     * رغم أن الفاتورة قد أُلغيت، لا يزال بالإمكان استلام الدفعة.
     * وهذا ينقل الفاتورة إلى حالة Paid.
     */
    public function pay(): void
    {
        echo "Invoice #{$this->invoice->getId()} paid - changing from Uncollectable to Paid\n";
        $this->invoice->setState(new PaidInvoiceState($this->invoice));
    }

    /**
     * Handle void event
     *
     * إذا كانت الفاتورة غير قابلة للتحصيل نهائياً، فيمكن إبطالها. وهذا
     * ينقل الفاتورة إلى حالة Void.
     */
    public function void(): void
    {
        echo "Invoice #{$this->invoice->getId()} voided - changing from Uncollectable to Void\n";
        $this->invoice->setState(new VoidInvoiceState($this->invoice));
    }

    public function getName(): string
    {
        return 'uncollectable';
    }
}

/**
 * فئة السياق - Invoice
 *
 * هذه هي فئة السياق في نمط الحالة. وهي تحتفظ بمرجع إلى
 * كائن الحالة الراهن وتفوّض كل السلوك الخاص بالحالة إلى
 * الحالة الراهنة. ولا يكون السياق مدركاً لفئات الحالة المحدّدة
 * بل يتفاعل معها عبر الواجهة المجرّدة InvoiceState.
 *
 * كما يحتفظ السياق ببيانات الفاتورة (المعرّف والمبلغ، إلخ) التي تبقى
 * ثابتة بغضّ النظر عن الحالة.
 */
class Invoice
{
    private $id;
    private $amount;

    /**
     * كائن الحالة الراهن
     *
     * هذا هو المكوّن الأساسي في نمط الحالة. إذ يحتفظ السياق بمرجع
     * إلى كائن الحالة الراهن ويفوّض كل العمليات الخاصة بالحالة
     * إلى هذا الكائن.
     *
     * @var InvoiceState
     */
    private $state;

    private $createdAt;

    /**
     * المُنشئ
     *
     * يُنشئ فاتورة جديدة. وتبدأ الفاتورة دائماً في حالة Draft
     * وفقاً لمتطلّبات العمل.
     */
    public function __construct(int $id, float $amount)
    {
        $this->id = $id;
        $this->amount = $amount;
        $this->createdAt = new \DateTime();
        // الحالة الأولية هي draft، وهنا يبدأ نمط الحالة - إذ
        // نضبط الحالة الأولية
        $this->state = new DraftInvoiceState($this);
    }

    public function getId(): int
    {
        return $this->id;
    }


    /**
     * ضبط الحالة الراهنة
     *
     * تستدعي كائنات الحالة هذا الأسلوب للانتقال إلى حالة جديدة. وهو
     * الآلية التي تتيح عمل نمط الحالة - إذ يمكن للحالات تغيير
     * حالة السياق باستدعاء هذا الأسلوب.
     *
     * @param InvoiceState $state كائن الحالة الجديد
     */
    public function setState(InvoiceState $state)
    {
        $this->state = $state;
    }

    /**
     * الحصول على كائن الحالة الراهن
     *
     * @return InvoiceState
     */
    public function getState(): InvoiceState
    {
        return $this->state;
    }

    /**
     * الحصول على اسم الحالة الراهنة
     *
     * هذا أسلوب مُيسِّر يفوّض إلى كائن الحالة الراهن.
     *
     * @return string
     */
    public function getStateName(): string
    {
        return $this->state->getName();
    }

    /**
     * أسلوب الحدث: finalize
     *
     * يفوّض هذا الأسلوب عملية الإنهاء إلى الحالة الراهنة. وهذا
     * هو جوهر نمط الحالة - إذ لا يعرف السياق كيف يعالج
     * العملية، فيفوّضها إلى الحالة الراهنة.
     */
    public function finalize()
    {
        $this->state->finalize();
    }

    /**
     * أسلوب الحدث: pay
     *
     * يفوّض هذا الأسلوب عملية الدفع إلى الحالة الراهنة. وسيتفاوت
     * السلوك تبعاً للحالة الراهنة.
     */
    public function pay()
    {
        $this->state->pay();
    }

    /**
     * أسلوب الحدث: cancel
     *
     * يفوّض هذا الأسلوب عملية الإلغاء إلى الحالة الراهنة. وسيتفاوت
     * السلوك تبعاً للحالة الراهنة.
     */
    public function cancel()
    {
        $this->state->cancel();
    }

    /**
     * أسلوب الحدث: void
     *
     * يفوّض هذا الأسلوب عملية الإبطال إلى الحالة الراهنة. وسيتفاوت
     * السلوك تبعاً للحالة الراهنة.
     */
    public function void()
    {
        $this->state->void();
    }

    /**
     * الحصول على معلومات الفاتورة
     *
     * يُرجع مصفوفة تتضمّن كل معلومات الفاتورة بما في ذلك الحالة الراهنة.
     * وهذا مفيد لتصحيح الأخطاء أو التسجيل أو استجابات الـ API.
     *
     * @return array
     */
    public function getInfo(): array
    {
        return [
            'id' => $this->id,
            'amount' => $this->amount,
            'state' => $this->getStateName(),
            'created_at' => $this->createdAt->format('Y-m-d H:i:s')
        ];
    }
}


/**
 * استثناء مخصّص لانتقالات الحالة غير الصالحة
 *
 * يُطلَق هذا الاستثناء عند محاولة انتقال حالة غير صالح. وهو
 * يوفّر رسائل خطأ واضحة حول الانتقال الذي جرت محاولته وسبب
 * فشله.
 */
class InvalidStateTransitionException extends \Exception
{
    /**
     * المُنشئ
     *
     * @param string $message رسالة الخطأ
     * @param int $code رمز الخطأ
     * @param \Exception|null $previous الاستثناء السابق
     */
    public function __construct($message = "", $code = 0, \Exception $previous = null)
    {
        parent::__construct($message, $code, $previous);
    }
}


/**
 * ============================================================================
 * مثال على الاستخدام وعرض توضيحي
 * ============================================================================
 *
 * يوضّح الكود التالي كيفية استخدام تطبيق نمط الحالة
 * عبر سيناريوهات متنوّعة تُظهر جميع انتقالات الحالة الممكنة.
 */

try {
    echo "=== Invoice State Pattern Demo ===\n\n";

    // إنشاء فاتورة جديدة (تبدأ في حالة draft)
    $invoice = new Invoice(1001, 1500.00);
    echo "Created invoice: " . json_encode($invoice->getInfo()) . "\n\n";

    // السيناريو 1: Draft -> Open -> Paid
    echo "--- Scenario 1: Draft -> Open -> Paid ---\n";
    $invoice->finalize(); // من Draft إلى Open
    echo "Current state: " . $invoice->getStateName() . "\n";

    $invoice->pay(); // من Open إلى Paid
    echo "Current state: " . $invoice->getStateName() . "\n";

    // محاولة الدفع مرة أخرى (يُفترض أن تفشل)
    try {
        $invoice->pay();
    } catch (InvalidStateTransitionException $e) {
        echo "Expected error: " . $e->getMessage() . "\n";
    }

    echo "\n--- Scenario 2: Draft -> Open -> Void ---\n";
    $invoice2 = new Invoice(1002, 750.00);
    $invoice2->finalize(); // من Draft إلى Open
    $invoice2->void(); // من Open إلى Void
    echo "Invoice 2 state: " . $invoice2->getStateName() . "\n";

    echo "\n--- Scenario 3: Draft -> Open -> Uncollectable -> Paid ---\n";
    $invoice3 = new Invoice(1003, 2000.00);
    $invoice3->finalize(); // من Draft إلى Open
    $invoice3->cancel(); // من Open إلى Uncollectable
    echo "Invoice 3 state: " . $invoice3->getStateName() . "\n";

    $invoice3->pay(); // من Uncollectable إلى Paid
    echo "Invoice 3 final state: " . $invoice3->getStateName() . "\n";

    echo "\n--- Scenario 4: Draft -> Open -> Uncollectable -> Void ---\n";
    $invoice4 = new Invoice(1004, 500.00);
    $invoice4->finalize(); // من Draft إلى Open
    $invoice4->cancel(); // من Open إلى Uncollectable
    $invoice4->void(); // من Uncollectable إلى Void
    echo "Invoice 4 final state: " . $invoice4->getStateName() . "\n";

    echo "\n--- Error Scenario: Invalid transition ---\n";
    $invoice5 = new Invoice(1005, 300.00);
    try {
        $invoice5->pay(); // محاولة دفع فاتورة مسوّدة (يُفترض أن تفشل)
    } catch (InvalidStateTransitionException $e) {
        echo "Expected error: " . $e->getMessage() . "\n";
    }

    echo "\n--- State Information ---\n";
    echo "Invoice 1: " . json_encode($invoice->getInfo()) . "\n";
    echo "Invoice 2: " . json_encode($invoice2->getInfo()) . "\n";
    echo "Invoice 3: " . json_encode($invoice3->getInfo()) . "\n";
    echo "Invoice 4: " . json_encode($invoice4->getInfo()) . "\n";
    echo "Invoice 5: " . json_encode($invoice5->getInfo()) . "\n";
} catch (InvalidStateTransitionException $e) {
    echo "Error: " . $e->getMessage() . "\n";
}

=== Invoice State Pattern Demo ===

Created invoice: {"id":1001,"amount":1500,"state":"draft","created_at":"2025-07-12 13:14:15"}

--- Scenario 1: Draft -> Open -> Paid ---
Invoice #1001 finalized - changing from Draft to Open
Current state: open
Invoice #1001 paid - changing from Open to Paid
Current state: paid
Expected error: Cannot pay invoice in paid state

--- Scenario 2: Draft -> Open -> Void ---
Invoice #1002 finalized - changing from Draft to Open
Invoice #1002 voided - changing from Open to Void
Invoice 2 state: void

--- Scenario 3: Draft -> Open -> Uncollectable -> Paid ---
Invoice #1003 finalized - changing from Draft to Open
Invoice #1003 cancelled - changing from Open to Uncollectable
Invoice 3 state: uncollectable
Invoice #1003 paid - changing from Uncollectable to Paid
Invoice 3 final state: paid

--- Scenario 4: Draft -> Open -> Uncollectable -> Void ---
Invoice #1004 finalized - changing from Draft to Open
Invoice #1004 cancelled - changing from Open to Uncollectable
Invoice #1004 voided - changing from Uncollectable to Void
Invoice 4 final state: void

--- Error Scenario: Invalid transition ---
Expected error: Cannot pay invoice in draft state

--- State Information ---
Invoice 1: {"id":1001,"amount":1500,"state":"paid","created_at":"2025-07-12 13:14:15"}
Invoice 2: {"id":1002,"amount":750,"state":"void","created_at":"2025-07-12 13:14:15"}
Invoice 3: {"id":1003,"amount":2000,"state":"paid","created_at":"2025-07-12 13:14:15"}
Invoice 4: {"id":1004,"amount":500,"state":"void","created_at":"2025-07-12 13:14:15"}
Invoice 5: {"id":1005,"amount":300,"state":"draft","created_at":"2025-07-12 13:14:15"}
```

### python

```python
from __future__ import annotations
from abc import ABC, abstractmethod


class Context:
    """
    يُعرّف السياق الواجهة التي تهمّ العملاء. كما يحتفظ بمرجع إلى
    نسخة من إحدى الفئات الفرعية للحالة، التي تمثّل الحالة الراهنة
    للسياق.
    """

    _state = None
    """
    مرجع إلى الحالة الراهنة للسياق.
    """

    def __init__(self, state: State) -> None:
        self.transition_to(state)

    def transition_to(self, state: State):
        """
        يسمح السياق بتغيير كائن الحالة في وقت التشغيل.
        """

        print(f"Context: Transition to {type(state).__name__}")
        self._state = state
        self._state.context = self

    """
    يفوّض السياق جزءاً من سلوكه إلى كائن الحالة الحالي.
    """

    def request1(self):
        self._state.handle1()

    def request2(self):
        self._state.handle2()


class State(ABC):
    """
    تُعلِن فئة الحالة الأساسية عن الأساليب التي ينبغي أن تنفّذها جميع
    الحالات المحسوسة، كما توفّر مرجعاً عكسياً إلى كائن السياق المرتبط
    بالحالة. ويمكن للحالات استخدام هذا المرجع العكسي لنقل السياق
    إلى حالة أخرى.
    """

    @property
    def context(self) -> Context:
        return self._context

    @context.setter
    def context(self, context: Context) -> None:
        self._context = context

    @abstractmethod
    def handle1(self) -> None:
        pass

    @abstractmethod
    def handle2(self) -> None:
        pass


"""
تُنفّذ الحالات المحسوسة سلوكيات متنوعة مرتبطة بحالة معيّنة من
حالات السياق.
"""


class ConcreteStateA(State):
    def handle1(self) -> None:
        print("ConcreteStateA handles request1.")
        print("ConcreteStateA wants to change the state of the context.")
        self.context.transition_to(ConcreteStateB())

    def handle2(self) -> None:
        print("ConcreteStateA handles request2.")


class ConcreteStateB(State):
    def handle1(self) -> None:
        print("ConcreteStateB handles request1.")

    def handle2(self) -> None:
        print("ConcreteStateB handles request2.")
        print("ConcreteStateB wants to change the state of the context.")
        self.context.transition_to(ConcreteStateA())


if __name__ == "__main__":
    # كود العميل.

    context = Context(ConcreteStateA())
    context.request1()
    context.request2()

Context: Transition to ConcreteStateA
ConcreteStateA handles request1.
ConcreteStateA wants to change the state of the context.
Context: Transition to ConcreteStateB
ConcreteStateB handles request2.
ConcreteStateB wants to change the state of the context.
Context: Transition to ConcreteStateA
```

### ruby

```ruby
# يُعرّف السياق الواجهة التي تهمّ العملاء. كما يحتفظ بمرجع إلى
# نسخة من إحدى الفئات الفرعية للحالة، التي تمثّل الحالة الراهنة
# للسياق.
class Context
  # مرجع إلى الحالة الراهنة للسياق.
  attr_accessor :state
  private :state

  # @param [State] state
  def initialize(state)
    transition_to(state)
  end

  # يسمح السياق بتغيير كائن الحالة في وقت التشغيل.
  def transition_to(state)
    puts "Context: Transition to #{state.class}"
    @state = state
    @state.context = self
  end

  # يفوّض السياق جزءاً من سلوكه إلى كائن الحالة الحالي.

  def request1
    @state.handle1
  end

  def request2
    @state.handle2
  end
end

# تُعلِن فئة الحالة الأساسية عن الأساليب التي ينبغي أن تنفّذها جميع الحالات
# المحسوسة، كما توفّر مرجعاً عكسياً إلى كائن السياق المرتبط
# بالحالة. ويمكن للحالات استخدام هذا المرجع العكسي لنقل السياق
# إلى حالة أخرى.
class State
  attr_accessor :context

  # @abstract
  def handle1
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end

  # @abstract
  def handle2
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
end

# تُنفّذ الحالات المحسوسة سلوكيات متنوعة مرتبطة بحالة معيّنة من
# حالات السياق.

class ConcreteStateA < State
  def handle1
    puts 'ConcreteStateA handles request1.'
    puts 'ConcreteStateA wants to change the state of the context.'
    @context.transition_to(ConcreteStateB.new)
  end

  def handle2
    puts 'ConcreteStateA handles request2.'
  end
end

class ConcreteStateB < State
  def handle1
    puts 'ConcreteStateB handles request1.'
  end

  def handle2
    puts 'ConcreteStateB handles request2.'
    puts 'ConcreteStateB wants to change the state of the context.'
    @context.transition_to(ConcreteStateA.new)
  end
end

# كود العميل.

context = Context.new(ConcreteStateA.new)
context.request1
context.request2

Context: Transition to ConcreteStateA
ConcreteStateA handles request1.
ConcreteStateA wants to change the state of the context.
Context: Transition to ConcreteStateB
ConcreteStateB handles request2.
ConcreteStateB wants to change the state of the context.
Context: Transition to ConcreteStateA
```

### rust

```rust
pub trait State {
    fn play(self: Box<Self>, player: &mut Player) -> Box<dyn State>;
    fn stop(self: Box<Self>, player: &mut Player) -> Box<dyn State>;
}

impl dyn State {
    pub fn next(self: Box<Self>, player: &mut Player) -> Box<dyn State> {
        self
    }

    pub fn prev(self: Box<Self>, player: &mut Player) -> Box<dyn State> {
        self
    }
}

pub struct StoppedState;
pub struct PausedState;
pub struct PlayingState;

impl State for StoppedState {
    ...
}

impl State for PausedState {
    ...
}

let state = Box::new(StoppedState);   // StoppedState.
let state = state.play(&mut player);  // StoppedState -> PlayingState.
let state = state.play(&mut player);  // PlayingState -> PausedState.

fn play(self: Box<Self>, player: &mut Player) -> Box<dyn State> {
    player.play();

    // Stopped -> Playing.
    Box::new(PlayingState)
}

fn play(self: Box<Self>, player: &mut Player) -> Box<dyn State> {
    player.pause();

    // Playing -> Paused.
    Box::new(PausedState)
}

/// مقطوعة موسيقية.
pub struct Track {
    pub title: String,
    pub duration: u32,
    cursor: u32,
}

impl Track {
    pub fn new(title: &'static str, duration: u32) -> Self {
        Self {
            title: title.into(),
            duration,
            cursor: 0,
        }
    }
}

/// يحتفظ مشغّل الموسيقى بقائمة تشغيل ويمكنه إجراء عمليات أساسية عليها.
pub struct Player {
    playlist: Vec<Track>,
    current_track: usize,
    _volume: u8,
}

impl Default for Player {
    fn default() -> Self {
        Self {
            playlist: vec![
                Track::new("Track 1", 180),
                Track::new("Track 2", 165),
                Track::new("Track 3", 197),
                Track::new("Track 4", 205),
            ],
            current_track: 0,
            _volume: 25,
        }
    }
}

impl Player {
    pub fn next_track(&mut self) {
        self.current_track = (self.current_track + 1) % self.playlist.len();
    }

    pub fn prev_track(&mut self) {
        self.current_track = (self.playlist.len() + self.current_track - 1) % self.playlist.len();
    }

    pub fn play(&mut self) {
        self.track_mut().cursor = 10; // محاكاة التشغيل.
    }

    pub fn pause(&mut self) {
        self.track_mut().cursor = 43; // مُوقَف مؤقتاً عند لحظة ما.
    }

    pub fn rewind(&mut self) {
        self.track_mut().cursor = 0;
    }

    pub fn track(&self) -> &Track {
        &self.playlist[self.current_track]
    }

    fn track_mut(&mut self) -> &mut Track {
        &mut self.playlist[self.current_track]
    }
}

use cursive::views::TextView;

use crate::player::Player;

pub struct StoppedState;
pub struct PausedState;
pub struct PlayingState;

/// توجد سمة (trait) أساسية `State` تحتوي على الأسلوبين `play` و`stop` اللذين
/// ينفّذان انتقالات الحالة. كما يوجد الأسلوبان `next` و`prev` في كتلة
/// `impl dyn State` منفصلة أدناه، وهما تطبيقان افتراضيان
/// لا يمكن تجاوزهما.
///
/// ما هي صيغة `self: Box<Self>`؟ نستخدم الحالة كما يلي:
/// ```rust
///   let prev_state = Box::new(PlayingState);
///   let next_state = prev_state.play(&mut player);
/// ```
/// يستقبل الأسلوب `play` كائن `Box<PlayingState>` كاملاً،
/// وليس `PlayingState` فحسب. فالحالة السابقة «تختفي» داخل الأسلوب،
/// وفي المقابل يُرجع كائن حالة جديداً `Box<PausedState>`.
pub trait State {
    fn play(self: Box<Self>, player: &mut Player) -> Box<dyn State>;
    fn stop(self: Box<Self>, player: &mut Player) -> Box<dyn State>;
    fn render(&self, player: &Player, view: &mut TextView);
}

impl State for StoppedState {
    fn play(self: Box<Self>, player: &mut Player) -> Box<dyn State> {
        player.play();

        // متوقّف -> قيد التشغيل.
        Box::new(PlayingState)
    }

    fn stop(self: Box<Self>, _: &mut Player) -> Box<dyn State> {
        // لا تغيير في الحالة.
        self
    }

    fn render(&self, _: &Player, view: &mut TextView) {
        view.set_content("[Stopped] Press 'Play'")
    }
}

impl State for PausedState {
    fn play(self: Box<Self>, player: &mut Player) -> Box<dyn State> {
        player.pause();

        // مُوقَف مؤقتاً -> قيد التشغيل.
        Box::new(PlayingState)
    }

    fn stop(self: Box<Self>, player: &mut Player) -> Box<dyn State> {
        player.pause();
        player.rewind();

        // مُوقَف مؤقتاً -> متوقّف.
        Box::new(StoppedState)
    }

    fn render(&self, player: &Player, view: &mut TextView) {
        view.set_content(format!(
            "[Paused] {} - {} sec",
            player.track().title,
            player.track().duration
        ))
    }
}

impl State for PlayingState {
    fn play(self: Box<Self>, player: &mut Player) -> Box<dyn State> {
        player.pause();

        // قيد التشغيل -> مُوقَف مؤقتاً.
        Box::new(PausedState)
    }

    fn stop(self: Box<Self>, player: &mut Player) -> Box<dyn State> {
        player.pause();
        player.rewind();

        // قيد التشغيل -> متوقّف.
        Box::new(StoppedState)
    }

    fn render(&self, player: &Player, view: &mut TextView) {
        view.set_content(format!(
            "[Playing] {} - {} sec",
            player.track().title,
            player.track().duration
        ))
    }
}

// التطبيقان الافتراضيان "next" و"prev" للسمة (trait).
impl dyn State {
    pub fn next(self: Box<Self>, player: &mut Player) -> Box<dyn State> {
        player.next_track();

        // لا تغيير في الحالة.
        self
    }

    pub fn prev(self: Box<Self>, player: &mut Player) -> Box<dyn State> {
        player.prev_track();

        // لا تغيير في الحالة.
        self
    }
}

mod player;
mod state;

use cursive::{
    event::Key,
    view::Nameable,
    views::{Dialog, TextView},
    Cursive,
};
use player::Player;
use state::{State, StoppedState};

// سياق التطبيق: مشغّل موسيقى وحالة.
struct PlayerApplication {
    player: Player,
    state: Box<dyn State>,
}

fn main() {
    let mut app = cursive::default();

    app.set_user_data(PlayerApplication {
        player: Player::default(),
        state: Box::new(StoppedState),
    });

    app.add_layer(
        Dialog::around(TextView::new("Press Play").with_name("Player Status"))
            .title("Music Player")
            .button("Play", |s| execute(s, "Play"))
            .button("Stop", |s| execute(s, "Stop"))
            .button("Prev", |s| execute(s, "Prev"))
            .button("Next", |s| execute(s, "Next")),
    );

    app.add_global_callback(Key::Esc, |s| s.quit());

    app.run();
}

fn execute(s: &mut Cursive, button: &'static str) {
    let PlayerApplication {
        mut player,
        mut state,
    } = s.take_user_data().unwrap();

    let mut view = s.find_name::<TextView>("Player Status").unwrap();

    // إليك كيفية عمل آلية الحالة: تنفّذ الحالة السابقة
    // إجراءً وتُرجع حالة جديدة.
    // تمتلك كل حالة العمليات الأربع جميعها لكنها تتفاعل بشكل مختلف.
    state = match button {
        "Play" => state.play(&mut player),
        "Stop" => state.stop(&mut player),
        "Prev" => state.prev(&mut player),
        "Next" => state.next(&mut player),
        _ => unreachable!(),
    };

    state.render(&player, &mut view);

    s.set_user_data(PlayerApplication { player, state });
}
```

### swift

```swift
import XCTest

/// يُعرّف السياق الواجهة التي تهمّ العملاء. كما يحتفظ بمرجع
/// إلى نسخة من إحدى الفئات الفرعية للحالة، التي تمثّل الحالة
/// الراهنة للسياق.
class Context {

    /// مرجع إلى الحالة الراهنة للسياق.
    private var state: State

    init(_ state: State) {
        self.state = state
        transitionTo(state: state)
    }

    /// يسمح السياق بتغيير كائن الحالة في وقت التشغيل.
    func transitionTo(state: State) {
        print("Context: Transition to " + String(describing: state))
        self.state = state
        self.state.update(context: self)
    }

    /// يفوّض السياق جزءاً من سلوكه إلى كائن الحالة الحالي.
    func request1() {
        state.handle1()
    }

    func request2() {
        state.handle2()
    }
}

/// تُعلِن فئة الحالة الأساسية عن الأساليب التي ينبغي أن تنفّذها جميع
/// الحالات المحسوسة، كما توفّر مرجعاً عكسياً إلى كائن السياق المرتبط
/// بالحالة. ويمكن للحالات استخدام هذا المرجع العكسي لنقل
/// السياق إلى حالة أخرى.
protocol State: AnyObject {

    func update(context: Context)

    func handle1()
    func handle2()
}

class BaseState: State {

    private(set) weak var context: Context?

    func update(context: Context) {
        self.context = context
    }

    func handle1() {}
    func handle2() {}
}

/// تُنفّذ الحالات المحسوسة سلوكيات متنوعة مرتبطة بحالة معيّنة من
/// حالات السياق.
class ConcreteStateA: BaseState {

    override func handle1() {
        print("ConcreteStateA handles request1.")
        print("ConcreteStateA wants to change the state of the context.\n")
        context?.transitionTo(state: ConcreteStateB())
    }

    override func handle2() {
        print("ConcreteStateA handles request2.\n")
    }
}

class ConcreteStateB: BaseState {

    override func handle1() {
        print("ConcreteStateB handles request1.\n")
    }

    override func handle2() {
        print("ConcreteStateB handles request2.")
        print("ConcreteStateB wants to change the state of the context.\n")
        context?.transitionTo(state: ConcreteStateA())
    }
}

/// لنرَ كيف يعمل كل ذلك معاً.
class StateConceptual: XCTestCase {

    func test() {
        let context = Context(ConcreteStateA())
        context.request1()
        context.request2()
    }
}

Context: Transition to StateConceptual.ConcreteStateA
ConcreteStateA handles request1.
ConcreteStateA wants to change the state of the context.

Context: Transition to StateConceptual.ConcreteStateB
ConcreteStateB handles request2.
ConcreteStateB wants to change the state of the context.

Context: Transition to StateConceptual.ConcreteStateA

import XCTest

class StateRealWorld: XCTestCase {

    func test() {

        print("Client: I'm starting working with a location tracker")
        let tracker = LocationTracker()

        print()
        tracker.startTracking()

        print()
        tracker.pauseTracking(for: 2)

        print()
        tracker.makeCheckIn()

        print()
        tracker.findMyChildren()

        print()
        tracker.stopTracking()
    }
}

class LocationTracker {

    /// تتبّع الموقع مُفعّل افتراضياً
    private lazy var trackingState: TrackingState = EnabledTrackingState(tracker: self)

    func startTracking() {
        trackingState.startTracking()
    }

    func stopTracking() {
        trackingState.stopTracking()
    }

    func pauseTracking(for time: TimeInterval) {
        trackingState.pauseTracking(for: time)
    }

    func makeCheckIn() {
        trackingState.makeCheckIn()
    }

    func findMyChildren() {
        trackingState.findMyChildren()
    }

    func update(state: TrackingState) {
        trackingState = state
    }
}

protocol TrackingState {

    func startTracking()
    func stopTracking()
    func pauseTracking(for time: TimeInterval)

    func makeCheckIn()
    func findMyChildren()
}

class EnabledTrackingState: TrackingState {

    private weak var tracker: LocationTracker?

    init(tracker: LocationTracker?) {
        self.tracker = tracker
    }

    func startTracking() {
        print("EnabledTrackingState: startTracking is invoked")
        print("EnabledTrackingState: tracking location....1")
        print("EnabledTrackingState: tracking location....2")
        print("EnabledTrackingState: tracking location....3")
    }

    func stopTracking() {
        print("EnabledTrackingState: Received 'stop tracking'")
        print("EnabledTrackingState: Changing state to 'disabled'...")
        tracker?.update(state: DisabledTrackingState(tracker: tracker))
        tracker?.stopTracking()
    }

    func pauseTracking(for time: TimeInterval) {
        print("EnabledTrackingState: Received 'pause tracking' for \(time) seconds")
        print("EnabledTrackingState: Changing state to 'disabled'...")
        tracker?.update(state: DisabledTrackingState(tracker: tracker))
        tracker?.pauseTracking(for: time)
    }

    func makeCheckIn() {
        print("EnabledTrackingState: performing check-in at the current location")
    }

    func findMyChildren() {
        print("EnabledTrackingState: searching for children...")
    }
}

class DisabledTrackingState: TrackingState {

    private weak var tracker: LocationTracker?

    init(tracker: LocationTracker?) {
        self.tracker = tracker
    }

    func startTracking() {
        print("DisabledTrackingState: Received 'start tracking'")
        print("DisabledTrackingState: Changing state to 'enabled'...")
        tracker?.update(state: EnabledTrackingState(tracker: tracker))
    }

    func pauseTracking(for time: TimeInterval) {
        print("DisabledTrackingState: Pause tracking for \(time) seconds")

        for i in 0...Int(time) {
            print("DisabledTrackingState: pause...\(i)")
        }

        print("DisabledTrackingState: Time is over")
        print("DisabledTrackingState: Returing to 'enabled state'...\n")
        self.tracker?.update(state: EnabledTrackingState(tracker: self.tracker))
        self.tracker?.startTracking()
    }

    func stopTracking() {
        print("DisabledTrackingState: Received 'stop tracking'")
        print("DisabledTrackingState: Do nothing...")
    }

    func makeCheckIn() {
        print("DisabledTrackingState: Received 'make check-in'")
        print("DisabledTrackingState: Changing state to 'enabled'...")
        tracker?.update(state: EnabledTrackingState(tracker: tracker))
        tracker?.makeCheckIn()
    }

    func findMyChildren() {
        print("DisabledTrackingState: Received 'find my children'")
        print("DisabledTrackingState: Changing state to 'enabled'...")
        tracker?.update(state: EnabledTrackingState(tracker: tracker))
        tracker?.findMyChildren()
    }
}

Client: I'm starting working with a location tracker

EnabledTrackingState: startTracking is invoked
EnabledTrackingState: tracking location....1
EnabledTrackingState: tracking location....2
EnabledTrackingState: tracking location....3

EnabledTrackingState: Received 'pause tracking' for 2.0 seconds
EnabledTrackingState: Changing state to 'disabled'...
DisabledTrackingState: Pause tracking for 2.0 seconds
DisabledTrackingState: pause...0
DisabledTrackingState: pause...1
DisabledTrackingState: pause...2
DisabledTrackingState: Time is over
DisabledTrackingState: Returing to 'enabled state'...

EnabledTrackingState: startTracking is invoked
EnabledTrackingState: tracking location....1
EnabledTrackingState: tracking location....2
EnabledTrackingState: tracking location....3

EnabledTrackingState: performing check-in at the current location

EnabledTrackingState: searching for children...

EnabledTrackingState: Received 'stop tracking'
EnabledTrackingState: Changing state to 'disabled'...
DisabledTrackingState: Received 'stop tracking'
DisabledTrackingState: Do nothing...
```

### typescript

```typescript
/**
 * يُعرّف السياق الواجهة التي تهمّ العملاء. كما يحتفظ بمرجع إلى
 * نسخة من إحدى الفئات الفرعية للحالة، التي تمثّل الحالة الراهنة
 * للسياق.
 */
class Context {
    /**
     * @type {State} مرجع إلى الحالة الراهنة للسياق.
     */
    private state: State;

    constructor(state: State) {
        this.transitionTo(state);
    }

    /**
     * يسمح السياق بتغيير كائن الحالة في وقت التشغيل.
     */
    public transitionTo(state: State): void {
        console.log(`Context: Transition to ${(<any>state).constructor.name}.`);
        this.state = state;
        this.state.setContext(this);
    }

    /**
     * يفوّض السياق جزءاً من سلوكه إلى كائن الحالة الحالي.
     */
    public request1(): void {
        this.state.handle1();
    }

    public request2(): void {
        this.state.handle2();
    }
}

/**
 * تُعلِن فئة الحالة الأساسية عن الأساليب التي ينبغي أن تنفّذها جميع
 * الحالات المحسوسة، كما توفّر مرجعاً عكسياً إلى كائن السياق المرتبط
 * بالحالة. ويمكن للحالات استخدام هذا المرجع العكسي لنقل
 * السياق إلى حالة أخرى.
 */
abstract class State {
    protected context: Context;

    public setContext(context: Context) {
        this.context = context;
    }

    public abstract handle1(): void;

    public abstract handle2(): void;
}

/**
 * تُنفّذ الحالات المحسوسة سلوكيات متنوعة مرتبطة بحالة معيّنة من
 * حالات السياق.
 */
class ConcreteStateA extends State {
    public handle1(): void {
        console.log('ConcreteStateA handles request1.');
        console.log('ConcreteStateA wants to change the state of the context.');
        this.context.transitionTo(new ConcreteStateB());
    }

    public handle2(): void {
        console.log('ConcreteStateA handles request2.');
    }
}

class ConcreteStateB extends State {
    public handle1(): void {
        console.log('ConcreteStateB handles request1.');
    }

    public handle2(): void {
        console.log('ConcreteStateB handles request2.');
        console.log('ConcreteStateB wants to change the state of the context.');
        this.context.transitionTo(new ConcreteStateA());
    }
}

/**
 * كود العميل.
 */
const context = new Context(new ConcreteStateA());
context.request1();
context.request2();

Context: Transition to ConcreteStateA.
ConcreteStateA handles request1.
ConcreteStateA wants to change the state of the context.
Context: Transition to ConcreteStateB.
ConcreteStateB handles request2.
ConcreteStateB wants to change the state of the context.
Context: Transition to ConcreteStateA.
```

