java

java,第1张

java

目录

引言

一、概述

二、代理模式介绍

(一)静态代理

(二)动态代理


引言

一、概述

在有些情况下,一个客户不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代理对象。例如,购买火车票不一定要去火车站买,可以通过 12306 网站或者去火车票代售点买。又如找女朋友、找保姆、找工作等都可以通过找中介完成。

在软件设计中,使用代理模式的例子也很多,例如,要访问的远程对象比较大(如视频或大图像等),其下载要花很多时间。还有因为安全原因需要屏蔽客户端直接访问真实对象,如某单位的内部数据库等。

代理模式的定义:

由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

代理模式的主要优点有:

  • 代理模式会造成系统设计中类的数量增加

  • 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;

  • 增加了系统的复杂度;

代理模式的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。

代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。


 

二、代理模式介绍 (一)静态代理

静态代理:由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口、被代理类、代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。

举个例子:

人到了适婚年龄,父母总是迫不及待希望早点抱孙子。而现在社会的人在各种压力之下,都选择晚婚晚育。于是着急的父母就开始到处为自己的子女相亲,比子女自己还着急。

这个相亲的过程,就是一种我们人人都有份的代理。来看代码实现:

定义一个接口(面向接口)

public interface Person {
    void findLove();
}

定义一个被代理类

public class Son implements Person {
    @Override
    public void findLove() {
        System.out.println("儿子要求:上海名媛");
    }
}

定义一个代理类

public class Father implements Person {
    private Son son;
    public Father(Son son) {
        this.son = son;
    }
    @Override
    public void findLove() {
        System.out.println("父母物色对象");
        son.findLove();
        System.out.println("双方同意交往,确立关系");
    }
}

 测试类

public class Test {
    public static void main(String[] args) {
        Father father=new Father(new Son());
        father.findLove();
    }
}

 这就是一个简单的静态代理模式。

(二)动态代理

代理类在程序运行时创建的代理方式被成为动态代理。

动态代理和静态对比基本思路是一致的,只不过动态代理功能更加强大,随着业务的扩展适应性更强。如果还以找对象为例,使用动态代理相当于是能够适应复杂的业务场景。

不仅仅只是父亲给儿子找对象,如果找对象这项业务发展成了一个产业,进而出现了媒婆、婚介所等这样的形式。那么,此时用静态代理成本就更大了,需要一个更加通用的解决方案,要满足任何单身人士找对象的需求。我们升级一下代码,先来看 JDK 实现方式:
 

public interface Person {
    void findLove();
}

public class Customer implements Person {
    @Override
    public void findLove() {
        System.out.println("上海名媛");
    }
}
public class JdkMeiPoInvocationHandler implements InvocationHandler {
    
    private Object target;

    public Object getInstance(Object target) {
        this.target = target;
        Class clazz = target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object obj = method.invoke(target, args);
        after();
        return obj;
    }

    private void before(){
        System.out.println("我是媒婆:我要给你找对象,现在已经拿到你的需求");
    }

    private void after(){
        System.out.println("如果合适的话,就准备办事");
    }

}

InvocationHandler接口

是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法。

特别注意:

这一段代理代码,通用!!!我们需要改动的只是其中的一个对象。只要是动态代理类,都可以用这样一个被规范成工具类的代码!

    private Object target;//target就是一个对象,可以改动,只可以改动它

    public Object getInstance(Object target) {
        this.target = target;//要改动时这里也要改动,只改动target
        Class clazz = target.getClass();//要改动时这里也要改动,只改动target
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
         //我们可以在代理类中定义额外的方法,然后在这里面调用
        Object obj = method.invoke(target, args);
     
        return obj;
    }

public class JdkTest {

    public static void main(String[] args) {
        Person person= (Person) new JdkMeiPoInvocationHandler().getInstance(new Customer());
        person.findLove();

    }
}

同样我们可以得到被代理者的儿子与媒婆代理之间,产生需求联系,然后得出被代理者的需求实现。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5685961.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存