1

我有一个算法,它返回一个分类列表(字符串),这取决于给算法的两个参数:一个类型变量和一个额外的类别字符串,它允许将某些特殊分类添加到结果列表中。

当前的实现,由于 ifs 和 switch 语句的规则表达,是不可读和不可扩展的。规则也是硬编码的。

代码的简化版本:

 private static List<string> DetermineTypes(Type x, object category) {
  List<string> Types = new List<string>();


  if (category is DateTime) {
    types.Add("1");
    types.Add("2");
    types.Add("3");
  } else if (category is string) {
    switch ((string)category) {
      case "A":
        Types.Add("4");
        break;
      case "B":
      case "C":
      case "D":
        Types.Add("5");
        break;
      case "":
        Types = DetermineTypesFromX(Types, x);
        break;
      default:
        Types.Add("6");
        break;
    }
  }
  return graphTypes;
}


private static List<string> DetermineTypesFromX(List<string> Types, Type x) {
  if (x.Equals(typeof(int))) {
    Types.Add("7");
  } else if (x.Equals(typeof(double))) {
    Types.Add("8");

  } else if (x.Equals(typeof(System.DateTime))) {
    Types.Add("9");
    Types.Add("10");
  }
  return Types;
}

我在想也许用 xml 指定这些会很好,这样新类型/规则就不需要更改代码,但这很可能对这种情况来说太重了。基本上,我正在尝试解决可能随时添加新“类型”的问题:常见情况是它是上述“规则”之一,而不太可能的边缘情况是新的“规则”分支可能必须被添加。

与极端情况发生的可能性和业务环境(时间表等)相比,我仍然要确定使用 xml 定义的规则(或任何其他方式)使其完全动态化的工作是否值得。

但我的主要问题是如何优雅地简化上面的嵌套条件代码?也许在设计中加入更多的灵活性以提高可扩展性?

我想知道使用 F# 模式匹配的组合是否是一个合适的解决方案?(注意:以前从未使用过 F#,最近一直很好奇,所以这就是我问的原因)

4

6 回答 6

1

我不会回避基于配置的选项;它通常具有不需要重建的优点。如果您不希望这样,另一个选项可能是通过属性的类型元数据。这将使为类型(您编写的)添加数据变得微不足道,并且您可以(间接)int通过 - 将属性添加到现有类型(等)TypeDescriptor.AddAttributes- 只要您TypeDescriptor.GetAttributes再次使用它们来恢复它们;-p

无论这是否是一个主意......好吧,反射(和双胞胎,TypeDescriptor)可能很慢,所以如果你想在一个紧密的循环中使用它,我会先看看涉及字典的东西。

于 2009-12-09T05:27:34.120 回答
1

最近在以下两篇博客文章中讨论了一种称为调度表的模式,您可能会感兴趣:

冯亚伦

K.斯科特艾伦

于 2009-12-09T03:58:39.240 回答
1

您的问题可能会根据决策树决策表进行编码

此外,Chris Smith 的博客中有关于决策树的帖子:

Awesome F# - 决策树 - 第一部分Awesome F# - 决策树 - 第二部分

于 2009-12-09T11:42:21.557 回答
0

Since you mention F#, here is some F# code with very similar behavior to the C# code:

open System

let DetermineTypesFromX(x:Type) =
    if x.Equals(typeof<int>) then
        ["7"]
    elif x.Equals(typeof<double>) then
        ["8"]
    elif x.Equals(typeof<DateTime>) then
        ["9"; "10"]
    else
        []

let DetermineTypes(x:Type, category:obj) =
    match category with
    | :? DateTime -> ["1"; "2"; "3"]
    | :? string as s ->
        match s with
        | "A" -> ["4"]
        | "B" | "C" | "D" -> ["5"]
        | "" -> DetermineTypesFromX(x)
        | _ -> ["6"]
    | _ -> []

That said, I would recommend considering a table-driven approach as an alternative to hard-coded if/switch logic, regardless of whether you move the logic out of the code and into a config file.

于 2009-12-09T06:20:23.410 回答
0

我遇到了类似的情况,我之前就可能对您有帮助的类似问题问了几个问题。

我所做的系统是一个配置驱动、基于规则的动态系统。所有配置和规则都保存在数据库中。决策表是根据从数据库中检索到的值和规则动态构建的。然后在 C# 中转换和比较值。这是我问的关于C# 中动态决策表的问题。以及有关动态转换和比较从数据库中检索的值的问题。

所以我最终在配置表方面有一些类似的东西(只是一个例子):

Conditions  IsDecision LHS        Operator  RHS
TTFF        False      PostCode   >         100
TFTF        False      PostCode   <         10000
FTTT        True 

Note: LHS is the property name of the object.

上表用简单的英文表示:

Condition 1 PostCode > 100      Yes Yes No  No
Condition 2 PostCode < 10000    Yes No  Yes No
Outcome 1                       Yes
Outcome 2                           Yes
Outcome 3                               Yes
Outcome 4                                   Yes

Then you have other tables/configs to determine the action for each outcome.

实现的核心部分是如何动态构造决策表以及如何动态转换和比较字符串值,所有这些我在上一段中提供了具体实现的链接。我相信你可以在你的情况下应用类似的概念,我希望我已经解释了这个概念。

其他资源:

Martin Fowler 的决策树文章

卢克关于决策树的帖子

于 2009-12-10T04:55:34.333 回答
0

我建议您查看业务规则/推理引擎。NxBRE 周围有一个很好的社区,并且相当成熟。这可能超出了您的直接要求,但如果您希望这些规则随着时间的推移而增加复杂性,BRE 将提供一个很好的框架来控制事情。

于 2009-12-09T04:39:19.310 回答