设计模式之代理模式

来源:互联网 发布:网络利弊议论文 编辑:程序博客网 时间:2024/06/08 19:22

设计模式之代理模式

代理模式(Proxy) 为其他对象提供一个代理以控制对这个对象的访问。

代理模式实现又分静态代理和动态代理。

结构图

代码示例

静态代理


需求:某一天,我和朋友老王聚会时,看见他的朋友娇妹很漂亮,想追求她。但是我又不好意思直接和娇妹打招呼,就想通过老王进行介绍认识。


实现时目标类和代理类实现同一个接口即可。

首先,定义打招呼的接口

public interface IMeetGirl {String sayHello();String doMyGirlFriend();}

真实的请求对象我:

public class Me implements IMeetGirl {private BeautifulGirl girl;public Me(BeautifulGirl girl) {    this.girl = girl;}//定义真实的行为@Overridepublic String sayHello() {    return girl.getName()+" 你好,我是一个大帅比!";}@Overridepublic String doMyGirlFriend() {    return girl.getName()+" 做我女朋友吧!";}}

代理对象老王:

public class LaoWang implements IMeetGirl {private Me me;public LaoWang(BeautifulGirl girl) {    me = new Me(girl);}//在代理方法中调用真实的方法@Overridepublic String sayHello() {    return me.sayHello();}@Overridepublic String doMyGirlFriend() {    return me.doMyGirlFriend();}}

实体类

public class BeautifulGirl {private String name;public String getName() {    return name;}public void setName(String name) {    this.name = name;}}

public class test {public static void main(String[] args) {    BeautifulGirl girl = new BeautifulGirl();    girl.setName("娇妹");    LaoWang proxy = new LaoWang(girl);    System.out.println(proxy.sayHello());    System.out.println(proxy.doMyGirlFriend());    //娇妹 你好,我是一个大帅比!    //娇妹 做我女朋友吧!}}

这样,我们就通过老王成功的向娇妹打招呼了。


动态代理

在Spring中,AOP的实现离不开动态代理。而实现动态代理又可通过jdk或者cglib来实现。
jdk动态代理是由java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。

JDK动态代理

使用jdk动态代理需要基于接口编程

public interface HelloService {    void sayHello();}
public class HelloServiceImpl implements HelloService {    @Override    public void sayHello() {        System.out.println("Hello World!");    }}
/** * 使用此种方法动态代理对象需要基于接口编程 */public class HelloServiceJdkProxyFactory implements InvocationHandler {    //需要被代理的目标对象    private HelloService helloService;    public HelloServiceJdkProxyFactory(HelloService helloService) {        this.helloService = helloService;    }    //生成代理对象    public HelloService newProxyInstance() {        /**         * loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载         interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了         h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上         */        return (HelloService) Proxy.newProxyInstance(helloService.getClass().getClassLoader(),                helloService.getClass().getInterfaces(), this);    }    /**     * @param proxy  被代理的对象     * @param method  要调用的方法     * @param args   方法调用时所需要参数     * @return     * @throws Throwable     */    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("before hello world");        //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用        Object o = method.invoke(helloService, args);        System.out.println("after hello world");        return o;    }}
   @Test    public void jdkProxyTest() {        HelloService helloService = new HelloServiceImpl();        HelloServiceJdkProxyFactory proxy = new HelloServiceJdkProxyFactory(helloService);        proxy.newProxyInstance().sayHello();         }

测试结果:
before hello world
Hello World !
after hello world


CGlib动态代理

/** * Cglib动态代理,需要cglib包和asm依赖包 **/public class HelloServiceCglibProxyFactory implements MethodInterceptor {    public Object newProxyInstance(Class c) {        Enhancer enhancer = new Enhancer();        enhancer.setSuperclass(c);        enhancer.setCallback(this);        return enhancer.create();    }    @Override    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {        System.out.println("before hello world");        Object invoke = methodProxy.invokeSuper(o, objects);        System.out.println("after hello world");        return invoke;    }}
    @Test    public void cglibProxyTest() {        HelloServiceCglibProxyFactory proxy = new HelloServiceCglibProxyFactory();        HelloService helloService = (HelloService) proxy.newProxyInstance(HelloServiceImpl.class);        helloService.sayHello();    }

测试结果:
before hello world
Hello World !
after hello world


那么什么样的需求时候适合使用代理模式呢?

代理模式的使用场景:

  • 远程代理:也就是为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。

  • 虚拟代理:如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。通过它来存放需要很长时间的真实对象

  • 安全代理:控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。

  • 智能代理,指当调用真实的对象时,代理处理另外一些事。如计算真实对象的引用次数,当该对象没有引用时,可以自动释放它。


源码链接

本文地址:http://blog.csdn.net/ProdigalWang/article/details/75675756