0

对于简单的对象,通常很容易拥有一个“状态”属性,它是一个字符串并且可以存储在数据库中。例如,想象一个 User 类。它可能处于非活动、未验证和活动状态。这可以使用两个布尔值进行跟踪——“活动”和“已验证”——但它也可以使用简单的状态机从非活动转换为未验证到活动,同时将当前状态存储在该“状态”属性中。很常见,对吧?

然而,现在想象一个有几个布尔属性的类,更重要的是,可以有很多这些属性的组合。例如,可能损坏、丢失、停用、过时等的事物。现在,在单个“状态”属性中跟踪状态变得更加困难。我猜,这是一个非确定性有限自动机或状态机。我真的不想存储“inactive_broken”和“active_missing_outdated”等状态。

我想出的最好的方法是同时拥有“状态”属性并存储某种超状态——在这种情况下,“可用”与“不可用”——以及每个布尔值。这样我就可以在过渡时使用类似守卫的方法。

有没有其他人遇到过这个问题并想出一个很好的跟踪状态的解决方案?

4

3 回答 3

1

您是否考虑过将“状态”序列化为位掩码并将其存储在数据库的整数列中?假设一个实体可以是活动的或不活动的,可用的或不可用的,或者以任何组合工作或损坏。

您可以将每个状态存储为一点;打开或关闭。这样,值 111 将处于活动状态、可用和工作状态,而值 000 将处于非活动状态、不可用和损坏。

然后,您可以使用适当的位掩码查询特定组合,或将实体反序列化为一个类,该类具有您要跟踪的每个状态的布尔值。将状态添加到对象也相对便宜,并且不会破坏已经序列化的对象。

于 2012-04-05T21:12:14.637 回答
1

与上面的答案相同,但比理论更实用:

  • 确定布尔属性的可能数量。所有这些属性的状态可以用 1=true 或 0=false 来表示

  • 采用适当大小的数字数据类型。unsigned short=16, unsigned int=32, unsigned long=64,如果你有更大的类型,取一个数字数组:例如 128 个属性取

    unsigned long[] attr= new long[2];  // two long side by side
    
  • 可以使用以下代码访问每个位

    bool GetBitAt(long attr, int position){
        return (attr & (1<<(position-1)) >0;
    }
    long SetBitAt(long attr, int position, bool value){
        return attr|=1<<(position-1);
    }
    
  • 现在让每个位位置代表一个属性。例如:位 5 表示可用?

     bool IsAvailable(long attr){
          return GetBitAt(attr, 5);
     }
    

好处

  • 节省空间,例如 64 个属性将只占用 8 个字节。

  • 易于保存和读取,您只需读取一个 short、int 或 long,这只是一个简单的变量

  • 比较一组属性很容易,因为您只需将 short、int 或 long 的数值与另一个进行比较。例如 if(Obj.attributes == Obj2.attributes){ }

于 2014-09-18T13:34:43.740 回答
0

我认为您正在描述Orthogonal Regions的示例。从该链接中,“当系统的行为被分割成独立的、同时活动的部分时,正交区域解决了状态数量组合增加的常见问题。”

您可能实现的一种方法是通过对象组合。例如,您的超级对象包含多个子对象。子对象各自独立地保持它们的关联状态。超级对象的状态是其所有子对象状态的组合。

搜索“正交状态”、“正交区域”或“正交分量”以获得更多想法。

于 2014-09-18T17:28:16.967 回答