Сколько должен быть OOP_Crazy программист в реальной жизни?

Дано: сложный алгоритм.

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"}
        }

     }

В этом примере мне нужно будет создать еще один AB ChainLink, который будет обрабатывать ситуацию "еще". И для всех случаев переключения мне нужно будет создавать разные цепочки ссылок. Это, конечно, увеличивает количество классов и время для реализации, но классы больше подходят для модульного тестирования и, с моей точки зрения, более расширяемы и гибки.

Вопрос:

  1. Я думаю - может быть, я взволнован Open-Close и "Хорошим программированием", и для реальных приложений лучше просто создать метод с переключателем и позаботиться о повторно используемых деталях?
  2. У меня начинка что тут может быть лучшее решение?

PS. Это не рабочий код C#, я просто попытался объяснить основную логику.

1 ответ

Решение

Анализируя что-то подобное, вы не можете просто посмотреть, что это сейчас.

  • Легко ли поддерживать этот алгоритм в будущем?
  • Насколько легко добавлять новые правила, не меняя существующую функциональность?
  • Насколько легко это проверить?
  • Вам нужно добавить новые правила во время выполнения (архитектуры плагинов)?

В 3 случаях с некоторыми, если другие, это, вероятно, не имеет значения в любом случае. В 40 случаях с дополнительными случаями и новым требованием, что все это нуждается в модульном тестировании? Я бы предпочел чистую изоляцию класса по правилу (или, скорее, универсальный класс с лямбда-выражениями, добавляемый в набор правил)

Ваш класс ссылок выглядит хорошо, но вам все равно понадобится класс цепочки, чтобы объединить все ссылки и определить, какую ссылку обрабатывать. Это может закончиться структурой, которая заменит этот оператор 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);
          } 
      }
   }
}

Если вы измените Решает подпись на Func<bool, MyObj> и совокупность Func<Sample, ICollection<MyObj>,ICollection<OtherObj>>

тогда вы можете добавить правила, такие как

RuleChain.AddRule("A", "A", (o) => true, (objs, others) => Sample(obj){Error = "Type can't be matched"})
RuleChain.AddRule("A", "B",...
Другие вопросы по тегам