探索设计模式之----代理模式

代理模式是一种非常重要的设计模式,在Java语言中有着广泛的应用,包括Spring AOP的核心设计思想,都和代理模式有密切关系。

代理模式主要分两种:一种是静态代理,一种是动态代理。两种代理方式的实现有着本质的差异。

代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在

客户端和目标对象之间起到中介的作用。

代理模式一般涉及到的角色有:

抽象角色:声明真实对象和代理对象的共同接口。

代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实

对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。

一、静态代理

静态代理代理和被代理对象在代理之前是确定的。他们都实现相同的接口或者继承相同的抽象类。

/**
 * 抽象角色
 */
public abstract class Subject {
    abstract public void request();
}

/**
 * 真实角色:实现了Subject的request()方法
 */
public class RealSubject extends Subject {

    public RealSubject() {
    }

    public void request() {
        System.out.println("真实角色的请求方法RealSubject.request()被调用!");
    }
}

/**
 * 代理角色
 */
public class ProxySubject extends Subject {
    private RealSubject realSubject; // 以真实角色作为代理角色的属性

    public ProxySubject() {
    }

    // 该方法封装了真实对象的request方法
    public void request() {
        preRequest();               //代理前执行的操作
        if (realSubject == null) {
            realSubject = new RealSubject();
        }
        realSubject.request();     // 此处执行真实对象的request方法
        postRequest();              //代理后执行的操作
    }

    private void preRequest() {
        // something you want to do before requesting
        System.out.println("代理前执行的操作ProxySubject.preRequest()!");
    }

    private void postRequest() {
        // something you want to do after requesting
        System.out.println("代理后执行的操作ProxySubject.postRequest()!");
    }
}

/**
 * 客户端调用
 */
public class Client {
    public static void main(String[] args) {
        Subject sub = new ProxySubject();
        sub.request();
    }
}

运行客户端调用,结果如下:

代理前执行的操作ProxySubject.preRequest()!

真实角色的请求方法RealSubject.request()被调用!

代理后执行的操作ProxySubject.postRequest()!

代码内容很简单,由以上代码可以看出,客户实际需要调用的是RealSubject类的request()方法,现在用ProxySubject来代理 RealSubject类,同样达到目的,同时还封装了其他方法(preRequest(),postRequest()),可以处理一些其他问题。

另外,如果要按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际使用时,一个真实角色必须对应一个 代理角色,如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。请看下面的动态代理模式。

二、动态代理

Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:

(1)Interface InvocationHandler:该接口中仅定义了一个方法

public object invoke(Object obj,Method method, Object[] args)

在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。 这个抽象方法在代理类中动态实现。

(2)Proxy:该类即为动态代理类,作用类似于上例中的ProxySubject,其中主要包含以下内容

动态代理类

protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。

static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)

动态代理类

所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作

在使用动态代理类时,我们必须实现InvocationHandler接口。

下面看个例子,在静态代理的基础上改为动态代理:

/**
 * 抽象角色
 */
public interface Subject {
    public void request();
}

/**
 * 具体角色:被代理类
 */
public class RealSubject implements Subject {
    public RealSubject() {
    }

    public void request() {
        System.out.println("具体角色的请求方法RealSubject.request()被调用!");
    }
}

/**
 * 代理处理器
 *
 * 该代理类的内部属性为Object类,实际使用时通过该类的构造函数DynamicSubject(Object obj)对其赋值;
 * 此外,在该类还实现了invoke方法,该方法中的 method.invoke(sub,args);
 * 其实就是调用被代理对象的将要被执行的方法,方法参数sub是实际的被代理对象,
 * args为执行被代理对象相应操作所需的参数。
 * 通过动态代理类,我们可以在调用之前或之后执行一些相关操作
 */

public class DynamicSubject implements InvocationHandler {
    private Object sub;       //被代理对象

    public DynamicSubject() {
    }

    /**
     * 构造方法,并初始化被代理对象
     * @param obj 是被代理的对象
     */
    public DynamicSubject(Object obj) {
        sub = obj;
    }

