【问题标题】:How much OOP_Crazy should real life programmer be? [closed]现实生活中的程序员应该是多少 OOP_Crazy? [关闭]
【发布时间】:2014-10-06 12:30:40
【问题描述】:

给定: 复杂的算法。

switch obj.field1 + "-" + obj.field2
case "A-A":
    return Sample(obj){Error = "Type can't be matched"}
case "A-B":
    {
    if(obj.field3 != null){
        var match = otherObjectCollection.FirstOrDefault(otherOb.field2 == obj.field3);
        return mathc != null? Sample(obj,match) : Sample(obj){Error="Can't find match"}
    }else{use field4...}
}
case "A-C":
{
var related = objectCollection.FirstOrDefault(parent.field4 == obj.field3);
if(related == null)
 return Sample(obj){Error = "Can't find parent"}
else {
  if(related.field3 != null){
       var match = otherObjectCollection.FirstOrDefault(otherOb.field2 == related.field3);
       return mathc != null? Samble(obj,match) : Sample(obj){Error="Can't find match"}
  }else{ use field 4 ...}

}
    }

等等。很多棘手的规则。我想出了下一个决定:

abstract class AggregationChain{
    protected MyObj Obj;
    abstract string Type{get;}
    abstract Priority Priority{get;}
    abstract bool Decide(MyObj obj);
    abstract Sample Aggregate(ICollection<MyObj> objects,ICollection<OtherObj> otherobjects);
    bool CanDecide(MyObj obj){
        if(Decide(obj)){
           Obj = obj;
           return true;
        }
        return false;
    }
 }

所以现在我可以拥有 ChainLinks 例如:

 class ABAggregationChainLink{

        string Type{get{return "A-B"}}
        Priority Priority{get{return Priority.High}}
        bool Decide(MyObj obj){ 
           return obj.fiel2 != null;
        }
        Sample Aggregate(ICollection<MyObj> objects,ICollection<OtherObj> otherobjects){
            var match = OtherObjectCollection.FirstOrDefault(otherOb.field2 == obj.field3);
            return mathc != null? Samble(obj,match) : Sample(obj){Error="Can't find match"}
        }

     }

在这个例子中,我需要再创建一个 A-B ChainLink 来处理“其他”情况。对于所有开关情况,我需要创建不同的 ChainLinks。这当然会增加类的数量和实现的时间,但类更适合单元测试,并且从我的角度来看更具可扩展性和灵活性。

问题:

  1. 我在想 - 可能是我对 Open-Close 和“好 编程”,对于现实生活中的应用程序,最好只创建 使用开关的方法并处理可重复使用的部件?
  2. 我有 在这里填写可能是更好的解决方案?

附言。这不是 C# 代码,我只是试图解释一下主要逻辑。

【问题讨论】:

  • 我有一种强烈的感觉,它太复杂了。一个简单的开关可能更易于维护和阅读。
  • 你需要学会在学术和实践之间划清界限。

标签: c# oop solid-principles flexibility


【解决方案1】:

在分析这样的事情时,您不能只看现在的情况。

  • 该算法是否易于维护?
  • 有多容易 在不改变现有功能的情况下添加新规则?
  • 多么容易 是要测试吗?
  • 您是否需要在运行时添加新规则(插件架构)?

在 3 种情况下,如果有其他情况,这两种情况都可能无关紧要。在 40 个带有子案例的案例中,以及所有都需要单元测试的新要求?我更喜欢每个规则的类的干净隔离(或者更可能是带有 lambda 表达式的泛型类添加到规则集合中)

您的链接类看起来不错,但您仍需要链类将所有链接放在一起并确定要处理的链接。最终可能会使用一个结构来替换该 switch 语句,例如:

Dictionary<String, Dictionary<String, List<Link>>> index;

if (index.ContainsKey(obj.Field1))
{
   var subIndex = index[obj.Field1];
   if (subIndex.ContainsKey(obj.Field2))
   {
      var linkList = subIndex[obj.Field2];
      foreach(var Link in linkList)
      {
          if (Link.Decide(obj))
          {
              return Link.Aggregate(objects, otherObjects);
          } 
      }
   }
}

如果您将 Decides 签名更改为 Func&lt;bool, MyObj&gt; 和 Aggregate Func&lt;Sample, ICollection&lt;MyObj&gt;,ICollection&lt;OtherObj&gt;&gt;

然后你可以添加类似的规则

RuleChain.AddRule("A", "A", (o) => true, (objs, others) => Sample(obj){Error = "Type can't be matched"})
RuleChain.AddRule("A", "B",...

【讨论】:

  • 我认为你是对的,但我无法想象这个规则应该是什么样子?因为它们没有相似的结构。
  • @ValentynVynogradskiy,如果不了解所有规则就很难说,你需要仔细阅读每一个规则,并找出最少的信息放在你的界面上才能使用它们。我已经编辑了我的答案,以包含有关链条的更多详细信息