为其它对象提供一种代理,来控制对这个对象的访问java
代理模式也叫做委托模式,它能够提供很是好的访问控制。代理模式包含三种角色:编程
- Subject抽象主题角色:能够是抽象类也能够接口,定义最普通的业务类型
- RealSubject具体主题角色:被代理类,被委托类,是业务逻辑的具体执行者
- Proxy代理主题角色:代理类,委托类。负责对真实角色的应用,把抽象角色内定义的方法限制委托给真实主题角色实现,并在真实主题角色处理完毕先后作预处理及善后处理工做
使用代理模式简单模拟用户打游戏过程,并将其系统化数组
IGamePlayer接口(抽象主题角色):游戏玩家接口,能够登陆,打怪,升级框架
public interface IGamePlayer { /** * 用户登陆 * @param username * @param password */ void login(String username, String password); /** * 玩家打怪 */ void killBoss(); /** * 玩家升级 */ void upgrade(); }
GamePlayer具体类(RealSubject具体主题角色):实现IGamePlayer接口并实现玩家操做ide
public class GamePlayer implements IGamePlayer { private String username; public GamePlayer(String username) { this.username = username; } public void login(String username, String password) { System.out.println("登陆帐号为" + username + "的用户" + this.username + "登陆成功!"); } public void killBoss() { System.out.println("用户" + this.username + "在打怪!"); } public void upgrade() { System.out.println("用户" + this.username + "升级!"); } }
Client场景类:模拟游戏玩家的游戏过程函数
public class Client { public static void main(String[] args) { // 定义一个游戏玩家 IGamePlayer gamePlayer = new GamePlayer("张三"); // 玩家登陆 gamePlayer.login("zhangsan", "123456"); // 玩家打怪 gamePlayer.killBoss(); // 玩家升级 gamePlayer.upgrade(); } }
常常打游戏,熬夜会得网瘾,身体顶不住。因而请游戏代练,将本身的游戏帐号交给代练,由代练代替玩家打怪升级。一个类能够实现多个接口,完成不一样任务的耦合。所以,代理类不单单能够实习主题接口,也能够实现其它接口完成不一样的任务。代理的目的是在真实角色对象方法的基础上作加强即对真实角色对象方法进行拦截和过滤。this
GamePlayerProxy类(Proxy代理主题角色):游戏代练,不能做弊,手动打怪升级。要求一样实现IGamePlayer接口代理
public interface IProxy { void before(); void after(); } public class GamePlayerProxy implements IGamePlayer, IProxy { private IGamePlayer gamePlayer; /** * 经过构造函数指定被代理的游戏玩家 * @param gamePlayer */ public GamePlayerProxy(IGamePlayer gamePlayer) { this.gamePlayer = gamePlayer; } public void login(String username, String password) { // 代练登陆 gamePlayer.login(username, password); } public void killBoss() { this.before(); // 代练打怪 gamePlayer.killBoss(); } public void upgrade() { // 代练升级 gamePlayer.upgrade(); this.after(); } public void before() { // 代练打游戏以前先吃饭补充 System.out.println("代练吃饭"); } public void after() { // 代练打完游戏以后睡觉休息 System.out.println("代练睡觉"); } }
Client场景类:模拟游戏代理玩家替代游戏玩家的游戏过程code
public class Client { public static void main(String[] args) { // 定义一个游戏玩家 IGamePlayer gamePlayer = new GamePlayer("张三"); // 定义一个代理玩家 IGamePlayer gamePlayerProxy = new GamePlayerProxy(gamePlayer); // 代理玩家登陆 gamePlayerProxy.login("zhangsan", "123456"); // 代理玩家打怪 gamePlayerProxy.killBoss(); // 代理玩家升级 gamePlayerProxy.upgrade(); } }
只须要关注真实角色的实际业务逻辑,不须要关注预处理及善后工做,减轻被代理类的负担。Spring AOP是一个典型的动态代理模式示例。对象
要求客户端只能访问代理角色,而不能访问真实角色(被代理角色)
以以上游戏过程为例,场景类不能new一个GamePlayer对象,被代理对象必须由GamePlayerProxy进行模拟场景
普通代理模式的GamePlayer具体类:经过构造函数限制建立真实角色,并传递游戏玩家姓名
public class GamePlayer implements IGamePlayer { private String username; public GamePlayer(IGamePlayer gamePlayer, String username) { if (gamePlayer == null) { System.out.println("不能建立真实角色"); } else { this.username = username; } } public void login(String username, String password) { System.out.println("登陆帐号为" + username + "的用户" + this.username + "登陆成功!"); } public void killBoss() { System.out.println("用户" + this.username + "在打怪!"); } public void upgrade() { System.out.println("用户" + this.username + "升级!"); } }
普通代理模式的GamePlayerProxy类
public class GamePlayerProxy implements IGamePlayer, IProxy { private IGamePlayer gamePlayer; public GamePlayerProxy(String username) { try { this.gamePlayer = new GamePlayer(this, username); } catch (Exception exception) { // TODO 异常处理 } } public void login(String username, String password) { // 代练登陆 gamePlayer.login(username, password); } public void killBoss() { this.before(); // 代练打怪 gamePlayer.killBoss(); } public void upgrade() { // 代练升级 gamePlayer.upgrade(); this.after(); } public void before() { // 代练打游戏以前先吃饭补充 System.out.println("代练吃饭"); } public void after() { // 代练打完游戏以后睡觉休息 System.out.println("代练睡觉"); } }
普通代理模式的Client场景类
public class Client { public static void main(String[] args) { // 定义一个代理玩家 IGamePlayer gamePlayerProxy = new GamePlayerProxy("张三"); // 代理玩家登陆 gamePlayerProxy.login("zhangsan", "123456"); // 代理玩家打怪 gamePlayerProxy.killBoss(); // 代理玩家升级 gamePlayerProxy.upgrade(); } }
普通代理模式调用者只须要知道被代理角色存在,并不须要知道被代理角色的是谁。屏蔽了真实角色的变动对高层模块的影响。
强制代理模式是调用者直接调用真实角色,不用关心代理是否存在,其代理的产生由真实角色决定。
强制代理模式必须经过真实角色找到代理角色,不容许直接访问真实角色。高层模块只须要找到真实角色指定的代理角色,就能够访问真实角色的全部实际逻辑,代理角色的管理由真实角色本身完成。
强制代理模式IGamePlayer接口
public interface IGamePlayer { /** * 用户登陆 * @param username * @param password */ void login(String username, String password); /** * 玩家打怪 */ void killBoss(); /** * 玩家升级 */ void upgrade(); /** * 每一个游戏玩家均可以找本身的代练 * @return */ IGamePlayer getProxy(); }
强制代理模式GamePlayer具体类
public class GamePlayer implements IGamePlayer { private String username; private IGamePlayer proxy; public GamePlayer(String username) { this.username = username; } public void login(String username, String password) { if (this.isProxy()) { System.out.println("登陆帐号为" + username + "的用户" + this.username + "登陆成功!"); } else { System.out.println("请指定游戏代练"); } } public void killBoss() { if (this.isProxy()) { System.out.println("用户" + this.username + "在打怪!"); } else { System.out.println("请指定游戏代练"); } } public void upgrade() { if (this.isProxy()) { System.out.println("用户" + this.username + "升级!"); } else { System.out.println("请指定游戏代练"); } } public IGamePlayer getProxy() { this.proxy = new GamePlayerProxy(this); return this.proxy; } /** * 检查是否制定游戏代练 * @return */ private boolean isProxy() { return this.proxy != null; } }
强制代理模式GamePlayerProxy类
public class GamePlayerProxy implements IGamePlayer, IProxy { private IGamePlayer gamePlayer; public GamePlayerProxy(IGamePlayer gamePlayer) { this.gamePlayer = gamePlayer; } public void login(String username, String password) { // 代练登陆 gamePlayer.login(username, password); } public void killBoss() { this.before(); // 代练打怪 gamePlayer.killBoss(); } public void upgrade() { // 代练升级 gamePlayer.upgrade(); this.after(); } /** * 暂时没有游戏代理,就是本身 * @return */ public IGamePlayer getProxy() { return this; } public void before() { // 代练打游戏以前先吃饭补充 System.out.println("代练吃饭"); } public void after() { // 代练打完游戏以后睡觉休息 System.out.println("代练睡觉"); } }
强制代理模式Client场景类
public class Client { public static void main(String[] args) { // 定义一个游戏玩家 IGamePlayer gamePlayer = new GamePlayer("张三"); // 指定游戏代练 IGamePlayer proxy = gamePlayer.getProxy(); // 代理玩家登陆 proxy.login("zhangsan", "123456"); // 代理玩家打怪 proxy.killBoss(); // 代理玩家升级 proxy.upgrade(); } }
动态代理模式是指在实现阶段不用关心代理谁,而在运行阶段指定被代理的对象。
JDK提供了动态代理的接口
InvocationHandler
,对被代理类的方法进行代理。
抽象主题
public interface Subject { void doSomething(); }
真实主题:被代理类
public class RealSubject implements Subject { @Override public void doSomething() { System.out.println("========> do something"); // TODO 业务操做 } }
通知接口及其实现
public interface IAdvice { /** * 执行通知 */ void exec(); } public class BeforeAdvice implements IAdvice { /** * 前置通知 */ @Override public void exec() { System.out.println("执行前置通知"); // TODO 执行前置通知业务逻辑 } } public class AfterAdvice implements IAdvice { /** * 后置通知 */ @Override public void exec() { System.out.println("执行后置通知"); // TODO 执行后置通知业务逻辑 } }
动态代理Handler类:全部动态代理的方法所有经过invoke
方法调用
public class MyInvocationHandler implements InvocationHandler { /** * 被代理对象 */ private Object object; /** * 我要代理的对象 * @param object */ public MyInvocationHandler(Object object) { this.object = object; } /** * 调用被代理的方法 * @param proxy * @param method * @param args * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 寻找JoinPoint链接点 if (true) { // 执行前置通知 new BeforeAdvice().exec(); } Object result = method.invoke(this.object, args); // 寻找JoinPoint链接点 if (true) { // 执行后置通知 new AfterAdvice().exec(); } return result; } }
动态代理类
public class DynamicProxy<T> { public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] clzss, InvocationHandler handler) { // 执行目标,获取主题代理 return (T) Proxy.newProxyInstance(loader, clzss, handler); } }
动态代理场景类
public class Client { public static void main(String[] args) { // 定义一个主题 Subject subject = new RealSubject(); // 定义一个Handler InvocationHandler handler = new MyInvocationHandler(subject); // 定义一个主题代理 Subject proxy = DynamicProxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), handler); // 代理行为 proxy.doSomething(); } }
subject.getClass().getInterfaces()
:查找到该类全部的接口,并实现全部的方法。方法的具体实现由new MyInvocationHandler(subject)
接管。动态代理类由
InvocationHandler
的实现类实现全部的方法,并由其invole
方法接管全部方法的实现。
扩展具体业务的动态代理类
public class SubjectDynamicProxy extends DynamicProxy<Subject> { public static Subject newProxyInstance(Subject subject) { // 获取ClassLoader ClassLoader classLoader = subject.getClass().getClassLoader(); // 获取接口数组 Class<?>[] clzss = subject.getClass().getInterfaces(); // 获取Handler InvocationHandler handler = new MyInvocationHandler(subject); return newProxyInstance(classLoader, clzss, handler); } }
场景类
public class Client { public static void main(String[] args) { // 定义一个主题 Subject subject = new RealSubject(); // 定义一个主题代理 Subject proxy = SubjectDynamicProxy.newProxyInstance(subject); // 代理行为 proxy.doSomething(); } }
动态代理的意图就是横切面编程,在不改变已有代码结构的状况下加强或控制对象的行为。动态代理是一个通用代理框架,实现自定义AOP框架,能够在此基础上进行扩展。