    /**
     *
     * @param proxy  指代理类
     * @param method 被代理的方法
     * @param args   被代理的方法所需要的参数数组
     * @return  在代理实例上处理方法调用并返回结果。
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理前执行的操作!");
        method.invoke(sub, args);
        System.out.println("代理后执行的操作!");
        return null;
    }
}

/**
 * 客户端
 */
public class Client {
    static public void main(String[] args) throws Throwable {

        RealSubject rs = new RealSubject();     // 在这里指定被代理类
        //通过被代理类对象声明一个代理类对象
        InvocationHandler dynamicSubject = new DynamicSubject(rs);
        Class<?> cls = rs.getClass();

        // 以下是一次性生成代理类实例:
        // 返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
        Subject subject = (Subject) Proxy.newProxyInstance(
                cls.getClassLoader(),           //定义代理类的类加载器
                cls.getInterfaces(),            //代理类要实现的接口列表
                dynamicSubject);                //指派方法调用的调用处理程序:InvocationHandler对象

        subject.request();      //调用代理处理器上的方法
    }
}

运行结果:

代理前执行的操作!

具体角色的请求方法RealSubject.request()被调用!

代理后执行的操作!

总结一下,动态代理实现的步骤

1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法

2.创建被代理的类以及接口。

3.通过Proxy的静态方法。

newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 创建一个代理类。

4.通过代理调用方法。

时间: 2024-07-31 09:03:20

探索设计模式之----代理模式的相关文章

Android设计模式之代理模式 Proxy

一.概述 代理模式也是平时比较常用的设计模式之一,代理模式其实就是提供了一个新的对象,实现了对真实对象的操作,或成为真实对象的替身.在日常生活中也是很常见的.例如A要租房,为了省麻烦A会去找中介,中介会替代A去筛选房子,A坐享中介筛选的结果,并且交房租也是交给中介,这就是一个典型的日常生活中代理模式的应用.平时打开网页,最先开到的一般都是文字,而图片等一些大的资源都会延迟加载,这里也是使用了代理模式. 代理模式的组成: Abstract Subject:抽象主题-声明真实主题和代理主题共同的接口

【设计模式】代理模式

代理模式在所需对象和用户代码之间增加了一层对象,这个对象被称为代理.用户代码只需要直接操作代理对象即可.著名的代理模式的例子就是引用计数指针对象,它使得我们对真实对象的操作都需要经过引用计数指针对象.下面是用C++写的一个运用了代理模式的例子. #include <iostream> #include <string> using namespace std; // 作为接口的抽象基类 class Subject { public: virtual void DoAction()

设计模式之代理模式(Proxy)摘录

23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象.创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些具体的类的信息封装起来.第二,它们隐藏了这些类的实例是如何被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以

【大话设计模式】——代理模式

对于面向对象的程序设计语言而言,继承和多态是两个最基本的概念.Hibernate 的继承映射可以理解持久化类之间的继承关系.例如:人和学生之间的关系.学生继承了人,可以认为学生是一个特殊的人,如果对人进行查询,学生的实例也将被得到. Hibernate支持三种继承映射策略: 使用 subclass 进行映射:将域模型中的每一个实体对象映射到一个独立的表中,也就是说不用在关系数据模型中考虑域模型中的继承关系和多态. 使用 joined-subclass 进行映射: 对于继承关系中的子类使用同一个表

设计模式之代理模式 c++实现以及详解

proxy模式 <1> 作用: 为其他对象提供一种代理以控制对这个对象的访问. <2> 代理模式的应用场景: 如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法: 1.修改原有的方法来适应.这样违反了"对扩展开放,对修改关闭"的原则. 2.就是采用一个代理类调用原有的方法,且对产生的结果进行控制.这种方法就是代理模式. 使用代理模式,可以将功能划分的更加清晰,有助于后期维护! <3> 结构图 代理类,含有一个指向RealSubject

JAVA设计模式之代理模式

学编程吧JAVA设计模式之代理模式发布了,欢迎通过xuebiancheng8.com来访问 一.概述 给某一个对象提供一个代理,并由代理对象来完成对原对象的访问.代理模式是一种对象结构型模式. 二.适用场景 当无法直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口. 三.UML类图 四.参与者 1.接口类:Subject 它声明了真实访问者和代理访问者的共同接口,客户端通常需要针对接口角色进行编程. 2.代理类

JAVA设计模式(3)----代理模式

1.  什么是代理模式?Proxy Pattern 代理模式定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 通俗的讲,代理模式就是我很忙没空理你,你要想找我可以先找我的代理人,代理人和被代理人继承同一个接口.代理人虽然不能干活,但是被代理的人可以干活. 这个例子中有水浒传中的这么几个人:名垂青史的潘金莲,王婆,西门大官人.西门庆想要找潘金莲,需要找王婆做代理.首先定义一个接口:Kin

设计模式之代理模式20170724

结构型设计模式之代理模式: 一.含义 代理模式也叫做委托模式,其定义如下: 为其他对象提供一种代理以控制对这个对象的访问. 二.代码说明 1.主要有两个角色 1)具体主题角色 也叫做委托角色.被代理角色.它是业务逻辑的具体执行者. 2)代理主题角色 也叫做委托类.代理类.它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作. 一个代理类可以代理多个被委托者或被代理者. 2.在用C实现过程中也是参考这种思想,以游戏代理场

设计模式 11 —— 代理模式

设计模式目录: 设计模式 1 ——观察者模式 设计模式 2 —— 装饰者模式 设计模式 3 —— 迭代器和组合模式(迭代器) 设计模式 4 —— 迭代器和组合模式(组合) 设计模式 5 —— 工厂模式 设计模式 6 —— 单件模式 设计模式 7 —— 命令模式 设计模式 8 —— 适配器和外观模式 设计模式 9 —— 模板方法模式 设计模式 10 —— 状态模式 设计模式 11 —— 代理模式 概述 一 代理模式基本概念 二 参考 一 代理模式基本概念 代理模式为另一个对象提供一个替身或占位符以