代理模式 (ProxyPattern)

Posted 顧棟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代理模式 (ProxyPattern)相关的知识,希望对你有一定的参考价值。

代理模式 (ProxyPattern)

代理模式的定义

为其他对象提供一种代理以控制对这个对象的访问。

代理模式的优点

  • 真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件事务,附带的结果就是编程简洁清晰。
  • 具体主题角色是随时都会发生变化的,只要它实现了接口,甭管它如何变化,都逃不脱如来佛的手掌(接口),那我们的代理类完全就可以在不做任何修改的情况下使用。
  • 这在我们以上的讲解中还没有体现出来,不过在我们以下的动态代理章节中你就会看到代理的智能化有兴趣的读者也可以看看Struts是如何把表单元素映射到对象上的。
  • 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
  • 代理对象可以扩展目标对象的功能;
  • 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度,增加了程序的可扩展性

代理模式的缺点

  • 代理模式会造成系统设计中类的数量增加
  • 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
  • 增加了系统的复杂度;

代理模式的结构

代理模式的主要角色如下。

  1. 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
  2. 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
  3. 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

代理模式的实现

普通代理

客户端只能访问代理角色,而不能访问真实角色。

public interface IGamePlayer {

    /**
     * 登录游戏
     */
    public void login(String user, String password);

    /**
     * 杀怪,网络游戏的主要特色
     */
    public void killBoss();

    /**
     * 升级
     */
    public void upgrade();
}
public interface IProxy {
    /**
     * 代理服务费
     */
    public void count();
}
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 killBoss() {
        System.out.println(this.name + "在打怪!");
    }

    /**
     * 升级
     */
    @Override
    public void upgrade() {
        System.out.println(this.name + "又升了一级!");
    }
}
public class GamePlayerProxy implements IGamePlayer, IProxy {

    private IGamePlayer gamePlayer = null;

    /**
     * 通过构造函数传递要对谁进行代练
     */
    public GamePlayerProxy(String name) {
        try {
            gamePlayer = new GamePlayer(this, name);
        } catch (Exception e) {
            // TODO 异常处理
        }
    }

    /**
     * 登录游戏
     */
    @Override
    public void login(String user, String password) {
        this.gamePlayer.login(user, password);
    }

    /**
     * 杀怪,网络游戏的主要特色
     */
    @Override
    public void killBoss() {
        this.gamePlayer.killBoss();
    }

    /**
     * 升级
     */
    @Override
    public void upgrade() {
        this.gamePlayer.upgrade();
        this.count();
    }

    /**
     * 代理服务费
     */
    @Override
    public void count() {
        System.out.println("升级总费用是:150元");
    }
}
public class Client {
    public static void main(String[] args) {
        //然后再定义一个代练者
        IGamePlayer proxy = new GamePlayerProxy("张三");
        //开始打游戏,记下时间戳
        System.out.println("开始");

        proxy.login("zhangSan", "password");
        //开始杀怪
        proxy.killBoss();
        //升级
        proxy.upgrade();
        //记录结束游戏时间
        System.out.println("结束");
    }
}

强制代理

必须通过真实角色查找到代理角色,否则你不能访问。

public interface IGamePlayer {
    /**
     * 登录游戏
     */
    public void login(String user, String password);

    /**
     * 杀怪,网络游戏的主要特色
     */
    public void killBoss();

    /**
     * 升级
     */
    public void upgrade();

    /**
     * 每个人都可以找一下自己的代理
     *
     * @return
     */
    public IGamePlayer getProxy();
}
public class GamePlayer implements IGamePlayer {

    private String name = "";

    /**
     * 我的代理是谁
     */
    private IGamePlayer proxy = null;

    public GamePlayer(String name) {
        this.name = name;
    }

    /**
     * 登录游戏
     */
    @Override
    public void login(String user, String password) {
        if (this.isProxy()) {
            System.out.println("登录名为" + user + "的用户" + this.name + "登录成功!");
        } else {
            this.mustProxy();
        }
    }

    /**
     * 杀怪,网络游戏的主要特色
     */
    @Override
    public void killBoss() {
        if (this.isProxy()) {
            System.out.println(this.name + "在打怪!");
        } else {
            this.mustProxy();
        }
    }

    /**
     * 升级
     */
    @Override
    public void upgrade() {
        if (this.isProxy()) {
            System.out.println(this.name + "又升了一级!");
        } else {
            this.mustProxy();
        }

    }

    public void mustProxy() {
        System.out.println("请使用指定的代理访问");
    }

    /**
     * 每个人都可以找一下自己的代理
     *
     * @return
     */
    @Override
    public IGamePlayer getProxy() {
        this.proxy = new GamePlayerProxy(this);
        return this.proxy;
    }

