有没有办法在调用类的任何其他函数之前始终执行函数?
我有一个类,我需要在调用任何函数之前刷新一些字段:
public class Example {
private int data;
public void function1(){
}
public void function2(){
}
//@BeforeOtherFunction
private void refresh(){
// refresh data
}
}
因为编程似乎不好,所以我不想在其他所有功能的开头调用refresh
。由于其他人也会参与这个项目的工作,因此有人会延长通话时间,并且不会拨打refresh
。
JUnit为@Before
- 注释提供了解决方案。有没有办法在其他课程中这样做?
顺便说一下:如果你知道一个编程模式,除了在每次调用任何函数时执行函数以另一种方式解决这个问题,那也是非常有用的!
答案 0 :(得分:2)
使用动态代理,您可以在其中过滤到应该调用特定“之前”方法的方法。并在发送呼叫之前在这些情况下调用它。请参阅How do I intercept a method invocation with standard java features (no AspectJ etc)?
的答案<强>更新强>
需要为代理分隔接口。 refresh()方法不能保持私有。它必须是公共的,并且可以从代理中调用接口的一部分(这里不是很好)。
package CallBefore;
public interface ExampleInterface {
void function1();
void function2();
void otherFunction();
void refresh();
}
您的类实现了该接口:
package CallBefore;
public class Example implements ExampleInterface {
@Override
public void function1() {
System.out.println("function1() has been called");
}
@Override
public void function2() {
System.out.println("function2() has been called");
}
@Override
public void otherFunction() {
System.out.println("otherFunction() has been called");
}
@Override
public void refresh() {
System.out.println("refresh() has been called");
}
}
执行该技巧的代理。它过滤所需的方法并调用refresh()。
package CallBefore;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ExampleProxy implements InvocationHandler {
private ExampleInterface obj;
public static ExampleInterface newInstance(ExampleInterface obj) {
return (ExampleInterface) java.lang.reflect.Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(), new ExampleProxy(obj));
}
private ExampleProxy(ExampleInterface obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
Object result;
try {
if (m.getName().startsWith("function")) {
obj.refresh();
}
result = m.invoke(obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (Exception e) {
throw new RuntimeException("unexpected invocation exception: " + e.getMessage());
}
return result;
}
}
用法:
package CallBefore;
public class Main {
public static void main(String[] args) {
ExampleInterface proxy = ExampleProxy.newInstance(new Example());
proxy.function1();
proxy.function2();
proxy.otherFunction();
proxy.refresh();
}
}
输出:
refresh() has been called
function1() has been called
refresh() has been called
function2() has been called
otherFunction() has been called
refresh() has been called
答案 1 :(得分:2)
这可能无法解决您的确切问题,但如果您被允许考虑重新设计,至少可能是一个起点。下面是一个简单的实现,但有一些小的触摸,我相信你可以实现更优雅的解决方案。顺便说一句,这称为动态代理模式。
您需要的第一件事就是为您的班级提供接口。
public interface Interface {
void hello(String name);
void bye(String name);
}
public class Implementation implements Interface {
@Override
public void hello(String name) {
System.out.println("Hello " + name);
}
@Override
public void bye(String name) {
System.out.println("Bye " + name);
}
}
然后java.lang.reflect.Proxy
上课来帮忙。该类能够在运行时为给定接口创建实例。它还接受InvocationHandler
,它可以帮助您捕获方法调用,看起来像这样。
public class InvocationHandlerImpl implements InvocationHandler {
private final Object instance;
public InvocationHandlerImpl(Object instance) {
this.instance = instance;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
try {
System.out.println("Before");
result = method.invoke(instance, args);
System.out.println("After");
} catch (Exception e){
e.printStackTrace();
throw e;
} finally {
System.out.println("finally");
}
return result;
}
}
毕竟您的客户端代码看起来像这样。
Interface instance = new Implementation();
Interface proxy = (Interface)Proxy.newProxyInstance(
Interface.class.getClassLoader(),
new Class[] { Interface.class },
new InvocationHandlerImpl(instance));
proxy.hello("Mehmet");
proxy.bye("Mehmet");
此代码的输出为
Before
Hello Mehmet
After
finally
Before
Bye Mehmet
After
finally
答案 2 :(得分:1)
我会为每个字段定义getter并在getter中进行刷新。如果你想完全避免对私有字段的未刷新访问,请将它们放在超类中(与调用刷新的getter一起)。
根据您的项目结构,为定期刷新的所有数据引入单独的类也是明智的。它可以提供getter并避免任何人访问未刷新的字段。
答案 3 :(得分:1)
不在Java SE中,但如果您使用的是Java EE,则可以使用interceptors。
对于独立应用程序,您可以考虑使用字节码操作框架,如javassist。
答案 4 :(得分:0)
If (sourceString).Contains($"< div class={QUOTE}panel-base xbl{QUOTE} style={QUOTE}background-color: RGB(236, 255, 236);{QUOTE}><div class={QUOTE}marshmallowLogo{QUOTE} id={QUOTE}xboxLogo{QUOTE}>Xbox 360</div><center><span class={QUOTE}statusSpan{QUOTE} style={QUOTE}color green;{QUOTE}>Up</span></center>") Then
End If
可以使用String.Format
方法。访问$""
方法,而不是使用protected getter
字段。子类只会看到data
,并且每次都会更新数据。
getData
答案 5 :(得分:0)
最好编写另一个方法,该方法将受到保护(子类可访问),它将首先调用refresh方法,然后调用该函数。
这样,每次调用函数之前都会刷新数据(根据您的要求)。 例如:
protected void callFunction1(){
refresh();
function();
}
谢谢, 拉杰什
答案 6 :(得分:0)
在这种情况下你应该使用Decorator。装饰器是拦截器之类的好选择。示例:https://msdn.microsoft.com/en-us/library/dn178467(v=pandp.30).aspx