java - 使用不兼容的包装器时如何减少代码重复

标签 java code-duplication

[TL;DR] 问题是,在 AWrapperAType 中,我必须复制几乎整个函数,其中始终存在语法:

public [TYPE/void] METHOD([OPT: args]) throws TestFailedException {
[OPT: TYPE result = null;]
long startTime = System.currentTimeMillis();
while (true) {
  try {
    beforeOperation();
    [OPT: result =] ((WrappedType) element).METHOD([OPT: args]);
    handleSuccess();
    break;
  } catch (Exception e) {
     handleSoftFailure(e);
     if (System.currentTimeMillis() - startTime > TIMEOUT) {
       handleFailure(e);
       break;
     } else {
       try {
         Thread.sleep(WAIT_FOR_NEXT_TRY);
       } catch (InterruptedException ex) {
       }
     }
   }
 }
 [OPT: return result;]
}

假设我有 2 个我不拥有的类(class):

public class IDontOwnThisType {

  public void doA(String string) { System.out.println("doA"); }
  public String doB();  {System.out.println("doB"); return "doB";}
  public OtherTypeIDoNotOwn doC() {System.out.println("doC"); return new OtherTypeIDoNotOwn();}

}

public OtherTypeIDoNotOwn {

  public void doD() { System.out.println("doD"); }
  public String doE() { System.out.println("doE); }
  public OtherTypeIDoNotOwn  doF(String string) {System.out.println("doF"); return new OtherTypeIDoNotOwn();}

}

所以,我有一个界面:

public interface OperationManipulator {

  void beforeOperation(); //called before operation
  void handleSuccess(); //called after success
  void handleSoftFailure(Exception e); //called after every failure in every try
  void handleFailure(Exception e) throws TestFailedException; //called after reaching time limit 

}

然后是一个扩展上述接口(interface)的接口(interface),“模仿”外部类的方法,但抛出自定义异常:

public interface IWrapper<T extends IType> extends OperationManipulator {

  public void doA(String string) throws TestFailedException;
  public String doB() throws TestFailedException;    
  public T doC() throws TestFailedException;

}

然后我们有 IType,它也扩展了 OperationManipulator:

public interface IType<T extends IType> extends OperationManipulator {

  public void doD() throws TestFailedException; 
  public String doE() throws TestFailedException;    
  public T doF(String string) throws TestFailedException;

}

然后,我们就有了上述接口(interface)的抽象实现:

public abstract class AType<T extends IType> implements IType{

  Object element; // I do not own type of this object, cant modify it.
  Class typeClass;
  long TIMEOUT = 5000;
  long WAIT_FOR_NEXT_TRY = 100;

  public AType(Object element) {
    this.element = element;
    elementClass = this.getClass();
  }

/* ... */

}

然后,我们重写接口(interface)中的函数,不包括OperationManipulator接口(interface):

函数不返回任何版本:

@Override
public void doD() throws TestFailedException {
  long startTime = System.currentTimeMillis();
  while (true) {
    try {
      beforeOperation();
      ((OtherTypeIDoNotOwn) element).doD();
      handleSuccess();
      break;
    } catch (Exception e) {
      handleSoftFailure(e);
      if (System.currentTimeMillis() - startTime > TIMEOUT) {
        handleFailure(e);
        break;
      } else {
        try {
          Thread.sleep(WAIT_FOR_NEXT_TRY);
        } catch (InterruptedException ex) {
        }
      }
    }
  }

返回正常引用版本的函数:

@Override
public String doE() throws TestFailedException {
  String result = null;
  long startTime = System.currentTimeMillis();
  while (true) {
    try {
      beforeOperation();
      result = ((OtherTypeIDoNotOwn) element).doE();
      handleSuccess();
      break;
    } catch (Exception e) {
      handleSoftFailure(e);
      if (System.currentTimeMillis() - startTime > TIMEOUT) {
        handleFailure(e);
        break;
      } else {
        try {
          Thread.sleep(WAIT_FOR_NEXT_TRY);
        } catch (InterruptedException ex) {
        }
      }
    }
  }
  return result;
}

函数返回类型参数的对象:

@Override
public T doF(String string) throws TestFailedException {
  T result = null;
  long startTime = System.currentTimeMillis();
  while (true) {
    try {
      beforeOperation();
      OtherTypeIDoNotOwn temp = ((OtherTypeIDoNotOwn) element).doF(string);
      result = (T) elementClass.getDeclaredConstructor(Object.class).newInstance(temp);
      handleSuccess();
      break;
    } catch (Exception e) {
      handleSoftFailure(e);
      if (System.currentTimeMillis() - startTime > TIMEOUT) {
        handleFailure(e);
        break;
      } else {
        try {
          Thread.sleep(WAIT_FOR_NEXT_TRY);
        } catch (InterruptedException ex) {
        }
      }
    }
  }
  return result;
}

AWrapper 也是如此,但区别在于:

  1. 构造函数具有存储类型的类参数
  2. 对象被转换为 IDoNotOwnThisType 而不是 OtherTypeIDoNotOwn。此对象的函数也可能返回 OtherTypeIDoNotOwn

IDoNotOwnThisTypeAWrapper 正在包装的类型。

OtherTypeIDoNotOwnAType 所包装的类型。

然后,我们实现了这些抽象类:

public class AssertingType extends AType<AssertingType> {

  public AssertingType(Object element) {
    super(element);
  }

  @Override
  public void beforeOperation() {
    //System.out.println("Asserting type before operation!");
  }

  @Override
  public void handleSuccess() {
    //TODO: add to log file and log to output
    System.out.println("Asserting type success!");
  }

  @Override
  public void handleFailure(Exception e) throws TestFailedException {
    //TODO: add to log file, log to output and throw exception
    System.out.println("Asserting type failure!");
    e.printStackTrace();
    throw new TestFailedException();
  }

  @Override
  public void handleSoftFailure(Exception e) {
    //TODO: add to log file, log to output
    System.out.println("Asserting type soft failure!");
    e.printStackTrace();
  }

}

还有:

public class AssertingWrapper extends AWrapper<AssertingType> {

  public AssertingWrapper (Object driver) {
    super(driver, AssertingType.class);
  }

  @Override
  public void beforeOperation() {
    //TODO
    System.out.println("Asserting wrapper success!");
  }

  @Override
  public void handleSuccess() {
    //TODO: add to log file and log to output
    System.out.println("Asserting wrapper success!");
  }

  @Override
  public void handleFailure(Exception e) throws TestFailedException {
    //TODO: add to log file, log to output and throw exception
    System.out.println("Asserting wrapper failure!");
    throw new TestFailedException();
  }

  @Override
  public void handleSoftFailure(Exception e) {
    //TODO: add to log file, log to output
    System.out.println("Asserting wrapper soft failure!");
    e.printStackTrace();
  }
}

所以,我们可以这样使用它:

AssertingWrapper wrapper = new AssertingWrapper(new IDoNotOwnThisType());

AssertingType type = wrapper.doC();

AssertingType type2 = type.doF();

输出:

Asserting wrapper before operation!
doC
Asserting wrapper success!
Asserting type before operation!
doF
Asserting type success!

完整的工作代码在这里: LIVE

问题是,我总是在 AType 中编写 whiletry catch 等>AWrapper,我可以以某种方式减少代码重复吗?在示例中,我为每个类仅提供了 3 个函数,但在我的实际代码中,我有 50 多个方法。我可以以某种方式包装这些函数,以便重复的部分不重复吗?

最佳答案

你的问题似乎相当复杂,我不能声称能够成功地解决它,但我会尝试一下,因为这似乎是一个非常有趣的问题,而且因为我碰巧有处理与您的情况相似的情况的一些经验。

如果由于我的误解而导致我的回答完全不正确,请原谅。

因此,您正在寻找的是一种通用解决方案,用于在调用之前和之后注入(inject)您自己的代码,其中调用可以是任何方法,接受任意数量的参数并返回任何类型的返回值.

在java中存在一个动态代理工具,您可以在java.lang.reflect.Proxy下找到它。

有了它,您可以执行以下操作:

ClassLoader classLoader = myInterfaceClass.getClassLoader();
T temp = (T)Proxy.newProxyInstance( classLoader, new Class<?>[] { myInterfaceClass }, 
    invocationHandler );

inplicationHandler 由您提供,其形式如下:

private final InvocationHandler invocationHandler = new InvocationHandler()
{
    @Override
    public Object invoke( Object proxy, Method method, Object[] arguments )
        throws Throwable
    {
        /* your pre-invocation code goes here */
        /* ... */

        /* invoke original object */
        Object result = method.invoke( myObject, arguments );

        /* your post-invocation code goes here */
        /* ... */

        /* return the result (will probably be null if method was void) */
        return result;
    }
};

所以,我认为您也许可以使用它以最少的代码来解决您的问题。

动态代理的创建和对 method.invoke() 的调用都表现得非常好(你知道,反射有点慢),但如果你使用它进行测试,它应该没关系。

关于java - 使用不兼容的包装器时如何减少代码重复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45388329/

相关文章:

java - Java 中的后自增 (i++) 和预自增 (++i) 运算符如何工作?

java - Websphere 上使用 Java 5 的 Jersey REST 服务

java - 如何检测 html 字符串中的第一个和倒数第二个 p 标签

java - 从B类访问A类

java - 自定义android谷歌地图方向线

java - 有代码重复并使其非常简单/可读更好,还是没有重复(使用泛型)但要复杂得多?

c++ - 防止循环内外的代码重复

java - 跟踪实用程序类

java - 当值需要不同但方法不需要不同时,方法中会出现代码重复

ruby-on-rails - Rails - 相同表单的不同 form_for 语句