我有一个模型程序,它代表一系列服务器上的消息流:
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不会让我以这种方式使用对象来保持我的状态。还有其他方法可以避免定义重复的布尔组,一个用于链中的每个服务器吗?
答案 0 :(得分:2)
除了风格问题之外,如问题中所示封装状态的主要好处是减少必须编写和读取的代码量。而不必编写(#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 :(得分:1)
自从写上我的答案以来,我已经了解了另一种更接近我原本想要的解决方案。
要使用具有实例变量的对象,您可以从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();
答案 2 :(得分:0)
我认为观察者模式可能会对您有所帮助 - http://www.dofactory.com/Patterns/PatternObserver.aspx