避免在检查默认响应时出现代码重复。

huangapple go评论91阅读模式
英文:

Avoiding code duplication when checking for default responses

问题

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

因此,我最终在大多数方法中重复使用了这种构造:

  1. public Type1 m1(String s) {
  2. try {
  3. Type1 r = FakeApi.m1(s);
  4. if (r != null) {
  5. return r;
  6. }
  7. } catch (Exception e) {
  8. // 记录错误
  9. }
  10. return RealApi.m1(s);
  11. }

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

英文:

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).

So, I ended up duplicating this kind of construct in most of my methods:

  1. public Type1 m1(String s) {
  2. try {
  3. Type1 r = FakeApi.m1(s);
  4. if (r != null) {
  5. return r;
  6. }
  7. } catch (Exception e) {
  8. // log error
  9. }
  10. return RealApi.m1(s);
  11. }

What are some options to avoid duplicating this try/catch block everywhere? It's important that if FakeApi throws an exception or returns null, the RealApi must be called.

答案1

得分: 6

以下是翻译后的内容:

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

  1. public <T> T fakeOrReal(Supplier<T> fake, Supplier<T> real) {
  2. try {
  3. T r = fake.get();
  4. if (r != null) {
  5. return r;
  6. }
  7. }
  8. catch (Exception e) {
  9. // 记录错误
  10. }
  11. return real.get();
  12. }

然后你可以使用以下方式调用它:

  1. public Type1 m1(String s) {
  2. return fakeOrReal(() -> FakeApi.m1(s), () -> RealApi.m1(s));
  3. }
英文:

One option would be encapsulate the error checking behaviour into its own method:

  1. public &lt;T&gt; T fakeOrReal(Supplier&lt;T&gt; fake, Supplier&lt;T&gt; real) {
  2. try {
  3. T r = fake.get();
  4. if (r != null) {
  5. return r;
  6. }
  7. }
  8. catch (Exception e) {
  9. // log error
  10. }
  11. return real.get();
  12. }

You can then just call it with

  1. public Type1 m1(String s) {
  2. return fakeOrReal(() -&gt; FakeApi.m1(s), () -&gt; RealApi.m1(s));
  3. }

答案2

得分: 1

这并不像Thomas Preißler的回答那样简单,但它将帮助您完全避免重复任何方法。因此,如果您扩展了接口,您只需要修改具体的类,而不需要修改描述您想要的实际行为的链接器。

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

  1. interface Api {
  2. Type1 m1(String s);
  3. }

然后创建一个执行实际调用的类:

  1. class ConcreteApi implements Api {
  2. public Type1 m1(String s) {
  3. return RealApi.m1(s);
  4. }
  5. }

接下来创建您的FakeApi:

  1. class TotallyFakeApi implements Api {
  2. public Type1 m1(String s) {
  3. return FakeApi.m1(s);
  4. }
  5. }

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

  1. private static Object callImplementation(Api api, Method method, Object[] methodArgs) throws Exception {
  2. Method actualMethod = api.getClass().getMethod(actualMethod.getName(), actualMethod.getParameterTypes());
  3. return actualMethod.invoke(api, methodArgs);
  4. }
  5. Api fakeOrReal(Api fakeApi, Api realApi) {
  6. return (Api) Proxy.newProxyInstance(
  7. FakeApi.class.getClassLoader(),
  8. new Class[]{Api.class},
  9. (proxy, method, methodArgs) -> {
  10. try {
  11. Object r = callImplementation(fakeApi, method, methodArgs);
  12. if (r != null) {
  13. return r;
  14. }
  15. } catch (Exception e) {
  16. // logError(e);
  17. }
  18. return callImplementation(realApi, method, methodArgs);
  19. }
  20. );
  21. }

像这样获取实际的实现:

  1. Api apiToUse = fakeOrReal(new TotallyFakeApi(), new ConcreteApi());
英文:

This is not as simple as Thomas Preißler's answer but it will help you not repeat any method at all. 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:

  1. interface Api {
  2. Type1 m1(String s);
  3. }

Then a class that does the actual call:

  1. class ConcreteApi implements Api {
  2. public Type1 m1(String s) {
  3. return RealApi.m1(s);
  4. }
  5. }

Then create your FakeApi:

  1. class TotallyFakeApi implements Api {
  2. public Type1 m1(String s) {
  3. return FakeApi.m1(s);
  4. }
  5. }

Now, the tricky part to avoid repeating yourself:

  1. private static Object callImplementation(Api api, Method method, Object[] methodArgs) throws Exception {
  2. Method actualMethod = api.getClass().getMethod(actualMethod.getName(), actualMethod.getParameterTypes());
  3. return actualMethod.invoke(api, methodArgs);
  4. }
  5. Api fakeOrReal(Api fakeApi, Api realApi) {
  6. return (Api) Proxy.newProxyInstance(
  7. FakeApi.class.getClassLoader(),
  8. new Class[]{Api.class},
  9. (proxy, method, methodArgs) -&gt; {
  10. try {
  11. Object r = callImplementation(fakeApi, method, methodArgs);
  12. if (r != null) {
  13. return r;
  14. }
  15. } catch (Exception e) {
  16. // logError(e);
  17. }
  18. return callImplementation(realApi, method, methodArgs);
  19. }
  20. );
  21. }

Get the actual implementation like this:

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

huangapple
  • 本文由 发表于 2020年9月15日 19:27:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/63900844.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定