OOP设计:字符串,枚举,界面还是其他?

时间:2009-10-28 14:21:17

标签: architecture oop

我开始从一个项目中提取数据并将其写回旧系统数据库。我已经开始使用域模型,并试图在过去的系统中改进这种设计,所以我想对此进行一些反馈。

这个例子是任意的,所以不需要那里的具体建议,但是假设数据库中有一个名为“WorkflowStep”的表,我正在编写一个类。表中有一个名为“CurrentStatus”的列定义了工作流的状态。它存储为varchar。此列的整个表格中有五个不同的字符串,并且不太可能被更改...值如“打开”,“已关闭”,“暂停”等等。

该类需要跟踪此值,但以何种方式?我可以走简单的路线,只是将它存储在一个字符串中,但这个定义不是很明确,我想设想未来的开发人员寻找字符串的不同值来应用逻辑。我可以使用枚举来使事情更明确,但这可能导致切换/案件地狱到处都是。我已经阅读了工程师创建界面的方法,比如说“IStatus”,然后制作代表状态的每个可能状态的具体类,但是在与此情况相同的情况下的其他一些列可能有一百个不同的值,所以100每个州的课程都有点矫枉过正。

我的主要问题:一种方法事实上比其他方法更好,如果没有,我应该考虑选择一种方法?

请注意,该项目仍处于起步阶段,我不确定该类的“status”属性将如何使用。它可能是无用的,或者它可能证明是至关重要的:我还不确定。

8 个答案:

答案 0 :(得分:2)

我个人更喜欢这种转换语句

var x = new Dictionary<Status, Action>  
  {Status.Fail, ()=>Console.Writeline("Fail")}
  {Status.Ok, ()=>Console.Writeline("Ok")};  

x[Status.Fail]();
x[Status.Ok]();

另外 - 你可能会喜欢Jimmy this article(如果你坚持使用枚举方案)。

答案 1 :(得分:2)

我不认为这方面有任何明确的答案,但这是一个常见的问题,以下方法一直很适合我:

  1. 如果您的业务逻辑或任何代码永远不会对值执行任何操作(比较,基于枚举值的切换等),请将其保留为字符串。
  2. 如果您要对其进行比较,请使用枚举。如果你有很多这些表,或者值可以改变,那么这非常适合代码生成。
  3. 如果值具有与其相关的其他元数据,请创建包含此元数据的类,以及创建相关类的枚举(在工厂方法中)。同样,代码生成非常适合这里。
  4. 对于像CurrentStatus这样的东西,它听起来像选项2或3将是自然的契合。如果以下任何一种情况适用,则备选方案3将是更可取的:

    • 对于包含空格或非字母数字字符(Enum.ToString()无法处理的任何内容)的状态,您需要一个“友好”名称。
    • 还有一些额外的逻辑或属性“出现”某种状态。例如,如果你有一些逻辑可以在“OnHold”或“Closed”项目上执行某个操作但不在“Open”项目上执行某些操作,那么在类上有一个“CanDoAction”属性是有意义的。
    • 您从中提取的数据库中包含状态参考表,其中包含与您可能希望在代码中使用的状态相关的信息。

答案 2 :(得分:1)

  

我已经阅读了工程师创建界面的方法,比如说“IStatus”,然后制作代表状态的每种可能状态的具体类,

那将是State Pattern

  

但是与此相同情况下的其他一些列可能有一百个不同的值,因此每个州的100个类似乎有点过分。

这似乎是一个单独的问题。没有更多细节,没有太多可说的。

答案 3 :(得分:1)

我建议您研究域驱动设计中定义的“值类型”的概念。这个WorkflowStep的东西听起来像是一个主要的候选人。你没有提到你编写的语言或环境,但是在.Net中,如果我最终使用这个概念,我会创建一个表示这个对象的结构,并编码,以便在它的公共接口中使用,客户端代码贯穿系统的其余部分,它出现在enum中,并将用作枚举。

MyTask.WorkFlowStatus = WorkFlowStep.OnHold; 
// creates and assigns new instance of struct

在C#中

  public struct WorkflowStep 
  {
     public static readonly WorkflowStep Null   = new WorkflowStep();
     public static readonly WorkflowStep Open   = new WorkflowStep(1);
     public static readonly WorkflowStep Closed = new WorkflowStep(2);
     public static readonly WorkflowStep OnHold = new WorkflowStep(3);
     private int val;
     private bool def;
     public bool HasValue { get { return def; } }
     public bool IsNull   { get { return !def ; } }
     private WorkflowStep ( ) { } // disable public instantiation
     private WorkflowStep (int value) 
     {
       val = value;
       def = true ;
     }
  }

您可以在模型中输入需要跟踪此WorkflowStep的其他clases的属性。此结构的每个实例的内存占用量非常小,用于保存值的int和用于保持其可空状态的bool。您可以为结构添加其他方法和重载,以启用打印格式输出,ToString Overloads,无论您想要什么......

答案 4 :(得分:1)

这是一个非常常见的问题,很大程度上取决于对问题的理解。通常我认为这是简单性,可读性和可扩展性之间的交集。

  1. 枚举/常量列表。这是最简单的路由,如果您在代码中工作的次数远远超过原始数据,那么它具有良好的可读性。可扩展性不是很好,因为你需要重构以保持这一点。
  2. 字符串即可。字符串的优点是您可以一目了然地轻松了解数据库数据。但是,它们往往会增加程序代码并且它们也不是非常可扩展的。
  3. 参考表。到目前为止,这是三者中最具扩展性的。可读性有所降低,因为现在只要想弄清楚发生了什么,就必须在参考表中查找值。编码是三者中最复杂的。
  4. 最简单=枚举。最可读=字符串。最可扩展=参考表。

    哪一个最适合您的问题?

答案 5 :(得分:1)

如果您非常确定状态的选项数量不会增加,则枚举将起作用。我认为你可以通过一些精心设计来避免切换/案例问题...也许使用策略模式。

另一方面,如果选项的数量可能会增加,那么创建一个WorkFlowStatus类将是最佳选择。这将允许您在不修改代码的情况下添加更多状态。我不认为你必须为每个人的状态创建一个班级。

答案 6 :(得分:1)

通常,您最终会将此类型的项目作为枚举引用。如果你想避免切换/案例地狱,你可以使用映射到每个枚举的Action - 这是一个例子:

private Dictionary<WorkflowStep, Action> _actions = 
  new Dictionary<WorkflowStep, Action>();

然后用

分配
_actions.Add(WorkflowStep.Open, OpenCommand);
_actions.Add(WorkflowStep.Closed, ClosedCommand);

你会有这样简单的方法:

private void OpenCommand()
{
  // Do something
}

private void ClosedCommand()
{
  // Do something.
}

最后,要调用它,你可以:

if (_actions[step] != null)
{
  _actions[step]();
}

请注意,您可以使用字符串执行此操作 - 不使用枚举,但此方法可帮助您避免代码中的魔术字符串。

答案 7 :(得分:1)

state-pattern听起来合理。

如果您有更多不同的值,您可以使用其中一个根实现,并添加一些 decorator-pattern