简体   繁体   English

检查默认响应时避免代码重复

[英]Avoiding code duplication when checking for default responses

I have a Java program that calls an external API ( RealApi in the code below) and sometimes I want to avoid calling this API and instead return pre-constructed responses (generated by FakeApi ).我有一个调用外部 API(下面代码中的RealApi )的 Java 程序,有时我想避免调用这个 API 而是返回预先构建的响应(由FakeApi生成)。

So, I ended up duplicating this kind of construct in most of my methods:所以,我最终在我的大多数方法中复制了这种结构:

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);
}

What are some options to avoid duplicating this try/catch block everywhere?有哪些选项可以避免在任何地方复制这个 try/catch 块? It's important that if FakeApi throws an exception or returns null, the RealApi must be called.重要的是,如果FakeApi抛出异常或返回 null,则必须调用RealApi

One option would be encapsulate the error checking behaviour into its own method:一种选择是将错误检查行为封装到它自己的方法中:

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();
}

You can then just call it with然后你可以调用它

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

This is not as simple as Thomas Preißler's answer but it will help you not repeat any method at all.这不像Thomas Preißler 的回答那么简单,但它会帮助您根本不重复任何方法。 So if you expand the interface, you have to modify only the concrete classes and not the linker which describes the actual behavior you want.因此,如果扩展接口,则只需修改具体的类,而不必修改描述所需实际行为的链接器。

Create an interface that contains all the methods of RealApi :创建一个包含RealApi所有方法的RealApi

interface Api {
  Type1 m1(String s);
}

Then a class that does the actual call:然后是一个执行实际调用的类:

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

Then create your FakeApi:然后创建你的 FakeApi:

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

Now, the tricky part to avoid repeating yourself:现在,避免重复自己的棘手部分:

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);
      }
    );
  
}

Get the actual implementation like this:得到这样的实际实现:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM