如何在NModel中封装状态变量?

发布于 2024-08-13 05:05:13 字数 1324 浏览 5 评论 0原文

我有一个模型程序,它代表沿着服务器链的消息流:

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 不会让我以这种方式使用对象来保持我的状态。是否有其他方法可以避免定义重复的布尔值组,每个布尔值对应链中的每个服务器?

I have a model program that represents message flow along a chain of servers:

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;
    }

}

There are lots more messages. The Enabled() logic for each server and message type is slightly different, but the state is similar, so I would like to encapsulate it by writing something more like:

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

and then use the encapsulated state in my actions:

[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;
}

However NModel won't let me use objects in this fashion to hold my state. Is there some other way I can avoid defining repeating groups of booleans, one for each server in the chain?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

栀子花开つ 2024-08-20 05:05:13

撇开风格问题不谈,问题中所示的封装状态的主要好处是减少必须编写和读取的代码量。不必编写 (#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);
    }

}

可以进一步减少代码事件的数量,例如通过使用设置将所有内容保存在单个变量中。但是,将状态空间分开的一个优点是它可以在模型查看器中生成更清晰的状态摘要。)

Questions of style aside, the main benefit of encapsulating the state as shown in the question is to reduce the amount of code that must be written and read. Instead of having to write (#servers * #messages) declarations, only (#server + #messages) are required.

The same reduction in code (with corresponding improvements in readability and reduction in carpal tunnel syndrome) can be achieved by using NModel's built-in Set class to track the state of each message. A set called send_msg1 contains the names of all the servers that have sent 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);
    }

}

(It is possible to reduce the amount of code event further, for example by using a map of sets to hold everything in a single variable. However one advantage of leaving the state patially separated is that it produces more legible state summaries in the model viewer.)

绝情姑娘 2024-08-20 05:05:13

自从在上面写下我的答案以来,我了解到了另一个更接近我最初寻找的解决方案。

要使用带有实例变量的对象,您可以从 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();

Since writing my answer above, I have learned of another solution that is closer to what I was originally looking for.

To use objects with instance variables, you can derive from LabeledInstance as shown below. The instances should be allocated using the static Create() method, and fields should be initialized in an overridden Initialize() method.

(You can also use instance methods for actions, but to do so you must assign a domain to the class; the name of that domain should correspond to a static set that contains all current instances of the class.)

Behind the scenes, NModel is going to translate this class into a bunch of maps, one for each instance variable in the class. The key into those maps will be indexed instances of the class name, e.g. State(1). This can be somewhat hard to read within the MVC tool, so you may also want to keep some kind of instance variable that contains a legible, consolidated summary of the object's state.

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();
弱骨蛰伏 2024-08-20 05:05:13

我认为观察者模式可能会在这里帮助你 - http://www.dofactory.com/Patterns/模式观察者.aspx

I think the observer pattern might help you here - http://www.dofactory.com/Patterns/PatternObserver.aspx

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文