【问题标题】:Best design pattern/approach for a long list of if/else/execute branches of code一长串 if/else/execute 代码分支的最佳设计模式/方法
【发布时间】:2015-05-09 02:59:39
【问题描述】:

我有一个想要重构的“遗留”代码。
该代码基本上对服务器进行远程调用并得到回复。然后根据回复相应执行。
代码骨架示例:

public Object processResponse(String responseType, Object response) {
    if(responseType.equals(CLIENT_REGISTERED)) {  
       //code  
       //code ...
    }  
    else if (responseType.equals(CLIENT_ABORTED)) {
       //code  
       //code....
    }    
    else if (responseType.equals(DATA_SPLIT)) {
      //code
      //code... 
   }  
   etc  

问题在于 if/else 分支有很多很多,并且每个 if 中的代码都不是微不足道的。
所以它变得难以维护。
我想知道最好的模式是什么?
我的一个想法是创建一个方法名称与 responseType 相同的单个对象,然后在 processResponse 中仅使用反射调用与 responseType 同名的方法。
这将清理 processResponse 但它将代码移动到具有许多/许多方法的单个对象,我认为反射会导致性能问题。
有没有很好的设计方法/模式来清理它?

【问题讨论】:

    标签: java oop design-patterns refactoring


    【解决方案1】:

    您描述的案例似乎非常适合策略模式的应用。特别是,您有许多算法变体,即根据远程服务器调用的响应执行的代码。

    实现 Stategy 模式意味着您必须定义一个类层次结构,如下所示:

    public interface ResponseProcessor {
       public void execute(Context ctx);
    }
    class ClientRegistered implements ResponseProcessor {
       public void execute(Context ctx) {
          // Actions corresponding to a client that is registered
          // ...
       }
    }
    class ClientAborted implements ResponseProcessor {
       public void execute(Context ctx) {
          // Actions corresponding to a client aborted
          // ...
       }
    }
    // and so on...
    

    Context 类型应包含执行每个“策略”所需的所有信息。请注意,如果不同的策略共享一些算法片段,您也可以在其中使用模板方法模式

    你需要一个工厂来在运行时创建一个特定的策略。工厂将从收到的响应开始制定策略。一种可能的实现应该是@Sattar Imamov 建议的实现。工厂将包含if .. else 代码。

    如果策略类构建起来并不繁重,并且它们在构建时不需要任何外部信息,您还可以将每个策略映射到枚举值。

    public enum ResponseType {
       CLIENT_REGISTERED(new ClientRegistered()),
       CLIENT_ABORTED(new ClientAborted()),
       DATA_SPLIT(new DataSplit());
    
       // Processor associated to a response
       private ResponseProcessor processor;
    
       private ResponseType(ResponseProcessor processor) {
          this.processor = processor;
       }
       public ResponseProcessor getProcessor() {
          return this.processor;
       }
    }
    

    【讨论】:

      【解决方案2】:

      两种方法:

      1. 策略模式http://www.dofactory.com/javascript/strategy-design-pattern
      2. 创建字典,其中键是元数据(在您的情况下元数据是 responseType),值是函数。

      例如:

      把这个放在构造函数中

      responses = new HashMap<string, SomeAbstraction>(); responses.Put(CLIENT_REGISTERED, new ImplementationForRegisteredClient()); responses.Put(CLIENT_ABORTED, new ImplementationForAbortedClient());

      ImplementationForRegisteredClientImplementationForAbortedClient 在哪里实现 SomeAbstraction

      并通过调用此字典 responses.get(responseType).MethodOfYourAbstraction(SomeParams);

      如果你想遵循 DI 的原则,你可以在你的客户端类中注入这个 Dictionary。

      【讨论】:

      • 在策略模式中,我如何在运行时使用正确的策略?例如。在en.wikipedia.org/wiki/Strategy_pattern#Java 中,它只是在每个服务器回复时硬编码一个策略实例,我将如何有效地使用正确的策略?
      • TBH 字典示例虽然不错,但 IMO 不是我们通常用 Java 编写的代码
      • @Jim 对不起,我在标签中看到 Java 自动想到了 javascript。我更新我的答案
      • +1。好答案。字典只不过是一个预先实例化的工厂。另一种方法是创建一个在需要时实例化所需实现的类,而不是一起创建它们。
      【解决方案3】:

      我的第一个方法是用 switch/case 替换 if/else if 结构:

      public Object processResponse(String responseType, Object response) {
          switch(responseType) {
              case CLIENT_REGISTERED: {  
             //code ...
          }  
          case CLIENT_ABORTED: {
             //code....
          }    
          case DATA_SPLIT: {
            //code... 
         }  
      

      我可能会从那里提取每个块作为方法,然后从那里应用策略模式。在任何感觉合适的时候停下来。

      【讨论】:

      • 在策略模式中,我如何在运行时使用正确的策略?例如。在en.wikipedia.org/wiki/Strategy_pattern#Java 中,它只是在每个服务器回复时硬编码一个策略实例,我将如何有效地使用正确的策略?
      猜你喜欢
      • 2015-01-31
      • 2015-08-12
      • 2021-08-20
      • 1970-01-01
      • 1970-01-01
      • 2012-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多