→阿童沐

財富==支撐一個人生存多長時間的能力!

导航

<Java设计模式>代理模式-

代理模式的作用:

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

  在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用

  中介不仅可以帮助客户端完成客户想要完成的事情,还可以完成中介自己想要做的事情


代理模式中涉及到的角色:     六十五-18:00

  1、抽象角色:声明真实对象代理对象共同接口;(例如:中介和房主两者均可以完成租房子这件事情,因此两者含有共同的接口,接口中含有租房子这个方法)

  2、代理角色:代理角色对象内部含有对真是对象的引用,从而可以操作真实对象(聚合包容关系),同时代理对象提供与真是对象相同的接口以便在任何时候都能代替真实的对象。

          同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真是对象进行封装。(例如:中介)

  3、真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。(例如:房主)

实例讲解:  六十五-24:00


代理模式举例:

  1、抽象角色(可用抽象类或者接口来实现):

package cn.edu.bupt.proxy;

public interface Subject
{
    void request();
}

  2、真实角色(需要实现抽象角色):

package cn.edu.bupt.proxy;

public class RealSubject implements Subject
{
    @Override
    public void request()
    {
        System.out.println("From real subject");
    }
}

  3、代理角色(仍然需要实现抽象角色):

package cn.edu.bupt.proxy;

public class ProxySubject implements Subject
{
    private RealSubject realSubject = null;    //代理角色内部引用了真实角色
    
    private void preRequest()
    {
        System.out.println("pre request");
    }
    
    private void postRequest()
    {
        System.out.println("post request");
    }
    
    
    @Override
    public void request()
    {
        //代理在真实角色操作之前所附加的操作
        this.preRequest();
        
        //代理所完成的主要任务代码写于此
        if (null == this.realSubject)
        {
            this.realSubject = new RealSubject();
        }
        this.realSubject.request();        //代理通过真实角色完成相同的事情
        
        //在真是角色操作之后所附加的操作
        this.postRequest();
    }

}

  4、客户端对代理角色的直接调用,同时对真实对象的间接调用:

package cn.edu.bupt.proxy;

public class Client
{
    public static void main(String[] args)
    {
        Subject sub = new ProxySubject();
        sub.request();
    }
}

 

打印结果:

 

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

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


 

Java动态代理类:    六十五-30:00

一般主要涉及一下两个类,他们均位于java.lang.reflect包下:

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

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

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

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

    1> protected Proxy(InvocationHandler h)

      构造函数用于给内部h赋值。

    2> static Class getProxyClass(ClassLoader loader, Class[] interfaces)

      获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

    3> static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

      返回一个代理类的实例,返回后的代理类可以被当做代理类使用(可使用被代理类的在Subject接口中声明过的方法)。

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

也就是说,在使用动态代理类的时候,我们必须实现InvocationHandler接口,这里面提供我们实质性的代码。


 利用动态代理改写上例:

 抽象角色(此时一定要使用接口实现抽象角色)

package cn.edu.bupt.dynamicproxy;

public interface SubjectInterface
{
    void request(String word);
    void request2(String word);
}

 

 

真实角色(一定要实现抽象角色)

 

posted on 2012-02-14 15:50  阿童沐  阅读(177)  评论(0)    收藏  举报