使用不兼容的包装器时如何减少代码重复
How to reduce code duplication when using non-compatible wrappers
[长话短说;博士]
问题是,在 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;]
}
假设我有 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
}
Then interface that extends above one, "mimicking" 外部方法 classes,但抛出自定义异常:
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;
}
然后,我们有以上接口的抽象实现:
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();
}
/* ... */
}
然后,我们覆盖接口中的函数,不包括 OperationManipulator 接口:
函数未 returning 任何版本:
@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) {
}
}
}
}
函数return正常参考版本:
@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;
}
函数 returning 类型参数对象:
@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也是一样,区别是:
- 构造函数有 class 个存储类型的参数
- 对象被转换为
IDoNotOwnThisType
而不是 OtherTypeIDoNotOwn
。此对象的功能也可能 return OtherTypeIDoNotOwn
.
IDoNotOwnThisType
是 AWrapper
换行的类型。
OtherTypeIDoNotOwn
是 AType
换行的类型。
然后,我们实现了这些抽象 classes:
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
和AWrapper
中写while
、try
、catch
等,我能以某种方式减少代码重复吗?在示例中,我只为每个 class 提供了 3 个函数,但在我的实际代码中,我有 50 多个方法。我能否以某种方式包装这些函数,使重复的部分不重复?
你的问题看起来很复杂,我不能说我已经成功地解决了它,但我会试一试,因为它看起来是一个非常有趣的问题而且因为我碰巧在处理与您的情况相似的情况方面有一些经验。
如果由于我的误解导致我的回答完全不正确,请原谅。
因此,您正在寻找的似乎是一种通用解决方案,用于在调用之前和之后注入您自己的代码,其中调用可以是任何方法,接受任意数量的参数,并且 returning 任何类型的 return 值。
在 java 中有一个动态代理工具,您可以在 java.lang.reflect.Proxy
下找到它。
有了它,您可以进行以下操作:
ClassLoader classLoader = myInterfaceClass.getClassLoader();
T temp = (T)Proxy.newProxyInstance( classLoader, new Class<?>[] { myInterfaceClass },
invocationHandler );
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;
}
};
因此,我认为您可以使用它以最少的代码量解决您的问题。
动态代理的创建和对 method.invoke()
的调用都没有表现得非常好,(你知道,反射有点慢,)但是如果你用它来测试,那应该没有关系。
[长话短说;博士]
问题是,在 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;]
}
假设我有 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
}
Then interface that extends above one, "mimicking" 外部方法 classes,但抛出自定义异常:
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;
}
然后,我们有以上接口的抽象实现:
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();
}
/* ... */
}
然后,我们覆盖接口中的函数,不包括 OperationManipulator 接口:
函数未 returning 任何版本:
@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) {
}
}
}
}
函数return正常参考版本:
@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;
}
函数 returning 类型参数对象:
@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也是一样,区别是:
- 构造函数有 class 个存储类型的参数
- 对象被转换为
IDoNotOwnThisType
而不是OtherTypeIDoNotOwn
。此对象的功能也可能 returnOtherTypeIDoNotOwn
.
IDoNotOwnThisType
是 AWrapper
换行的类型。
OtherTypeIDoNotOwn
是 AType
换行的类型。
然后,我们实现了这些抽象 classes:
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
和AWrapper
中写while
、try
、catch
等,我能以某种方式减少代码重复吗?在示例中,我只为每个 class 提供了 3 个函数,但在我的实际代码中,我有 50 多个方法。我能否以某种方式包装这些函数,使重复的部分不重复?
你的问题看起来很复杂,我不能说我已经成功地解决了它,但我会试一试,因为它看起来是一个非常有趣的问题而且因为我碰巧在处理与您的情况相似的情况方面有一些经验。
如果由于我的误解导致我的回答完全不正确,请原谅。
因此,您正在寻找的似乎是一种通用解决方案,用于在调用之前和之后注入您自己的代码,其中调用可以是任何方法,接受任意数量的参数,并且 returning 任何类型的 return 值。
在 java 中有一个动态代理工具,您可以在 java.lang.reflect.Proxy
下找到它。
有了它,您可以进行以下操作:
ClassLoader classLoader = myInterfaceClass.getClassLoader();
T temp = (T)Proxy.newProxyInstance( classLoader, new Class<?>[] { myInterfaceClass },
invocationHandler );
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;
}
};
因此,我认为您可以使用它以最少的代码量解决您的问题。
动态代理的创建和对 method.invoke()
的调用都没有表现得非常好,(你知道,反射有点慢,)但是如果你用它来测试,那应该没有关系。