代理模式(Proxy Pattern)是一个使用率非常高的模式,其定义如下:
Provide a surrogate or placeholder for another object to control access to it.(为其他对象提供一种代理以控制对这个对象的访问。)
public interface Subject {
void request();
}
public class RealSubject implements Subject {
@Override
public void request() {
//业务逻辑处理
}
}
public class Proxy implements Subject {
private Subject subject = null;
public Proxy() {
this.subject = new Proxy();
}
public Proxy(Object... objects) {
}
@Override
public void request() {
this.before();
this.subject.request();
this.after();
}
private void before() {
}
private void after(){
}
}
…………………………(很多)
普通代理要求客户端只能访问代理角色,而不能访问真实角色
public interface IGamePlayer {
//登录游戏
public void login(String user, String password);
//杀怪
public void kissBoss();
//升级
public void upgrade();
}
public class GamePlayer implements IGamePlayer {
private String name = "";
public GamePlayer(IGamePlayer _gamePlayer, String _name) throws Exception {
if (_gamePlayer == null) {
throw new Exception("不能创建角色");
}else {
this.name = _name;
}
}
@Override
public void login(String user, String password) {
System.out.println("登录名为" + user + "的用户" + this.name + "登录成功");
}
@Override
public void kissBoss() {
System.out.println(this.name+"在打怪");
}
@Override
public void upgrade() {
System.out.println(this.name+"又升了一级!");
}
}
public class GamePlayerProxy implements IGamePlayer {
private IGamePlayer gamePlayer = null;
public GamePlayerProxy(String name) {
try {
gamePlayer = new GamePlayer(this, name);
} catch (Exception e) {
}
}
@Override
public void login(String user, String password) {
this.gamePlayer.login(user, password);
}
@Override
public void kissBoss() {
this.gamePlayer.kissBoss();
}
@Override
public void upgrade() {
this.gamePlayer.upgrade();
}
}
public class Client {
public static void main(String[] args) {
IGamePlayer proxy = new GamePlayerProxy("张三");
System.out.println("开始时间是:2018-09-26 10:00");
proxy.login("zhangsan", "password");
proxy.kissBoss();
proxy.upgrade();
System.out.println("结束时间是:2018-09-27 10:00");
}
}
注意 普通代理模式的约束问题,尽量通过团队内的编程规范类约束,因为每一个主题类是可被重用的和可维护的,使用技术约束的方式对系统维护是一种非常不利的因素。
强制代理却是要“强制”,你必须通过真实角色查找到代理角色,否则你不能访问。甭管你是通过代理类还是通过直接new一个主题角色类,都不能访问,只有通过真实角色指定的代理类才可以访问,也就是说由真实角色管理代理角色。
public interface IGamePlayer {
//登录游戏
public void login(String user, String password);
//杀怪
public void kissBoss();
//升级
public void upgrade();
//每个人都可以找一下自己的代理
public IGamePlayer getProxy();
}
public class GamePlayer implements IGamePlayer {
private String name = "";
//我的代理是谁
private IGamePlayer proxy = null;
public GamePlayer(String _name) throws Exception {
this.name = _name;
}
//找到自己的代理
@Override
public IGamePlayer getProxy() {
this.proxy = new GamePlayerProxy(this);
return this.proxy;
}
@Override
public void login(String user, String password) {
if (this.isProxy()) {
System.out.println("登录名为" + user + "的用户" + this.name + "登录成功");
} else {
System.out.println("请使用代理访问");
}
}
@Override
public void kissBoss() {
if (this.isProxy()) {
System.out.println(this.name + "在打怪");
}else{
System.out.println("请使用代理访问");
}
}
@Override
public void upgrade() {
if (this.isProxy()) {
System.out.println(this.name + "又升了一级!");
}else{
System.out.println("请使用代理访问");
}
}
//检查是否是代理访问
private boolean isProxy() {
if (this.proxy == null) {
return false;
} else {
return true;
}
}
}
public class GamePlayerProxy implements IGamePlayer {
private IGamePlayer gamePlayer = null;
public GamePlayerProxy(IGamePlayer _gamePlayer) {
this.gamePlayer = _gamePlayer;
}
@Override
public void login(String user, String password) {
this.gamePlayer.login(user, password);
}
@Override
public void kissBoss() {
this.gamePlayer.kissBoss();
}
@Override
public void upgrade() {
this.gamePlayer.upgrade();
}
//代理的代理暂时还没有,就是自己
@Override
public IGamePlayer getProxy() {
return this;
}
}
如果直接访问真实角色
public class Client {
public static void main(String[] args) {
IGamePlayer proxy = new GamePlayer("张三");
System.out.println("开始时间是:2018-09-26 10:00");
proxy.login("zhangsan", "password");
proxy.kissBoss();
proxy.upgrade();
System.out.println("结束时间是:2018-09-27 10:00");
}
}
运行结果就会如下所示
开始时间是:2018-09-26 10:00
请使用代理访问
请使用代理访问
请使用代理访问
结束时间是:2018-09-27 10:00
那么直接访问代理呢
public class Client {
public static void main(String[] args) {
IGamePlayer player = new GamePlayer("张三");
IGamePlayer proxy = new GamePlayerProxy(player);
System.out.println("开始时间是:2018-09-26 10:00");
proxy.login("zhangsan", "password");
proxy.kissBoss();
proxy.upgrade();
System.out.println("结束时间是:2018-09-27 10:00");
}
}
结果还是不行
开始时间是:2018-09-26 10:00
请使用代理访问
请使用代理访问
请使用代理访问
结束时间是:2018-09-27 10:00
这是因为这个代理是你new出来的,不是玩家指定的
public class Client {
public static void main(String[] args) {
IGamePlayer player = new GamePlayer("张三");
IGamePlayer proxy = player.getProxy();
System.out.println("开始时间是:2018-09-26 10:00");
proxy.login("zhangsan", "password");
proxy.kissBoss();
proxy.upgrade();
System.out.println("结束时间是:2018-09-27 10:00");
}
}
这次终于可以了。
一个类可以实现多个接口,完成不同任务的整合。也就是说代理类不仅仅可以实现主题接口,也可以实现其他接口完成不同的任务,而且代理的目的是在目标对象方法的基础上作增强,这种增强的本质通常就是对目标对象的方法进行拦截和过滤。
例如,增加一个IPorxy接口,作用是用来计算代理的费用。
public interface IPorxy {
//计算费用
public void count();
}
public class GamePlayerProxy implements IGamePlayer,IPorxy {
private IGamePlayer gamePlayer = null;
public GamePlayerProxy(IGamePlayer _gamePlayer) {
this.gamePlayer = _gamePlayer;
}
@Override
public void login(String user, String password) {
this.gamePlayer.login(user, password);
}
@Override
public void kissBoss() {
this.gamePlayer.kissBoss();
}
@Override
public void upgrade() {
this.gamePlayer.upgrade();
this.count();
}
//代理的代理暂时还没有,就是自己
@Override
public IGamePlayer getProxy() {
return this;
}
@Override
public void count() {
System.out.println("升级总费用为 150元");
}
}
代理类不仅仅是可以有自己的运算方法,通常的情况下代理的职责并不一定单一,它可以组合其他的真实角色,也可以实现自己的职责,比如计算费用。代理类可以为真实角色预处理消息、过滤消息、消息转发、事后处理消息等功能。当然一个代理类,可以代理多个真实角色,并且真实角色之间可以有耦合关系
动态代理是在实现阶段不用关心代理谁,而在运行阶段才指定代理哪一个对象。相对来说,自己写代理类的方式就是静态代理。本章节的核心部分就在动态代理上,现在有一个非常流行的名称叫做面向横切面编程,也就是AOP(Aspect Oriented Programming),其核心就是采用了动态代理机制
public class GamePlayIH implements InvocationHandler {
//被代理者
Class cls = null;
//被代理的实例
Object object = null;
//我要代理谁
public GamePlayIH(Object _obj) {
this.object = _obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(this.object, args);
if (method.getName().equalsIgnoreCase("login")) {
System.out.println("有人在用我的账号登录");
}
return result;
}
}
public class Client {
public static void main(String[] args) {
//定义一个痴迷的玩家
IGamePlayer player = new GamePlayer("张三");
//定义一个handler
InvocationHandler handler = new GamePlayIH(player);
//开始游戏
System.out.println("开始时间是:2018-09-26 10:00");
//获得类的class loader
ClassLoader c1 = player.getClass().getClassLoader();
//动态产生一个代理类
IGamePlayer proxy = (IGamePlayer) java.lang.reflect.Proxy.newProxyInstance(c1, new Class[]{IGamePlayer.class}, handler);
proxy.login("zhangsan", "password");
proxy.kissBoss();
proxy.upgrade();
System.out.println("结束时间是:2018-09-27 10:00");
}
}
我们看一下一个通用的动态代理代码
public interface Subject {
//业务操作
public void doSomething(String string);
}
public class RealSubject implements Subject {
@Override
public void doSomething(String string) {
System.out.println("do something --->" + string);
}
}
public class MyInvocationHandler implements InvocationHandler {
//被代理的对象
private Object target = null;
//通过构造函数传递一个对象
public MyInvocationHandler(Object target) {
this.target = target;
}
//代理方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//执行被代理的方法
return method.invoke(this.target,args);
}
}
public class DynamicProxy {
public static T newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler handler) {
//寻找JoinPoint连接点,AOP框架使用源数据定义
if(true){
//执行一个前置通知
(new BeforeAdvice()).exce();
}
return (T) Proxy.newProxyInstance(loader, interfaces, handler);
}
}
public interface IAdvice {
//通知只有一个方法,执行即可
public void exce();
}
public class BeforeAdvice implements IAdvice {
@Override
public void exce() {
System.out.println("前置通知执行了!");
}
}
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("Finish");
}
}
具体业务的动态代理
public class SubjectDynamicProxy extends DynamicProxy {
public static T newProxyInstance(Subject subject) {
ClassLoader classLoader = subject.getClass().getClassLoader();
Class>[] classes = subject.getClass().getClasses();
InvocationHandler handler = new MyInvocationHandler(subject);
return newProxyInstance(classLoader, classes, handler);
}
}
场景类更加简单
public class Client {
public static void main(String[] args) {
//定义一个主题
Subject subject = new RealSubject();
//定义一个Handler
InvocationHandler handler = new MyInvocationHandler(subject);
//定义主题的代理
Subject proxy = SubjectDynamicProxy.newProxyInstance(subject);
//代理的行为
proxy.doSomething("Finish");
}
}