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

Java 如何在使用不兼容的包装器时减少代码重复,java,code-duplication,Java,Code Duplication,[TL;DR] 问题是,在AWrapper和AType中,我必须复制几乎整个函数,其中始终存在语法: public [TYPE/void] METHOD([OPT: args]) throws TestFailedException { [OPT: TYPE result = null;] long startTime = System.currentTimeMillis(); while (true) { try { beforeOperation(); [OPT: res

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

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;]
}
假设我有两个我没有的课程:

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 

}
然后,扩展到一个以上的接口,“模仿”外部类的方法,但引发自定义异常:

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;

}
然后,我们有上述接口的抽象实现:

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

/* ... */

}
返回正常参考版本的函数:

@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;
}
Awraper也是如此,但区别在于:

  • 构造函数具有存储类型的类参数
  • 对象被强制转换为
    IDONOTOWTHISTYPE
    ,而不是
    其他类型IDONOTOWN
    。此对象的函数也可能返回
    othertypeidonown
  • idonown此类型是
    AWrapper
    正在包装的类型

    othertypeidonown
    AType
    正在包装的类型

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

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

    Asserting wrapper before operation!
    doC
    Asserting wrapper success!
    Asserting type before operation!
    doF
    Asserting type success!
    
    完整的工作代码如下:


    问题是,我总是要写
    AType
    AWrapper
    中尝试
    catch
    等,我能以某种方式减少代码重复吗?在这个示例中,我只为每个类提供了3个函数,但在我的实际代码中,我有50多个方法。我可以用某种方式包装这些函数,这样重复的部分就不会被复制吗?

    您的问题似乎很复杂,我不能说我能够成功地将我的想法包装起来,但我会尝试一下,因为这似乎是一个非常有趣的问题,因为我碰巧有一些处理类似于你的情况的经验

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

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

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

    使用它,您可以执行以下操作:

    ClassLoader classLoader = myInterfaceClass.getClassLoader();
    T temp = (T)Proxy.newProxyInstance( classLoader, new Class<?>[] { myInterfaceClass }, 
        invocationHandler );
    
    因此,我认为您可以使用它以最少的代码量解决您的问题


    无论是创建动态代理还是调用
    方法。invoke()
    性能都不是很好(你知道,反射有点慢),但是如果你使用它进行测试,这应该无关紧要。

    你能给我们一个TL;所有这些的博士?@MikeNakis providedso,我的解决方案对你有用吗?它给了我很多启发:)我必须在整个类中添加额外的功能,所以我不能像你建议的那样只使用代理。最后,我编写了一个函数:
    protectedobjectreferencedmethod(类wrappedInterface、字符串methodName、对象[]argValues、函数resultConverter)
    ,并设法将每个函数代码简化为一个线性函数:)
    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!
    
    ClassLoader classLoader = myInterfaceClass.getClassLoader();
    T temp = (T)Proxy.newProxyInstance( classLoader, new Class<?>[] { myInterfaceClass }, 
        invocationHandler );
    
    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;
        }
    };