代理模式

代理模式

  • 代理模式的定义
  • 代理模式的应用
    • 优点
    • 使用场景
  • 代理模式的扩展
    • 普通代理
    • 强制代理
    • 代理是有个性的
    • 动态代理

代理模式的定义

代理模式(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");
    }
}

你可能感兴趣的:(学习笔记)