Хорошо ли использовать шаблон состояния для поддержания текущего выбранного объекта? - PullRequest
0 голосов
/ 13 сентября 2018

Типичный сценарий картины состояний включает состояния, которые в основном отличаются, например closed_connection_state или open_connection_state. В моем случае все состояния по сути одинаковы, но операцию необходимо применить к выбранному в данный момент объекту.

Как правило, что-то вроде этого делается с помощью индексной переменной, которая указывает на выбранный в данный момент объект, но использует шаблон состояния для лучшей реализации, чтобы сделать это, как в примере ниже?

class Object
{
    std::string _name;
public:
    Object(std::string name) : _name(name)
    {

    }

    void Perform()
    {
        std::cout << _name << " Perform called\r\n";
    }
};

class CurrentObject
{
    Object* _a;
    Object* _b;
    Object* _current;

public:

    CurrentObject(Object* a, Object* b) : _a(a), _b(b)
    {
        _current = a;
    }

    void Perform()
    {
        _current->Perform();

        // Update _current logic goes here, lets just switch
        // the state whenever `Perform` is called.
        if (_current == _a)
            _current = _b;
        else
            _current = _a;
    };

};

int main()
{
    Object a("a"); // program can be in a state when `a` is the current object.
    Object b("b"); // or b can become the current object as result of an operation on current object

    CurrentObject current(&a, &b); // it assigns the defaults

    // assume Perform() does its thing but it also needs to change the current selected object.
    // In this example, we assumes the current selection object is always swapped.
    current.Perform(); // operates on `a`, the default
    current.Perform(); // operates on `b` due state changed in above line
    current.Perform(); // operates on `a` doe to state changed in above line again
}

1 Ответ

0 голосов
/ 13 сентября 2018

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

Вы, вероятно, хотите, чтобы ваши состояния (a & b) расширяли общее абстрактное состояние, чтобы при одинаковой функциональности во всех состояниях вам не приходилось реализовывать его в каждом отдельном объекте.

Для расширения вы, вероятно, также захотите «назвать» свои состояния и поместить их в хеш-таблицу, когда она масштабируется (помните, в программировании у вас есть 1 или много), добавление нового состояния не потребует изменения кода вашего состояния. машина - но я предполагаю, что у вас уже есть что-то подобное и просто уменьшил количество вопросов.

Также обратите внимание, что для переключения состояний вы не хотите делать это напрямую (как ваш пример), вам, вероятно, нужен метод (setState), который изменяет состояние при возврате метода execute, а не в самом методе execute или while. это работает. Фактически, вы можете выполнить execute, возвращая строку, указывающую на следующее желаемое состояние ..

Редактировать из комментариев:

То, что я имел в виду, называя ваши состояния вместо:

class CurrentObject
{
    Object* _a;
    Object* _b;
    Object* _current;
    ...

У вас может быть что-то вроде (извините за мой java-синтаксис, C # не мой основной язык, но я знаю, что он очень похож по функциональности)

class CurrentObject
{
    Hashtable states=new Hashtable();
    Object* _current;

    public addState(String stateName, Object* state)
    {
        states.put(stateName, state)
    }

    public void Perform()
    {
        String nextState = _current->Perform();
        if(nextState != null)
            setState(nextState);
    }
    public void setState(String stateName)
    {
        _current = states.get(stateName);
    }

}

Ваш код вызова будет выглядеть примерно так:

currentObject = new CurrentObject()
currentObject.addState("state a", _a);
currentObject.addState("state b", _b); 
currentObject.setState("state a");
currentObject.perform();
...

Я игнорирую много инициализации и проверки ошибок.

В данный момент ваш конечный автомат имеет только одно событие: "Perform ()". Вы можете обнаружить, что вам нужны другие события, которые немного усложнят ситуацию (в java я мог бы использовать отражение или аннотации для решения этой проблемы, не зная, как C # сделает это).

...