【问题标题】:Better approach to refactor conditional part of the code更好的方法来重构代码的条件部分
【发布时间】:2016-07-05 21:25:57
【问题描述】:

我正在尝试重构一段给定的代码,如下所述:

原始代码:

Method(URL link)
{
    if(ConditionA(link))
    {
      MehodA(link);
    }else if(ConditionB(link))
    {
      MehodB(link);
    }else if(ConditionC(link))
    {
      MehodC(link);
    }else if(ConditionD(link))
    {
      MehodD(link);
    }
}

上面的代码可能会随着未来新情况的出现而增长。重构后,我可以将代码分成多个类,每个类都专注于单一职责,从而降低初始复杂性,如下所示:

重构之后:

METHOD(URL link)
{
  ConditionalHandlerClass obj = new ConditionalHandlerClass(link);
  ConditionalHandlerClass.HandleLinkProcessing();
}

Class ConditionalHandlerClass
{
  URL link;
  IConditionalProcess process;

  public ConditionalHandlerClass(URL _link)
  {
    link = _link;
  }

  public void HandleLinkProcessing()
  {
     if(ConditionA(link))
        {
          process = new ProcessA(link);
        }else if(ConditionB(link))
        {
          process = new ProcessB(link);
        }else if(ConditionC(link))
        {
         process = new ProcessC(link);
        }else if(ConditionD(link))
        {
         process = new ProcessD(link);
        }
    process.Handle();
  }
}

interface IConditionalProcess
{
  void handle();
}


class ProcessA() : IConditionalProcess
{
   void handle()
  {
   // Business Logic here
  }
}

class ProcessB() : IConditionalProcess
{
   void handle()
  {
   // Business Logic here
  }
}

class ProcessC() : IConditionalProcess
{
   void handle()
  {
   // Business Logic here
  }
}

class ProcessD() : IConditionalProcess
{
   void handle()
  {
   // Business Logic here
  }
}

但是我看到 ConditionalHandlerClass 类中的 HandleLinkProcessing() 方法仍会随着新条件的不断添加而不断增加。

您能否建议我如何使这个实现更好,以便在添加新的 ConditionE() 和 MethodE() 调用流时不应该更改像 ConditionalHandlerClass 这样的类。因此,即使添加了新条件,也可以降低一次类的复杂性。

我正在目标 c 中编写此代码。

【问题讨论】:

标签: objective-c design-patterns solid-principles


【解决方案1】:

我认为你在正确的轨道上。当然,可以通过无数种方式进行处理(如果通过 DI 进行构造函数注入,则不需要处理大多数情况),但这是一种方法,它组合了具有条件和执行逻辑的 Handler 类的可重用实例。 .

public interface IConditional
{
    bool Evaluate(Url link);
}

public class ConditionA : IConditional
{
    public bool Evaluate(Url link)
    {
        return true; // your conditional logic here
    }
}

public class ConditionB : IConditional
{
    public bool Evaluate(Url link)
    {
        return true; // your conditional logic here
    }
}

public class ConditionC : IConditional
{
    public bool Evaluate(Url link)
    {
        return true; // your conditional logic here
    }
}

public class ConditionD : IConditional
{
    public bool Evaluate(Url link)
    {
        return true; // your conditional logic here
    }
}

public interface IProcessor
{
    void Process(Url link);
}

public class MethodA : IProcessor
{
    public void Process(Url link)
    {
        // whatever A does?
    }
}

public class MethodB : IProcessor
{
    public void Process(Url link)
    {
        // whatever B does?
    }
}

public class MethodC : IProcessor
{
    public void Process(Url link)
    {
        // whatever C does?
    }
}

public class MethodD : IProcessor
{
    public void Process(Url link)
    {
        // whatever D does?
    }
}

public class Handler
{
    private IConditional conditional;
    private IProcessor processor;

    public Handler(
        IConditional conditionalReference,
        IProcessor processorReference)
    {
        this.conditional = conditionalReference;
        this.processor = processorReference;
    }

    public bool Handle(Url link)
    {
        bool handled = false;
        if (this.conditional.Evaluate(link)
        {
            this.processor.Process(link);
            handled = true;
        }

        return handled;
    }
}

public class Program
{
    public static void Main()
    {
        Handler[] orderedHandlers = new []
        {
            new Handler(new ConditionA(), new MethodA()),
            new Handler(new ConditionB(), new MethodB()),
            new Handler(new ConditionC(), new MethodC()),
            new Handler(new ConditionD(), new MethodD()),
        };

        Url link = new Url("xxx");

        foreach(Handler handler in orderedHandlers)
        {
            if(handler.Handle(link))
            {
                break;
            }
        }
    }
}

【讨论】:

    【解决方案2】:

    一种可能的方法是保留Predicate<URL>Consumer<URL> 对的集合。这种结构可能是,例如LinkedHashMap,它保持插入顺序。

    LinkedHashMap<Predicate<URL>, Consumer<URL>> ops = new LinkedHashMap<> {{ 
        put(::ConditionA, ::MethodA); 
        put(::ConditionB, ::MethodB); .... 
    }}
    
    void processURL(URL link) {
         for(Map.Entry<...,...> entry : ops.entrySet()) {
              if (entry.getKey().test(link)) {
                   entry.getValue().accept(link);
                   break;
              }
         }
    }
    

    编辑:在我写答案时,Java 标签消失了。但是,我不是很流利的 Objective C,但与主要语言无关。

    【讨论】:

    • 这与我在回复中发布的基本相同。这两种解决方案都摆脱了大如果,它只是处理程序列表,分别是您的地图增长并需要以某种方式初始化。
    【解决方案3】:

    可能类似于为处理程序引入策略并对其进行迭代。处理程序列表可以在运行时或在某些静态上下文中初始化,但至少可以避免您创建 mega-if-construct

    编辑对不起我的 Java 伪代码...

    interface LinkHandler() {
    
      boolean accepts(URL link);
    
      void handle(URL link);
    }
    
    public static void main( ...) {
      List<LinkHandler> handlers = ...
    
      URL urlToCheck = new URL( ... );
    
      for( LinkHandler handler : handlers ) {
         if( handler.accepts(urlToCheck) ) {
           handler.handle(urlToCheck);
           break;
         }
       }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 2015-12-31
      • 2011-09-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多