Как инкапсулировать переменные состояния в NModel? - PullRequest
1 голос
/ 02 декабря 2009

У меня есть модельная программа, которая представляет поток сообщений по цепочке серверов:

public class MyModel
{
    static bool x_send_msg1 = false; // has X sent msg1?
    static bool y_recv_msg1 = false; // has Y received msg1?

    static bool y_send_msg1 = false; // has Y sent msg1?
    static bool z_send_msg1 = false; // has Z received msg1?

    // (etc for more servers and more messages)

    [Action]
    static void YSendMsg1()
    {
       // Y sends Msg1 to Z
       y_send_msg1 = true;
       z_recv_msg1 = true;
    }
    static bool YSendMsg1Enabled()
    {
       // in the simplest case, this can happen whenever Y has received the
       // message but not yet forwarded it
       return y_recv_msg1 && !y_send_msg1;
    }

}

Есть еще много сообщений. Логика Enabled () для каждого сервера и типа сообщения немного отличается, но состояние схоже, поэтому я хотел бы инкапсулировать его, написав что-то вроде:

class State
{
    public bool send_msg1 = false;
    public bool recv_msg1 = false;
}
public static State X = new State();
public static State Y = new State();

и затем использовать инкапсулированное состояние в моих действиях:

[Action]
static void YSendMsg1()
{
  // instead of y_qqq above, now we can write Y.qqq:
   Y.send_msg1 = true;
   Z.recv_msg1 = true;
}
static bool YSendMsg1Enabled()
{
   return Y.recv_msg1 && !Y.send_msg1;
}

Однако NModel не позволит мне использовать объекты таким образом, чтобы удерживать мое состояние. Есть ли другой способ избежать повторяющихся логических групп, по одной для каждого сервера в цепочке?

Ответы [ 3 ]

2 голосов
/ 18 декабря 2009

Помимо вопросов стиля, главное преимущество инкапсуляции состояния, как показано в вопросе, заключается в уменьшении объема кода, который должен быть написан и прочитан. Вместо того, чтобы писать (#servers * #messages) объявления, требуется только (#server + #messages).

Такое же сокращение кода (с соответствующим улучшением читабельности и уменьшением синдрома запястного канала) может быть достигнуто с помощью встроенного класса NModel Set для отслеживания состояния каждого сообщения. Набор под названием send_msg1 содержит имена всех серверов, которые отправили msg1:

public class MyModel
{
    static set<int> send_msg1 = set<int>.EmptySet; // has server #n sent msg #1?
    static set<int> recv_msg1 = set<int>.EmptySet; // has server #n received msg #1?
    // (etc for more messages)

    static int X = 1;
    static int Y = 2;
    // (etc for more server names)

    [Action]
    static void YSendMsg1()
    {
       // Y sends Msg1 to Z
       send_msg1 = send_msg1.Add(Y);
       recv_msg1 = recv_msg1.Add(Z);
    }
    static bool YSendMsg1Enabled()
    {
       // in the simplest case, this can happen whenever Y has received the
       // message but not yet forwarded it
       return recv_msg1.Contains(Y) && !send_msg1.Contains(Y);
    }

}

(Можно еще больше уменьшить количество событий кода, например, используя карту наборов, чтобы хранить все в одной переменной. Однако одно преимущество, состоящее в том, чтобы разделять состояние по частям, состоит в том, что оно создает более четкие сводки состояний просмотрщик моделей.)

1 голос
/ 14 января 2010

С тех пор, как я написал свой ответ выше, я узнал о другом решении, которое ближе к тому, что я искал изначально.

Чтобы использовать объекты с переменными экземпляра, вы можете получить из LabeledInstance, как показано ниже. Экземпляры должны быть распределены с использованием статического метода Create(), а поля должны быть инициализированы переопределенным методом Initialize().

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

За кулисами NModel собирается перевести этот класс в набор карт, по одной для каждой переменной экземпляра в классе. Ключ в этих картах будет индексированными экземплярами имени класса, например, State(1). Это может быть довольно трудно прочитать в инструменте MVC, поэтому вы можете также захотеть сохранить какую-то переменную экземпляра, которая содержит четкую, сводную сводку состояния объекта.

class State : LabeledInstance<State>
{ 
    public override void Initialize()
    {
        send_msg1 = false;
        recv_msg1 = false;
    }
    public bool send_msg1;
    public bool recv_msg1;
} 

public static State X = State.Create();
public static State Y = State.Create();
0 голосов
/ 17 декабря 2009

Я думаю, что модель наблюдателя может помочь вам здесь - http://www.dofactory.com/Patterns/PatternObserver.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...