Какова наилучшая практика для иерархического конечного автомата, использующего шаблон состояний? - PullRequest
9 голосов
/ 15 августа 2010

Я собираюсь реализовать иерархический конечный автомат в C #, используя шаблон состояний. В качестве руководства я использую этот пример. Этот пример не дает ответа относительно иерархических состояний. К сожалению, я не могу найти хороших примеров в другом месте. Моя первая мысль - создать вложенные классы для иерархических состояний. Но считается ли это лучшей практикой или есть лучшие решения?

Поздравил!

UPDATE:

Я сидел весь день, пытаясь реализовать шаблон состояний, как описано выше. HSM основан на очень простом медиаплеере:

альтернативный текст http://www.freeimagehosting.net/uploads/e8d2d6486a.jpg

Я думал, что сделал это, но одну вещь я не понимаю. Сначала код, который я написал (извините, это довольно много):

public class MediaPlayer
{
    public MediaPlayerStates state;

    public MediaPlayer(MediaPlayerStates state)
    {
        this.state = state;
    }

    public void OnButtonPressed()
    {
        state.OnButtonPressed(this);
    }

    public void DeviceBooted()
    { 
        state. ?????
    }

    //Other Functions
}

//The 3 initial states (Start, On, End) know only 2 events.
public abstract class MediaPlayerStates
{
    public abstract void OnButtonPressed(MediaPlayer player);
    public abstract void OffButtonPressed(MediaPlayer player);
}

//The very beginpoint of the state machine
public class Start : MediaPlayerStates
{
    //When hitting the onbutton, the state changes to the OnState state
    public override void OnButtonPressed(MediaPlayer player)
    {
        player.state = new OnState(player);
    }

    //No need to implement this one
    public override void OffButtonPressed(MediaPlayer player)
    {
        throw new NotImplementedException();
    }
}

//OnState implements the 2 events from the MediaPlayerStates abstract class.
public class OnState : MediaPlayerStates
{
    //When entered the OnState state, a new entrypoint is creaeted: the Start state
    public OnState(MediaPlayer player)
    {
        player.state = new OnStartState();
    }

    //The OnState doesn't have a OnButtonPressed event so it doesn't need to be implemented
    public override void OnButtonPressed(MediaPlayer player)
    {
        throw new NotImplementedException();
    }

    //When hitting the offbutton in the OnState, the new state is End
    public override void OffButtonPressed(MediaPlayer player)
    {
        player.state = new End();
    }

    //The OnState itself containts 3 events, therefore these need to be implemented by every state whitin the OnState state
    public abstract class SubStates : MediaPlayerStates
    {
        public abstract void DeviceBooted(MediaPlayer player);
        public abstract void PlayButtonPressed(MediaPlayer player);
        public abstract void StopButtonPressed(MediaPlayer player);
    }

    //The OnStartState is the pseudoState where the On state starts
    public class OnStartState : SubStates
    {
        //When booted, the state of the player changes to the ShowMediaFileState state
        public override void DeviceBooted(MediaPlayer player)
        {
            player.state = new ShowMediaFileState();
        }

        //The events below don't need to be implemented since they don't exist. 
        public override void PlayButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }

        public override void StopButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }

        public override void OnButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }

        public override void OffButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }
    }

    public class ShowMediaFileState : SubStates
    {
        //This event doesn't exists for this state
        public override void DeviceBooted(MediaPlayer player)
        {
            throw new NotImplementedException();
        }

        //When hitting the play button in this state, play the mediafile
        public override void PlayButtonPressed(MediaPlayer player)
        {
            player.state = new PlayMediaFileState();
        }

        //These events also don't exist for this state
        public override void StopButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }

        public override void OnButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }

        public override void OffButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }
    }

    public class PlayMediaFileState : SubStates
    {
        //This event doesn't exist for this state
        public override void DeviceBooted(MediaPlayer player)
        {
            throw new NotImplementedException();
        }

        //This event doesn't exist for this state
        public override void PlayButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }

        //While playing a file and hitting the stopbutton, the state changes to the ShowMediaFileState state
        public override void StopButtonPressed(MediaPlayer player)
        {
            player.state = new ShowMediaFileState();
        }

        //This event doesn't exist for this state
        public override void OnButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }

        //This event doesn't exist for this state
        public override void OffButtonPressed(MediaPlayer player)
        {
            throw new NotImplementedException();
        }
    }
}

//The endstate doesn't need any implementation since there cannot occur a event while being off
public class End : MediaPlayerStates
{
    public override void OnButtonPressed(MediaPlayer player)
    {
        throw new NotImplementedException();
    }

    public override void OffButtonPressed(MediaPlayer player)
    {
        throw new NotImplementedException();
    }
}

При определении событий в классе MediaPlayer я не могу вызывать какие-либо другие функции, кроме

  • OnButtonPressed
  • OffButtonPressed

Так что мне интересно, насколько хороша моя реализация? Что случилось? Я также попытался взглянуть на предложение использовать составной шаблон, но я не понимаю, как его следует использовать с шаблоном состояний. Надеюсь, что кто-нибудь может помочь!

Ответы [ 4 ]

3 голосов
/ 15 августа 2010

Я думаю, вы тоже захотите Composite;это позволит вам связать конечные автоматы вместе.

2 голосов
/ 10 февраля 2011

Для создания HSM с шаблоном состояний каждое состояние с подсостояниями должно быть самим конечным автоматом.Таким образом, верхний уровень не знает подсостояний (меньше побочных эффектов), и государство может лучше управлять своими подсостояниями (может иметь состояние по умолчанию, может помнить последнее состояние, в котором оно было и т. Д.)выбрасывать исключение, когда вы не можете сделать что-либо полезное с действием, неправильно.Вы должны просто игнорировать это.Вы генерируете исключения только в исключительных случаях, при нажатии на неправильную кнопку ожидаемое поведение пользователя.

1 голос
/ 08 июня 2013

Чтобы заставить его работать в общем виде, вам нужно рассматривать иерархию конечного автомата как древовидную структуру;переходы между узлами могут использовать алгоритм наименьшего общего предка (LCA) для деревьев, затем выходить из узла ниже общего предка в происхождении исходного узла (каскадный выход в любые дочерние узлы), затем вводить каждый узел в предке целевого узла изузел ниже общего предка целевого узла, наконец, если у целевого узла есть дочерние элементы, вам нужно будет ввести их, как если бы вы входили в любое другое составное состояние.

Этот метод упоминается вСпецификация надстройки UML.

Взгляните на исходный код в https://github.com/steelbreeze/state.cs, так как он реализует описанный выше метод.

Чтобы увидеть рабочий пример, взгляните на сайт проекта.для сестринской версии JavaScript здесь: http://www.steelbreeze.net/state.js/

1 голос
/ 15 августа 2010

Прежде чем приступить к реализации собственной инфраструктуры FSM, взгляните на SMC - компилятор конечного автомата.

SMC берет текстовое определение конечного автомата и генерирует код для его реализации. Он имеет бэкэнды для широкого спектра языков, включая C #. Он также может выводить точечные файлы для генерации схемы автомата.

SMC может создать нечто похожее на иерархические конечные автоматы с переходами push и pop - по существу, push передает управление на новый конечный автомат, а pop возвращает управление на исходный конечный автомат.

...