一天攻克一个知识点 —— 设计模式之动态代理

一、设计模式之代理设计

代理设计是在Java开发中使用较多的一种设计模式,所谓的代理设计模式就是指一个代理主体操作真实主体,真实主体操作具体业务,代理主体负责给具体业务添砖加瓦。

就好比在生活中你有一套房子想要出租(你=真实主体),你找了房产中介(中介=代理主体)。真实主体负责提供房屋和收钱,代理主体负责带客户看房 、扣除手续费。租客只管租房子和付款,至于谁提供的房子并不关心。

我们发现,只需要定义一个租赁的接口,真实主体与代理主体都可以实现此接口,然后再由代理主体操作真实主体即可,上面的要求可以形成如下的代码:

1. 定义租赁接口

java 复制代码
package com.javabasic.proxy;

/**
 * 定义抽象接口
 */
public interface House {

    /**
     * 定义抽象方法 租赁
     */
    void rent();
}

2. 定义真实主体 - 房东

java 复制代码
package com.javabasic.proxy;

/**
 * 定义真实主体 房东
 */
public class Owner implements House{

    @Override
    public void rent() {
        System.out.println("房东提供房子,收取租金200元/月");
    }
}

3. 定义代理主体 - 中介

java 复制代码
package com.javabasic.proxy;

/**
 * 定义代理主体 中介
 */
public class Agent implements House{

    // 接收真实主体 房东
    private House house;

    /**
     * 通过构造方法,让中介与房东之间产生联系。
     * 根据Java动态绑定机制,House运行时的真实类型是房东类型,就可以获取到房东的出租行为。
     * @param house
     */
    public Agent(House house){
        this.house = house;
    }

    /**
     * 中介对房东出租业务进行增强
     */
    @Override
    public void rent() {
        rentBefore();
        house.rent(); // 房东 出租
        rentAfter();
    }

    private void rentBefore(){
        System.out.println("中介负责寻找租客、带看、保存租客信息、签合同、收取租金。");
    }

    private void rentAfter(){
        System.out.println("中介负责租客退租后的清扫工作。");
    }

}

4. 主程序 中介出租房屋

二、动态代理

上面讲解的代理机制的操作,属于静态代理,因为每一个代理类只能为一个接口服务,这样程序开发中必然会产生过多的代理类。最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理功能。

Java 中想要实现动态代理的机制,则需要java.lang.reflect.InvocationHandler接口java.lang.reflect.Proxy类的支持。

InvocationHandler接口的定义如下:

java 复制代码
package java.lang.reflect;

public interface InvocationHandler {

    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类。

java 复制代码
	/*
		ClassLoader loader : 类加载器
		Class<?>[] interfaces : 得到真实类实现的全部接口
		InvocationHandler h : 得到InvocationHandler子类实例
	*/
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        ...
    }

房屋租赁代码修改如下 :

1. 需要房东实现租赁的接口

java 复制代码
public interface House {

    /**
     * 定义抽象方法 租赁
     */
    void rent();
}

public class Owner implements House{

    @Override
    public void rent() {
        System.out.println("房东提供房子,收取租金200元/月");
    }
}

2. 创建代理类(InvocationHandler / Proxy)

java 复制代码
package com.javabasic.proxy;

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

public class Agent2 implements InvocationHandler {

    // 接收真实主体
    private Object obj;

    // 对外提供绑定真实主体方法
    public Object bind(Object obj){
        this.obj = obj;
        // 通过真实对象创建代理对象并返回给调用者。
        /*
             Proxy.newProxyInstance : 三个参数
                    类加载器 :  this.obj.getClass().getClassLoader()
                    真实类型实现的所有接口 : this.obj.getClass().getInterfaces()
                    代理类  : this
             return 代理对象
         */
        Object object = Proxy.newProxyInstance(this.obj.getClass().getClassLoader(),
                this.obj.getClass().getInterfaces(), this);
        System.out.println("bind之后object真实类型 = " + object.getClass().getName());
        return object;
    }

    /**
     * 代理类会执行的方法。
     * @param proxy 代理主体
     * @param method 调用的方法
     * @param args 方法的参数
     *
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("proxy真实类型 = " + proxy.getClass().getName());
        
        rentBefore();
        method.invoke(this.obj, args); // 通过反射执行真实主体方法
        rentAfter();
        return null;
    }

    private void rentBefore(){
        System.out.println("中介负责寻找租客、带看、保存租客信息、签合同、收取租金。");
    }

    private void rentAfter(){
        System.out.println("中介负责租客退租后的清扫工作。");
    }
}

3. 主程序 出租

相关推荐
进击的女IT3 分钟前
SpringBoot上传图片实现本地存储以及实现直接上传阿里云OSS
java·spring boot·后端
Miqiuha10 分钟前
lock_guard和unique_lock学习总结
java·数据库·学习
一 乐1 小时前
学籍管理平台|在线学籍管理平台系统|基于Springboot+VUE的在线学籍管理平台系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习
数云界2 小时前
如何在 DAX 中计算多个周期的移动平均线
java·服务器·前端
阑梦清川2 小时前
Java继承、final/protected说明、super/this辨析
java·开发语言
快乐就好ya3 小时前
Java多线程
java·开发语言
IT学长编程3 小时前
计算机毕业设计 二手图书交易系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·二手图书交易系统
CS_GaoMing4 小时前
Centos7 JDK 多版本管理与 Maven 构建问题和注意!
java·开发语言·maven·centos7·java多版本
艾伦~耶格尔4 小时前
Spring Boot 三层架构开发模式入门
java·spring boot·后端·架构·三层架构
man20174 小时前
基于spring boot的篮球论坛系统
java·spring boot·后端