Java面试知识点(七十九)设计模式之代理模式(上)

154 篇文章 5 订阅
150 篇文章 6 订阅

一、定义

1.什么是代理模式

  • 代理(Proxy)模式是结构型的设计模式之一,它可以为其他对象提供一种代理(Proxy)以控制对这个对象的访问

  • 所谓代理,是指具有与被代理的对象具有相同的接口的类,客户端必须通过代理与被代理的目标类交互,而代理一般在交互的过程中(交互前后),进行某些特别的处理。

  • 通俗的来讲代理模式就是我们生活中常见的中介或者代理人,比如我们想要买房子或者买车,自己弄太麻烦,就可以找一个中介,帮我全部打理好;或者父母是孩子的代理人,有些事情是需要父母出面代理孩子完成。

2.为什么要用代理模式

  • 中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口
  • 开闭原则,增加功能:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。

3.参与角色

  • 抽象主题(Subject):真实主题与代理主题的共同接口。

  • 真实主题(RealSubject):实现抽象主题,定义真实主题所要实现的业务逻辑,供代理主题调用。

  • 代理主题(Proxy):实现抽象主题,是真实主题的代理。通过真实主题的业务逻辑方法来实现抽象方法,并可以附加自己的操作。

4.应用场景

  • 需要控制对目标对象的访问。

  • 需要对目标对象进行方法增强。如:添加日志记录,计算耗时等。

  • 需要延迟加载目标对象。


代理又分为静态代理和动态代理,我们以孩子交学费为例

二、静态代理

【抽象主题】

package designpatterns.proxy;

public interface IChild {
    void money();
    void school();
}

【真实主题】

package designpatterns.proxy;

public class Child implements IChild {
    @Override
    public void money() {
        System.out.println("娃娃去交钱");
    }

    @Override
    public void school() {
        System.out.println("娃娃去上学");
    }
}

【代理主题】

package designpatterns.proxy;

public class Parent implements IChild {

    private IChild child;

    public Parent(IChild child) {
        this.child = child;
    }

    @Override
    public void money() {
        System.out.println("父母去交钱");
    }

    @Override
    public void school() {
        child.school();
    }
}

【测试环境】

package designpatterns.proxy;

public class Demo {
    public static void main(String[] args) {
        IChild child = new Child();
        IChild proxy = new Parent(child);
        proxy.money();
        proxy.school();
    }
}

【运行结果】

父母去交钱
娃娃去上学

注意:在代理主题中引入的对象是抽象主题类而不是真实主题类


三、动态代理

动态代理的实现手段:JDK 自带的 Proxy 类、CGlib、Javaassist 等。

1.Proxy类实现动态代理

抽象主题和真实主题不变

【代理处理类】

package designpatterns.proxy;

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

public class ChildHandle implements InvocationHandler {

    private IChild child;

    public ChildHandle(IChild child) {
        this.child = child;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object obj = null;

        /**
         *  method.getName()是获得抽象主题的方法,通过多态定位到具体实现类
         *  当在生产环境进行调用的时候,根据不同的方法名执行不同的方法
         * */
        if ("school".equals(method.getName())) {
            obj = method.invoke(child,args);
        }

        if ("money".equals(method.getName())) {
            System.out.println("父母交学费");
        }

        return obj;
    }
}

【测试环境】

package designpatterns.proxy;

import java.lang.reflect.Proxy;

public class Dynamic {
    public static void main(String[] args) {
        IChild child = new Child();
        ChildHandle handler = new ChildHandle(child);

        // 代理模式
        IChild proxy = (IChild) Proxy.newProxyInstance(
                child.getClass().getClassLoader(),
                child.getClass().getInterfaces(),
                handler);
		// 这里的方法调用,对用的就是ChildHandle类中invoke方法中method.getName()所得到得内容
        proxy.money();
        proxy.school();
    }
}

【运行结果】

父母交学费
娃娃去上学

注意 Proxy.newProxyInstance() 方 法接受三个参数

  • ClassLoader loader: 指定当前目标对象使用的类加载器,获取加载器的方法是固定的
  • Class<?>[] interfaces: 指定目标对 象实现的接口的类型,使用泛型方式确认类型
  • InvocationHandler:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法

关于proxy动态代理的个人理解:proxy动态代理的InvocationHandler 接口就类似多线程的runnable接口,而invoke方法就相当于run方法,多线程的逻辑写在run方法中,而代理模式中需要实现的逻辑是写在invoke方法中,而通过java反射,又可以在运行的时候获取抽象主题和真实主题的方法,然后重新实现代理逻辑。实现的方式跟多线程的start方式略有不同,代理是通过不同的方法调用来实现的,代理的类的方式通过invocationHandle的invoke,逻辑已经更改。

总结:虽然相对于静态代理,动态代理大大减少了我们的开发任务,同时减少了对业务接口的依赖,降低了耦合度。但是还是有一点点小小的遗憾之处,那就是Java 的继承机制注定了这些动态代理类们无法实现对 class 的动态代理,仅支持 interface 代理。


  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值