Rui*_*uik 10 java design-patterns
有没有办法在调用类的任何其他函数之前始终执行函数?
我有一个类,我需要在调用任何函数之前总是刷新一些字段:
public class Example {
private int data;
public void function1(){
}
public void function2(){
}
//@BeforeOtherFunction
private void refresh(){
// refresh data
}
}
Run Code Online (Sandbox Code Playgroud)
因为它似乎是糟糕的编程,所以我不想refresh在每个其他函数的开头调用。由于其他人也将在此项目上工作,因此存在危险,即有人扩展了调用而没有调用refresh。
JUnit 有一个带有@Before-Annotation的解决方案。有没有办法在其他课程中做到这一点?
顺便说一句:如果你知道一种编程模式,它以另一种方式解决这个问题,而不是每次调用任何函数时都执行一个函数,那也会非常有帮助!
使用动态代理,您可以在其中过滤到应调用特定“before”方法之前的那些方法。在这些情况下,在发送呼叫之前调用它。请参阅如何拦截具有标准 Java 功能(无 AspectJ 等)的方法调用的答案?
更新:
需要为代理分离一个接口。refresh() 方法不能保持私有。它必须是公共的并且是接口的一部分(这在这里不好)才能从代理调用。
package CallBefore;
public interface ExampleInterface {
void function1();
void function2();
void otherFunction();
void refresh();
}
Run Code Online (Sandbox Code Playgroud)
您的课程实现了该接口:
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");
}
}
Run Code Online (Sandbox Code Playgroud)
可以解决问题的代理。它过滤所需的方法并调用 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;
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
refresh() has been called
function1() has been called
refresh() has been called
function2() has been called
otherFunction() has been called
refresh() has been called
Run Code Online (Sandbox Code Playgroud)
这可能无法解决您的确切问题,但如果您被允许考虑重新设计,那么至少可以作为一个起点。下面是一个简单的实现,但通过一些小修改,我相信您可以实现更优雅的解决方案。顺便说一句,这称为动态代理模式。
您需要的第一件事是您的类的接口。
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);
}
}
Run Code Online (Sandbox Code Playgroud)
然后java.lang.reflect.Proxy班级来帮忙。该类能够在运行时为给定接口创建实例。它还接受一个InvocationHandler可以帮助您捕获方法调用的 an ,看起来像这样。
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;
}
}
Run Code Online (Sandbox Code Playgroud)
毕竟您的客户端代码将如下所示。
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");
Run Code Online (Sandbox Code Playgroud)
该代码的输出是
Before
Hello Mehmet
After
finally
Before
Bye Mehmet
After
finally
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
14565 次 |
| 最近记录: |