代理模式是一个使用率非常高的模式,其定义是为其他对象提供一种代理以控制对这个对象的访问。代理模式也叫委托模式,是一项基本设计技巧。许多其他的模式,如状态模式、策略模式、访问者模式本质上都是在更特殊的场合采用了委托模式。
下面以一个游戏练级的例子分别讲解不同的代理类型:
普通代理:它的要求就是客户端只能访问代理角色,而不能访问真是角色。
public interface IGamePlayer {
public void login();
public void killBoss();
public void upgrade();
}
public class GamePlayer implements IGamePlayer {
private String name;
@Override
public void login() {
System.out.println("用户"+this.name+"登录了");
}
@Override
public void killBoss() {
System.out.println("用户"+this.name+"击杀了怪");
}
@Override
public void upgrade() {
System.out.println("用户"+this.name+"升级了");
}
public GamePlayer(IGamePlayer _gamePlayer, String _name) throws Exception{
if(_gamePlayer == null){
throw new Exception("不能创建真实角色");
}
this.name = _name;
}
}
public class GamePlayerProxy implements IGamePlayer {
private IGamePlayer gamePlayer;
@Override
public void login() {
this.gamePlayer.login();
}
@Override
public void killBoss() {
this.gamePlayer.killBoss();
}
@Override
public void upgrade() {
this.gamePlayer.upgrade();
}
public GamePlayerProxy(String _name) throws Exception{
gamePlayer = new GamePlayer(this, _name);
}
}
public class Client {
public static void main(String[] args) throws Exception {
IGamePlayer proxy = new GamePlayerProxy("测试人员");
proxy.login();
proxy.killBoss();
proxy.upgrade();
}
}
在该模式下,调用者只知道代理而不用知道真实的角色是谁,屏蔽了真实角色对高层模块的影响,真实的主题角色想怎么修改就怎么修改,对高层次的模块没有任何影响,只要你实现了接口所对应的方法,该模式非常适合对扩展性要求较高的场合。
此外,代理类除了实现主体接口之外,如果需要在目标对象方法的基础上作前置或后置处理,则可以再实现一个接口,如上面的例子,如果升一级了就加收5元钱,
代理类可以为真实角色预处理消息、过滤消息、消息转发、事后处理消息等功能,并且一个代理类,还可以代理多个真实角色,并且真实角色之间可以有耦合关系。
动态代理:是在实现阶段不用关心代理谁,而在运行阶段才制定代理哪一个对象。像现在流行的面相切面编程,也就是AOP,其核心就是采用动态代理机制。相对来说,自己写代理类的方式就是静态代理。
如图,动态代理实现代理的职责,业务逻辑Subject实现相关的逻辑功能,两者之间没有必然的相互耦合的关系。通知Advice从另一个切面切入,最终在高层模块也就是Client进行耦合,完成逻辑的封装任务。
public interface Subject {
public void doSomething(String str);
}
public class RealSubject implements Subject {
@Override
public void doSomething(String str) {
System.out.println("真实主题doSomething="+str);
}
}
public class MyInvocationHandle implements InvocationHandler {
//被代理的对象
private Object target = null;
public MyInvocationHandle(Object _obj) {
this.target = _obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//执行被代理的方法
return method.invoke(this.target, args);
}
}
public class DynamicProxy<T> {
public static <T> T newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler invocationHandler){
//寻找JoinPoint连接点,AOP框架使用元数据定义
if(true){
//执行前置通知
(new BeforeAdvice()).exec();
}
return (T) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
}
}
public interface IAdvice {
public void exec();
}
public class BeforeAdvice implements IAdvice {
@Override
public void exec() {
System.out.println("执行前置通知");
}
}
这里可能有读者要问,这样与静态代理有什么区别呢?都是需要实现一个代理类。其实是有区别的,注意看父类,动态代理的主要意图就是解决我们常说的“审计”问题,也就是横向切面编程,在不改变我们已有代码结构的情况下增强或控制对象的行为。
要实现动态代理的首要条件是:被代理类必须实现一个接口。