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

news2024/9/25 23:20:14

一、设计模式之代理设计

代理设计是在Java开发中使用较多的一种设计模式,所谓的代理设计模式就是指一个代理主体操作真实主体,真实主体操作具体业务,代理主体负责给具体业务添砖加瓦。
就好比在生活中你有一套房子想要出租(你=真实主体),你找了房产中介(中介=代理主体)。真实主体负责提供房屋和收钱,代理主体负责带客户看房 、扣除手续费。租客只管租房子和付款,至于谁提供的房子并不关心。

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

1. 定义租赁接口

package com.javabasic.proxy;

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

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

2. 定义真实主体 - 房东

package com.javabasic.proxy;

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

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

3. 定义代理主体 - 中介

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接口的定义如下:

package java.lang.reflect;

public interface InvocationHandler {

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

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

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

房屋租赁代码修改如下 :

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

public interface House {

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

public class Owner implements House{

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

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

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. 主程序 出租

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1971084.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mysql-窗口函数一

文章目录 1. 窗口函数概述1.1 介绍1.2 作用 2. 场景说明2.1 准备工作2.2 场景说明2.3 分析2.4 实现2.4.1 非窗口函数方式实现2.4.2 窗口函数方式实现 3. 窗口函数分类4. 窗口函数基础用法&#xff1a;OVER关键字4.1 语法4.2 场景一 :计算每个值和整体平均值的差值4.2.1 需求4.2…

免费的远程办公软件

产生背景 我们的SD-WAN组网的产品一直都是以CPE盒子的形式进行交付&#xff0c;如果您有多个企业分支&#xff0c;那么需要在每个分支安装一个CPE盒子。 这种形式存在一些问题&#xff1a; 成本过高&#xff0c;CPE盒子本身是有成本的&#xff0c;没办法做到免费使用&#xf…

用Maven构建项目和管理依赖

运行本篇中的代码&#xff1a;idea专业版或者idea社区版本&#xff08;2021.1~2022.1.4&#xff09; 用Maven构建项目和管理依赖 1. 初见maven2. maven在网站项目中的应用3. maven和idea的关系4. maven的使用4.1 项目构建4.11 在idea创建maven项目4.12 利用maven命令打包项目 4…

“QtGraphicalEffects“ is not installed

【1】问题&#xff1a;qml项目报 module "QtGraphicalEffects" is not installed 【2】解决方法&#xff1a;将qml目录中的"QtGraphicalEffects" 拷贝到工程release目录

3种 Ajax 方式:原生、jQuery、axios

毋庸多言&#xff0c;Ajax 技术在网页中是划时代的进步。学会它&#xff0c;可以说掌握了一招半式&#xff0c;不再是门外汉了。 这里将 3 种 Ajax 方式一并呈上。 感谢 https://run.uv.cc/ 平台&#xff0c;以及 /api 接口 https://andi.cn/page/621639.html https://andi…

用Java手写jvm之模拟类加载器加载class

写在前面 本文来尝试模拟类加载器加载class的过程。 1&#xff1a;程序 首先来定义类加载器类&#xff1a; /*** 类加载器* 正常应该有bootstrap&#xff0c;ext&#xff0c;app三个类加载器&#xff0c;这里简单起见&#xff0c;只用一个来模拟了*/ public class ClassLoa…

入门 PyQt6 看过来(案例)20~ 动态树

​ 1 QTreeWidget树类 QTreeWidget类可以呈现数组、数列等数据&#xff0c;并且可以进行交互&#xff0c;它使用标准的数据模型&#xff0c;其单元格数据通过QTableWidgetItem对象来实现。 QTreeWidget继承自QTreeView&#xff0c;是封装了默认Model的QTreeView&#xff0c;其…

C++ | Leetcode C++题解之第312题戳气球

题目&#xff1a; 题解&#xff1a; class Solution { public:int maxCoins(vector<int>& nums) {int n nums.size();vector<vector<int>> rec(n 2, vector<int>(n 2));vector<int> val(n 2);val[0] val[n 1] 1;for (int i 1; i &l…

ElasticSearch入门(六)SpringBoot2

private String author; Field(name “word_count”, type FieldType.Integer) private Integer wordCount; /** Jackson日期时间序列化问题&#xff1a; Cannot deserialize value of type java.time.LocalDateTime from String “2020-06-04 15:07:54”: Failed to des…

Django文件上传

【图书介绍】《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》_django 5企业级web应用开发实战(视频教学版)-CSDN博客 《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》(王金柱)【摘要 书评 试读】- 京东图书 (jd.com) 本节主要介…

【计算机网络】IP地址和子网掩码(子网掩码篇)

个人主页:【😊个人主页】 系列专栏:【❤️计算机网络】 文章目录 前言什么是子网掩码?子网掩码的组成组成规则表示方法子网掩码的分类标准(默认)子网掩码:变长子网掩码(VLSM):全零和全一子网掩码:子网掩码的计算确定IP地址类别及默认子网掩码计算子网掩码根据子网数…

橙单中台化低代码生成器

​橙单中台化低代码生成器 在当今快速发展的软件开发领域&#xff0c;橙单中台化低代码生成器凭借其强大的功能和灵活的架构&#xff0c;成为了开发者不可或缺的利器。本文将介绍橙单的基本信息、特点以及如何快速部署和使用。 软件简介 橙单中台化低代码生成器是一款开源的低…

被华为的AI扩图震惊到,超自然超好看!

美颜、P图对大家来说都不陌生&#xff0c;但是近期在互联网实火的各种AI扩图你了解多少&#xff1f;它既能满足图片构图时进行延伸美化&#xff0c;又能在未知的创意里无限探索。 近期&#xff0c;华为Pura 70系列手机获推HarmonyOS 4.2.0.172 更新&#xff0c;华为Pura 70 Pr…

事务性邮件API的功能优势?考虑哪些指标?

事务性邮件API的性能如何优化&#xff1f;怎么选择邮件API接口&#xff1f; 在当今数字化时代&#xff0c;企业需要一种高效、可靠的方法与客户沟通。事务性邮件API成为解决这一需求的重要工具。AokSend将探讨事务性邮件API的功能优势及考虑的关键指标。 事务性邮件API&#…

如何在 Kubernetes 中使用 ClickHouse 和 JuiceFS

ClickHouse 结合 JuiceFS 一直是一个热门的组合&#xff0c;社区中有多篇实践案例。今天的文章来自美国公司 Altinity&#xff0c;一家提供 ClickHouse 商业服务的企业&#xff0c;作者是 Vitaliy Zakaznikov&#xff0c;他尝试了这个组合并公开了过程中使用的代码。原文有两篇…

基于DreamBooth的“妙鸭相机”——一次不太成功的实践

重磅推荐专栏: 《大模型AIGC》 《课程大纲》 《知识星球》 本专栏致力于探索和讨论当今最前沿的技术趋势和应用领域,包括但不限于ChatGPT和Stable Diffusion等。我们将深入研究大型模型的开发和应用,以及与之相关的人工智能生成内容(AIGC)技术。通过深入的技术解析和实践经…

Encoder-Decoder:Seq2seq

目录 一、编码器解码器架构&#xff1a;1.定义&#xff1a;2.在CNN中的体现&#xff1a;3.在RNN中的体现&#xff1a;4.代码&#xff1a; 二、Seq2seq&#xff1a;1.模型架构&#xff1a;1.1编码器&#xff1a;1.2解码器&#xff1a; 2.架构细节&#xff1a;3.模型评估指标BLEU…

C# Unity 补全计划 泛型

本文仅作学习笔记与交流&#xff0c;不作任何商业用途&#xff0c;作者能力有限&#xff0c;如有不足还请斧正 1.什么是泛型 泛型&#xff08;Generics&#xff09;是C#中的一个强大特性&#xff0c;允许你编写可以适用于多种数据类型的可重用代码&#xff0c;而不需要重复编写…

第二证券:刚刚!亚太股市,跌麻了!

今天早盘&#xff0c;亚太股市全线崩跌。日经225指数在大幅低开之后快速下行&#xff0c;最大跌幅近5%&#xff1b;韩国、澳大利亚股指亦迎来逾越2%以上的暴降。那么&#xff0c;毕竟发生了什么&#xff1f; 剖析人士认为&#xff0c;或许仍是与日元套息有关。从前史来看&…

Duplicate class kotlin.collections.jdk8.CollectionsJDK8Kt found in modules。Android studio纯java代码报错

我使用java代码 构建项目&#xff0c;初始代码运行就会报错。我使用的是Android Studio Giraffe&#xff08;Adroid-studio-2022.3.1.18-windows&#xff09;。我在网上找的解决办法是删除重复的类&#xff0c;但这操作起来真的太麻烦了。 这是全部报错代码&#xff1a; Dupli…