代理模式的运用(续)
动态代理的核心是InvocationHandler接口,要使用动态代理就必须实现该接口。这个接口的委派任务是在invoke(Object proxy, Method m, Object[] args)方法里面实现的:
//在调用核心功能之前作一些动作……//调用核心功能m.invoke(obj, args);//在调用核心功能以后做一些动作……??? 我们可以看到动态代理其实用的是反射机制来调用核心功能的:m.invoke(obj, args);正是这种反射机制的使用使得我们调用核心功能更加灵活,而不用依赖于某一个具体的接口,而是依赖于Object对象。
??? 下面我们来具体看看动态代理或动态委派如何使用:
import java.lang.reflect.InvocationHandler;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Proxy;interface DoAction{public void ViewAction();public void AddAction();}class DoActionImpl implements DoAction {public void ViewAction(){System.out.println("查看信息!");}public void AddAction(){System.out.println("添加信息!");}}class ProxyAction implements InvocationHandler {private Object action;private User user = new User() ;public ProxyAction(Object action) {this.action = action;}public static Object getInstance(Object action) {return Proxy.newProxyInstance(action.getClass().getClassLoader(),action.getClass().getInterfaces(), new ProxyAction(action));}public Object invoke(Object proxy, Method m, Object[] args)throws Throwable {Object result = null;try {// 在委派之前作动作,如权限判断等if(user.getPermission().equals(m.getName())){}else{//没权限,不执行委派return result;}// 进行委派result = m.invoke(action, args);} catch (InvocationTargetException e) {throw e.getTargetException();} catch (Exception e) {throw new RuntimeException("unexpected invocation exception: "+ e.getMessage());} finally {// 在委派之后做动作}return result;}}//用户信息class User{private String permission = "ViewAction" ;public String getPermission() {return permission;}public void setPermission(String permission) {this.permission = permission;}}public class proxy {public static void main(String[] args) {DoAction action =(DoAction) ProxyAction.getInstance(new DoActionImpl());action.ViewAction();}}?这个代理类,首先是实现了InvocationHandler接口;然后在getInstance()方法里得到了代理类的实例;在invoke()方法里实现代理功能,也很简单。??? 下面我们来看客户端:Action action = (Action)ProxyAction.getInstance(new ViewAction());Action.doAction();
??? 我们可以看到代理类对接口的依赖也转移到了客户端上,这样,代理类不依赖于某个接口。对于同样的代理类ProxyAction,我们也可以有如下的客户端调用:Engine engine = (Engine)ProxyAction.getInstance(new EngineImpl());Engine.execute();
??? 只要engineImpl类实现了Engine接口,就可以像上面那样使用。
??? 现在我们可以看到,动态代理的确是拥有相当的灵活性。