【问题标题】:Avoiding code duplication when checking for default responses检查默认响应时避免代码重复
【发布时间】:2020-09-15 11:27:32
【问题描述】:

我有一个调用外部 API(下面代码中的 RealApi)的 Java 程序,有时我想避免调用此 API,而是返回预先构建的响应(由 FakeApi 生成)。

所以,我最终在我的大多数方法中复制了这种构造:

public Type1 m1(String s) {
    try {
        Type1 r = FakeApi.m1(s);
        if (r != null) {
            return r;
        }
    } catch (Exception e) {
        // log error
    }

    return RealApi.m1(s);
}

有哪些选项可以避免到处重复这个 try/catch 块?重要的是,如果 FakeApi 抛出异常或返回 null,则必须调用 RealApi

【问题讨论】:

  • 封装该行为的包装器,您只会在代码中看到Wrapper.m1(s); 调用?

标签: java code-duplication


【解决方案1】:

一种选择是将错误检查行为封装到它自己的方法中:

public <T> T fakeOrReal(Supplier<T> fake, Supplier<T> real) {
  try {
    T r = fake.get();
    if (r != null) {
      return r;
    }
  }
  catch (Exception e) {
    // log error
  }

  return real.get();
}

然后你可以直接调用它

public Type1 m1(String s) {
  return fakeOrReal(() -> FakeApi.m1(s), () -> RealApi.m1(s));
}

【讨论】:

  • 使用这个选项,仍然需要为他们想要使用的每个方法重复最后一个代码块。
【解决方案2】:

这并不像Thomas Preißler's answer 那样简单,但它可以帮助您完全不重复任何方法。所以如果你扩展接口,你只需要修改具体的类,而不是描述你想要的实际行为的链接器。

创建一个包含RealApi的所有方法的接口:

interface Api {
  Type1 m1(String s);
}

然后是一个进行实际调用的类:

class ConcreteApi implements Api {
  public Type1 m1(String s) {
    return RealApi.m1(s);
  }
}

然后创建你的 FakeApi:

class TotallyFakeApi implements Api {
  public Type1 m1(String s) {
    return FakeApi.m1(s);
  }
}

现在,避免重复自己的棘手部分:

private static Object callImplementation(Api api, Method method, Object[] methodArgs) throws Exception {
  Method actualMethod = api.getClass().getMethod(actualMethod.getName(), actualMethod.getParameterTypes());
  return actualMethod.invoke(api, methodArgs);
}
Api fakeOrReal(Api fakeApi, Api realApi) {
  return (Api) Proxy.newProxyInstance(
      FakeApi.class.getClassLoader(),
      new Class[]{Api.class},
      (proxy, method, methodArgs) -> {
        try {
          Object r = callImplementation(fakeApi, method, methodArgs);
          if (r != null) {
            return r;
          }
        } catch (Exception e) {
          // logError(e);
        }
        return callImplementation(realApi, method, methodArgs);
      }
    );
  
}

像这样获取实际的实现:

Api apiToUse = fakeOrReal(new TotallyFakeApi(), new ConcreteApi());

【讨论】:

    猜你喜欢
    • 2015-06-16
    • 2014-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多