码迷,mamicode.com
首页 > 其他好文 > 详细

代理模式

时间:2017-11-09 11:30:34      阅读:225      评论:0      收藏:0      [点我收藏+]

标签:blog   for   建立   ide   ssl   int   null   ring   不能   

什么是代理模式

  对其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

代理模式的组成

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

  代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他操作,相当于对真实对象进行封装

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

代理模式使用场景

  1. 当我们想要隐藏某个类时,可以为其提供代理类
  2. 当一个类需要对不同的调用者提供提供不同的调用权限是,可以使用代理类来实现(代理类不一定只有一个,我们可以建立多个代理类来实现,也可以在一个代理类中进行权限判断来进行不同权限的功能调用)
  3. 当我们要扩展某个类的某个功能时,可以使用代理模式,在代理类中进行简单扩展(只针对简单扩展,可在引用委托类的语句之前与之后进行)

代理模式的分类

  静态代理、动态代理、Cglib代理

1、静态代理:

  静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。

  类图:

  技术分享

 

 

  看一个例子来了解静态代理。

  步骤一、创建一个抽象角色 Subject.java

package org.burning.sport.design.pattern.proxypattern.notdynamic;
/**
 *  @ProjectName: base-project 
 */
public abstract class Subject {
    public abstract void request();
}

 

  步骤二、创建一个真实角色 RealSubject.java

package org.burning.sport.design.pattern.proxypattern.notdynamic;
/**
 *  @ProjectName: base-project 
 */
public class RealSubject extends Subject {
    @Override
    public void request() {
        System.out.println("from real subject...");
    }
}

 

  步骤三、创建一个代理角色 ProxySubject.java

package org.burning.sport.design.pattern.proxypattern.notdynamic;

/**
 *  @ProjectName: base-project 
 */
public class ProxySubject extends Subject {

    private RealSubject realSubject; //代理角色内部引用了真实角色
    @Override
    public void request() {
        this.preRequest();

        if(null == realSubject) {
            realSubject = new RealSubject();
        }

        realSubject.request(); //真实角色完成事情

        this.postRequest();
    }

    private void preRequest() {
        System.out.println("pre request...");
    }

    private void postRequest() {
        System.out.println ("post request...");
    }

}

   步骤四、测试

package org.burning.sport.design.pattern.proxypattern.notdynamic;

/**
 *  @ProjectName: base-project 
 */
public class StaticDynamicMain {
    public static void main(String[] args) {
        Subject subject = new ProxySubject();
        subject.request();
    }
}

 

输出:

pre request...
from real subject...
post request...

总结:

  1、可以做到在不修改目标对象的功能前提下,对目标功能扩展

  2、缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护,如何解决静态代理中的缺点呢?答案是可以使用动态代理方式。

2、动态代理:

  动态代理的特点:

  1、代理对象,不需要实现接口

  2、代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)

  3、动态代理也叫做:JDK代理,接口代理

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

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

    - public object invoke(Object obj, Method method, Object[] args) 在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。

  2、Proxy: 该类纪委动态代理类,作用相当于静态代理中的ProxySubject

  动态代理的例子:

  步骤一、创建一个抽象角色

package org.burning.sport.design.pattern.proxypattern.dynamic;
/**
 *  @ProjectName: base-project 
 */
public interface SubjectInterface {
    public void request();
}

  步骤二、创建一个实体角色

package org.burning.sport.design.pattern.proxypattern.dynamic;
/**
 *  @ProjectName: base-project 
 */
public class RealSubject implements SubjectInterface {
    @Override
    public void request() {
        System.out.println("From real subject");
    }
}

  步骤三、实现InvocationHandler开始动态代理

package org.burning.sport.design.pattern.proxypattern.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 *  @ProjectName: base-project 
 */
public class DynamicSubject implements InvocationHandler {
    private Object sub;

    public DynamicSubject(Object obj) {
        this.sub = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before calling..." + method);
        method.invoke(sub, args);
        System.out.println("after calling..." + method);
        return null;
    }
}

  步骤四、写客户端测试

package org.burning.sport.design.pattern.proxypattern.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 *  @ProjectName: base-project 
 *  @Description: 动态代理
 */
public class DynamicProxyMain {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        InvocationHandler handler = new DynamicSubject(realSubject);
        Class<?> classType = handler.getClass();
        SubjectInterface subjectInterface = (SubjectInterface)Proxy.newProxyInstance(classType.getClassLoader(),
                realSubject.getClass().getInterfaces(), handler);

        subjectInterface.request();

        System.out.println(subjectInterface.getClass());
    }
}

输出:

before calling...public abstract void org.burning.sport.design.pattern.proxypattern.dynamic.SubjectInterface.request()
From real subject
after calling...public abstract void org.burning.sport.design.pattern.proxypattern.dynamic.SubjectInterface.request()
class com.sun.proxy.$Proxy0

 3.cglib代理

  上面的静态代理和动态代理模式都是要求目标对象是实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理。Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。代理的类不能是final,否则报错;目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法

  步骤一、创建目标对象

package org.burning.sport.design.pattern.proxypattern.cglib;

public class Target {
    public void save(String data) {
        System.out.println("----已经保存数据:" + data + "----");
    }
}

 

  步骤二、创建cglib代理工厂: ProxyFactory

package org.burning.sport.design.pattern.proxypattern.cglib;


import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class ProxyFactory implements MethodInterceptor {
    //维护目标对象
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    //给目标对象创建一个代理对象
    public Object getProxyInstance() {
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("开始事务.....");
        //执行目标对象的方法
        Object returnValue = method.invoke(target, objects);
        return returnValue;
    }
}

  步骤三、测试

package org.burning.sport.design.pattern.proxypattern.cglib;

public class ClientMain {
    public static void main(String[] args) {
        //目标对象
        Target target = new Target();
        //代理对象
        Target proxy = (Target) new ProxyFactory(target).getProxyInstance();
        //执行代理对象的方法
        proxy.save("lala");
    }
}

 输出:

开始事务.....
----已经保存数据:lala----

 

 

https://gitee.com/play-happy/base-project

参考:

[1] 博客,http://www.cnblogs.com/cenyu/p/6289209.html

 [2] 博客,http://blog.csdn.net/zghwaicsdn/article/details/50957474

代理模式

标签:blog   for   建立   ide   ssl   int   null   ring   不能   

原文地址:http://www.cnblogs.com/happyflyingpig/p/7800822.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!