【问题标题】:Configuring the order of method execution配置方法执行的顺序
【发布时间】:2016-05-09 04:12:27
【问题描述】:

我有一个能够调用 4 个不同端点的 api 客户端。我遇到了一个问题,我试图使其尽可能可配置,因为每个 api 调用方法都是相互独立的。所以,我想保留它们可以称为灵活的顺序。这就是我的意思:

public class APICaller () {
    public void endpointA () {...
    }

    public void endpointB () {...
    }

    public void endpointC () {...
    }

    public void endpointD () {...
    }
}

我尝试通过传入一个 Endpoint 枚举数组(A,B,C,D)然后迭代数组的内容并使用 switch 语句调用相关方法来做到这一点:

for (Endpoint end : passedInArrayOfOrdering) {
    switch(end) {
        case A:
            endpointA();
        ...
    }
}

我的上述尝试对我来说似乎有点脏。是否存在让我配置进行这些端点调用的顺序的现有模式?

【问题讨论】:

  • 在过去的几周里,SO 发布了一个类似的问题。虽然是关于method references with javafx,但基本方法可能对调查有用。

标签: java algorithm design-patterns


【解决方案1】:

这里实际上并没有涉及任何特定的模式——充其量,可以将其视为Command Pattern 的一个实例。幸运的是,Java 8 已经包含了一般处理此问题所需的一切:您可以使用 Method References 存储要调用的方法,然后遍历列表:

import java.util.Arrays;
import java.util.List;

public class ApiCallerExample {
    public static void main(String[] args) {
        ApiCaller a = new ApiCaller();

        List<Runnable> commands = Arrays.asList(
            a::endpointB, 
            a::endpointA, 
            a::endpointD,
            a::endpointC, 
            a::endpointA, 
            a::endpointB);
        commands.forEach(Runnable::run); // Prints "BADCAB"
    }
}

class ApiCaller { 
    public void endpointA () { System.out.print("A"); }
    public void endpointB () { System.out.print("B"); }
    public void endpointC () { System.out.print("C"); }
    public void endpointD () { System.out.print("D"); }
}

注意这里方法的类型是Runnable,因为它们是不返回任何东西的无参数方法。如果您的方法需要参数(或返回某些内容),那么您可以使用适当的functional interface,或者将您的方法参数“固定”到调用站点的特定调用:

Runnable runnable0 = () -> apiCaller.endpointA(argument0, argument1);
commands.add(runnable0);

【讨论】:

    【解决方案2】:

    你可以定义一个调用接口

    公共接口调用者

    { void callSomething(APICaller ac); }

    然后定义实现

    public class CallA implements Caller
    {
      public void callSomething(APICaller ac)
      {
         ac.endpointA()
       }
    }
    

    然后传递诸如 CallA 实例之类的对象,而不是您的 Endpoint 枚举,因此您不需要使用 switch() 语句。

    【讨论】:

    • 这意味着我必须在我的 APICaller 类上公开 endpointA() 等。我宁愿避免这种情况!
    【解决方案3】:

    您正在使用枚举类型来切换执行的逻辑,这意味着逻辑取决于类型 - 所以在类型上定义它。将Endpoint 设为接口并创建特定端点。例如

    public interface Endpoint {
          public void call();
    }
    

    以及实现,例如

    public class EndpointA implements Endpoint {
    
        public void call(){
          // endpoint a specific code
        }
    
    }
    

    然后你可以避免切换

    for (Endpoint end : passedInArrayOfOrdering) {
       end.call()
    }
    

    PS: 每次您使用某种类型切换(例如使用枚举)时,您都会根据类型解析要手动执行的代码。 JVM 可以做得更好。它被命名为动态调度。从 OO 的角度来看,它只是多态性。

    前段时间我写了一篇关于类型转换的博客并讨论了它的优缺点。见https://www.link-intersystems.com/blog/2015/12/03/enums-as-type-discriminator-anti-pattern/

    【讨论】:

      【解决方案4】:
      public class EndPoint {
      
          public void call() {
              // process endpoint
          }
      }
      

      现在让每个端点的内容/数据将一个端点与另一个端点区分开来。例如,如果它们是几何点,那么重要的是它们的坐标。不需要创建端点A、端点B等方法。如果你有数百个点的情况,你会创建数百个方法吗?没有。

      ...
      
      for (Endpoint end : passedInArrayOfOrdering) {
         end.call();
      }
      

      【讨论】:

        猜你喜欢
        • 2013-11-05
        • 1970-01-01
        • 1970-01-01
        • 2021-03-15
        • 2015-09-05
        • 2017-08-16
        • 2012-10-30
        • 1970-01-01
        • 2017-05-13
        相关资源
        最近更新 更多