    /**
     * 校验是否是代理访问
     */
    private boolean isProxy() {
        return this.proxy != null;
    }
}
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 killBoss() {
        this.gamePlayer.killBoss();
    }

    /**
     * 升级
     */
    @Override
    public void upgrade() {
        this.gamePlayer.upgrade();
    }

    /**
     * 每个人都可以找一下自己的代理
     */
    @Override
    public IGamePlayer getProxy() {
        return this;
    }
}
public class Client {
    public static void main(String[] args) {
        //定义一个游戏的角色
        IGamePlayer player = new GamePlayer("张三");
        IGamePlayer playerProxy = player.getProxy();
        //开始打游戏,记下时间戳
        System.out.println("开始");
        playerProxy.login("zhangSan", "password");
        //开始杀怪
        playerProxy.killBoss();
        //升级
        playerProxy.upgrade();
        //记录结束游戏时间
        System.out.println("结束");

    }
}

动态代理

动态代理是在实现阶段不用关心代理谁,而在运行阶段才指定代理哪一个对象。

public interface IGamePlayer {

    /**
     * 登录游戏
     */
    public void login(String user, String password);

    /**
     * 杀怪,网络游戏的主要特色
     */
    public void killBoss();

    /**
     * 升级
     */
    public void upgrade();
}
public class GamePlayIH implements InvocationHandler {
    /**
     * 被代理者
     */
    Class cls = null;
    /**
     * 被代理的实例
     */
    Object obj = null;

    /**
     * 我要代理谁
     *
     * @param obj
     */
    public GamePlayIH(Object obj) {
        this.obj = obj;
    }

    /**
     * 调用被代理的方法
     *
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object result = method.invoke(this.obj, args);
        if (method.getName().equalsIgnoreCase("login")) {
            System.out.println("有人在用我的账号登录!");
        }
        return result;
    }
}
public class GamePlayer implements IGamePlayer {
    private String name = "";

    public GamePlayer(String name) {
        this.name = name;
    }

    /**
     * 登录游戏
     */
    @Override
    public void login(String user, String password) {
        System.out.println("登录名为" + user + "的用户" + this.name + "登录成功!");
    }

    /**
     * 杀怪,网络游戏的主要特色
     */
    @Override
    public void killBoss() {
        System.out.println(this.name + "在打怪!");
    }

    /**
     * 升级
     */
    @Override
    public void upgrade() {
        System.out.println(this.name + "又升了一级!");
    }
    
}
public class Client {
    public static void main(String[] args) throws Exception {
        //定义一个痴迷的玩家
        IGamePlayer player = new GamePlayer("张三");
        //定义一个handler
        InvocationHandler handler = new GamePlayIH(player);
        //开始打游戏,记下时间戳
        System.out.println("开始");
        //获得类的class loader
        ClassLoader cl = player.getClass().getClassLoader();
        //动态产生一个代理者
        IGamePlayer proxy = (IGamePlayer) Proxy.newProxyInstance(cl, new Class[]{IGamePlayer.class}, handler);
        proxy.login("zhangSan", "password");
        //开始杀怪
        proxy.killBoss();
        //升级
        proxy.upgrade();
        //记录结束游戏时间
        System.out.println("结束");
    }
}

AOP

public interface Subject {
    /**
     * 业务操作
     */
    public void doSomething(String str);
}
public class RealSubject implements Subject {
    /**
     * 业务操作
     */
    @Override
    public void doSomething(String str) {
        System.out.println("do something!---->" + str);
    }
}
public interface IAdvice {
    /**
     * 通知只有一个方法,执行即可
     */
    public void exec();
}
public class BeforeAdvice implements IAdvice {
    @Override
    public void exec() {
        System.out.println("我是前置通知,我被执行了!");
    }
}
public class MyInvocationHandler implements InvocationHandler {
    /**
     * 被代理的对象
     */
    private Object target = null;

    /**
     * 通过构造函数传递一个对象
     */
    public MyInvocationHandler(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 {
    @SuppressWarnings("unchecked")
    public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) {
        //寻找JoinPoint连接点,AOP框架使用元数据定义
        if (true) {
            //执行一个前置通知
            (new BeforeAdvice()).exec();
        }
        //执行目标,并返回结果
        return (T) Proxy.newProxyInstance(loader, interfaces, h);
    }
}
public class SubjectDynamicProxy extends DynamicProxy {
    public static <T> T newProxyInstance(Subject subject) {
        //获得ClassLoader
        ClassLoader loader = subject.getClass().getClassLoader();
        //获得接口数组
        Class<?>[] classes = subject.getClass().getInterfaces();
        //获得handler
        InvocationHandler handler = new MyInvocationHandler(subject);
        return newProxyInstance(loader, classes, handler);
    }
}
public class Client {
    public 以上是关于代理模式 (ProxyPattern)的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之:代理模式ProxyPattern的实现

ProxyPattern代理模式

设计模式 - 学习笔记 - 代理模式ProxyPattern

设计模式 - 学习笔记 - 代理模式ProxyPattern

代理模式

大话涉及模式Python实现-代理模式