当前位置: 首页 > news >正文

Java之设计模式

概述

设计模式就是经过我们开发人员通过长时间的开发实践得出的一种开发模式,目的就是在开发过程中降低代码耦合度,提高代码可复用性/扩展/维护。目前设计模式可以分为创建型模式、行为型模式、结构型模式,一共包括23种设计模式。本文列举了实际项目中使用到的设计模式,包括单例模式、策略模式、代理模式

创建型模式

单例模式

  • 目的就是解决一个类Class在应用程序中只有一个实例存在,并提供对外的全局访问
  • 构造函数私有化、对外提供获取实例静态方法
  • 项目实践
    • 在多线程环境中缓存文件操作记录到队列中,后续通过定时任务添加到数据库
  • public class LazyQueueSingleton {private static int QUEUE_MAX_SIZE = 80000;// LinkedBlockingQueue线程安全的共享队列,并设置队列初始大小避免内存溢出private volatile Queue<HistoryRecords> ShareQueue = new LinkedBlockingQueue<>(QUEUE_MAX_SIZE);private static final Object lockedObj = new Object();//懒汉式队列单例,保证实例全局唯一 private static volatile LazyQueueSingleton INSTANCE;private LazyQueueSingleton() {if(ShareQueue == null) {ShareQueue = new LinkedBlockingQueue<>(QUEUE_MAX_SIZE);}}public static LazyQueueSingleton getInstance() {if(INSTANCE == null) {synchronized (lockedObj) {if(INSTANCE == null) {INSTANCE = new LazyQueueSingleton();}}}return INSTANCE;}public Queue<HistoryRecords> getPendingTodoQueue() {return ShareQueue;}
    }

行为型模式

策略(Strategy)模式

  • 定义了一组算法,将每一个算法封装到具有共同接口的独立的类中,使得它们可以相互替换。常常适用于业务存在很多复杂分支场景
  • 上下文/Context(持有策略对象的引用,通过该引用来调用算法或行为)、策略/Strategy(定义所有支持的算法的公共接口)、具体策略/Concrete Strategy(实现策略接口的具体算法或行为)
  • 项目实践
    • 系统需要根据不同部门来计算报表生成的内容
    • // 1.定义策略接口
      public interface GernerateReportStrategy {boolean calculateReport(int departmentId);
      }// 2.实现具体策略
      public class BDGernerateReportStrategy implements GernerateReportStrategy {@Overridepublic boolean calculateReport(int departmentId) {......}
      }
      public class SwGernerateReportStrategy implements GernerateReportStrategy {@Overridepublic boolean calculateReport(int departmentId) {......}
      }
      // 3.创建上下文
      public class DownloadReportContext {private GernerateReportStrategy gernerateReportStrategy;public void setGernerateReportStrategy(GernerateReportStrategy gernerateReportStrategy) {this.gernerateReportStrategy = gernerateReportStrategy;}......
      }
      // 4.接下来就可以使用了,若后续有新增部门则直接实现具体策略类即可

结构型模式

代理模式

  • 核心思想:为其他对象提供一种代理以控制对这个对象的访问
  • 角色:代理角色、真实/原始/目标角色
  • 作用:一是保护真实/原始/目标对象,二是增强真实/原始/目标对象
静态代理
  • 静态代理是一种在编译时就已经确定代理类和目标对象关系的代理模式。它通常通过创建一个接口和两个实现这个接口的类(一个为目标对象类,另一个为代理类)来实现
  • 代码实践
    • // 1.定义一个接口,该接口包含一个或多个方法
      interface Service {void execute();
      }
      // 2.创建一个目标对象类,它实现这个接口
      class RealService implements Service {public void execute() {System.out.println("Executing real service.");}
      }
      // 3.创建一个代理类,也实现这个接口,并包含对目标对象的引用。也可以在调用目标对象的方法之前或之后添加额外的操作
      class ProxyService implements Service {private RealService realService;public ProxyService(RealService realService) {this.realService = realService;}public void execute() {System.out.println("Before execution.");realService.execute();System.out.println("After execution.");}
      }
      // 4.客户端使用
      Service service = new ProxyService(new RealService());
      service.execute();
动态代理
  • 动态代理是一种在运行时动态创建代理对象的代理模式。不需要事先编写代理类代码,而是在运行时根据目标对象动态生成代理类
    • JDK动态代理 VS Cglib动态代理
      • 代理的目标对象要求
        • JDK要求目标类必须实现接口,而Cglib提供更大的灵活性,目标类实现接口或者只是普通类都可以(基于此SpringBoot2.x以上默认使用CGLIB代理)
      • 代理对象的创建方式
        • JDK通过Proxy类和实现InvocationHandler接口来创建代理对象; Cglib通过Enhancer类直接创建代理对象
      • 执行性能
        • JDK动态通过反射实现,Cglib则使用字节码生成技术直接操作字节码,因此在一些场景下,Cglib更加高效
      • 通常情况下,我们开发人员不需要在配置文件中明确指定AOP使用的代理方式,因为Spring会自动根据目标对象的类型选择代理方式
  • 项目实践
    • JDK动态代理代码实践
// 1. 定义接口
public interface Report {void generateReportByDepartmentId(int departmentId);void generateReportByDepartmentName(String departmentName);
}
// 2. 定义目标/原始/真实对象
public class generateReport implements Report {@Overridepublic void generateReportByDepartmentId(int departmentId) {System.out.println("按部门ID已生成报表:" + departmentId);}@Overridepublic void generateReportByDepartmentName(String departmentName) {System.out.println("按部门名称已生成报表:" + departmentName);}
}
// 3. 定义代理对象
public class ReportJDKProxy implements InvocationHandler {//需要被代理的对象private Object object;public ReportJDKProxy(Object object) {this.object = object;}@SuppressWarnings("unchecked")public <T> T getProxy(){// 使用反射API动态创建代理类return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),//当前线程的上下文ClassLoaderobject.getClass().getInterfaces(), //代理需要实现的接口this); // 处理器自身}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = null;//进行方法匹配,调用对应方法名的方法if ("generateReportByDepartmentId".equals(method.getName())) {System.out.println("按部门ID已生成报表------前置增强------");result=method.invoke(object, args);System.out.println("按部门ID已生成报表------后置增强------");}if ("generateReportByDepartmentName".equals(method.getName())) {System.out.println("按部门名称已生成报表------前置增强------");result=method.invoke(object, args);System.out.println("按部门名称已生成报表------后置增强------");}return result;}
}
// 4. 客户端使用// 调用方式一Report player=new generateReport(); Report proxy=new ReportJDKProxy(player).getProxy(); proxy.generateReportByDepartmentId(666);proxy.generateReportByDepartmentName("SW");/** // 调用方式二 * Report p=new generateReport(); * Report o = (Report)Proxy.newProxyInstance( p.getClass().getClassLoader(),p.getClass().getInterfaces(), new ReportJDKProxy(p) );* o.generateReportByDepartmentId(666); * o.generateReportByDepartmentName("SW");*/
  • Cglib动态代理代码实践
    • // 1. 创建目标对象/接口实现类
      class ToReport{public void generateReport() {System.out.println("生成报表---CglibProxy");}
      }
      // 2. 创建代理对象
      class CglibProxy implements MethodInterceptor {/*** @param o:           代理对象* @param method:      被代理方法* @param params:      方法入参* @param methodProxy: CGLIB方法**/@Overridepublic Object intercept(Object o, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {System.out.println("【Cglib前置方法】代理对象正在执行的方法:" + method.getName());Object result = methodProxy.invokeSuper(o, params);System.out.println("【Cglib后置方法】代理对象正在执行的方法:" + method.getName());return result;}
      }
      // 3. 创建Enhancer(设置要被代理的类和调用方法时触发的拦截器)
      class CglibProxyFactory{public static Object creatCglibProxyObj(Class<?> clazz) {Enhancer enhancer = new Enhancer();// 为加强器指定要代理的业务类(即为下面生成的代理类指定父类)enhancer.setSuperclass(clazz);// 设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法enhancer.setCallback(new CglibProxy());return enhancer.create();}
      }
      // 4. 客户端使用
      public static void main(String[] args) {	ToReport report = (ToReport)CglibProxyFactory.creatCglibProxyObj(ToReport.class);report.generateReport();
      }

相关文章:

Java之设计模式

概述 设计模式就是经过我们开发人员通过长时间的开发实践得出的一种开发模式,目的就是在开发过程中降低代码耦合度,提高代码可复用性/扩展/维护。目前设计模式可以分为创建型模式、行为型模式、结构型模式,一共包括23种设计模式。本文列举了实际项目中使用到的设计模式,包括单…...

大胆预测:计算机将要回暖

中概财报集体亮眼 虽然最近几天恒指&#xff08;港股&#xff09;稍有回落&#xff0c;但年线仍有 9% 的上涨。 过去三年&#xff0c;恒指分别下跌 14.08%、15.46% 和 13.82%。 而在近期&#xff0c;国内各大互联网都公布了财报&#xff0c;别看各个大厂的作妖不断&#xff0c;…...

49 序列化和反序列化

本章重点 理解应用层的作用&#xff0c;初识http协议 理解传输层的作用&#xff0c;深入理解tcp的各项特性和机制 对整个tcp/ip协议有系统的理解 对tcp/ip协议体系下的其他重要协议和技术有一定的了解 学会使用一些网络问题的工具和方法 目录 1.应用层 2.协议概念 3. 网络计…...

PS —— 精修图像

PS —— 精修图像 修复污点修复画笔工具修复画笔工具 美白滤镜去杂锐化加杂减淡和锐化工具 我觉得今天这篇博客&#xff0c;无论是男同胞还是女同胞&#xff0c;都要熟练掌握&#xff08;哈哈哈哈…) 今天我们来学习如何精修图像&#xff0c;精修图像一般分为几步——修复&…...

哥白尼哨兵系列卫星数据不能下载的解决方法

自2023年1月24日起&#xff0c;一个新的哥白尼数据空间生态系统已经启动&#xff0c;为所有哨兵数据&#xff08;Sentinel-1, Sentinel-2, Sentinel-3 and Sentinel-5P&#xff09;提供可视化和数据处理&#xff0c;地址为&#xff1a;https://dataspace.copernicus.eu/。详细介…...

结构型模式之桥接模式

文章目录 概述原理结构图代码示例 小结 概述 桥接模式(bridge pattern) 的定义是&#xff1a;将抽象部分与它的实现部分分离&#xff0c;使它们都可以独立地变化。 桥接模式用一种巧妙的方式处理多层继承存在的问题,用抽象关联来取代传统的多层继承,将类之间的静态继承关系转…...

数据结构--顺序表

目录 1.顺序表 1.1顺序表的概念及结构 线性表 2、顺序表分类 2.1顺序表和数组的区别 静态顺序表 动态顺序表 3.顺序表的实现 3.1初始化 随后便可对顺序表初始化 3.2插入数据 尾插 头插 在指定位置插入数据 顺序表的查找 头删、尾删及指定位置删除 实现代码&#x…...

【C++项目】实时聊天的在线匹配五子棋对战游戏

目录 项目介绍 开发环境 核心技术 项目前置知识点介绍 Websocketpp 1. WebSocket基本认识 2. WebSocket协议切换原理解析 3. WebSocket报文格式 4. Websocketpp介绍 5. 搭建一个简单WebSocket服务器 JsonCpp 1. Json格式的基本认识 2. JsonCpp介绍 3. 序列化与反序…...

7.2k star的万能视频解析下载插件

今天给大家介绍一个超级厉害的浏览器插件&#xff0c;可以解析各个平台网页视频——猫抓。 项目简介 猫抓&#xff08;cat-catch&#xff09; 是一款资源嗅探扩展插件&#xff0c;他能够帮助你筛选列出当前页面的资源。简单来说&#xff0c;当你打开任意一个带有视频的网页&a…...

dmanywhere的docker制作

dmanywhere的docker制作 官网地址&#xff1a; http://www.dmanywhere.cn/ 下载相关执行文件。 Dockerfile的默认命名是“Dockerfile”&#xff0c; 在构建镜像时&#xff0c;如果没有指定Dockerfile文件&#xff0c;Docker通常会寻找名为“Dockerfile”的文件 1.Dockerf…...

Leetcode | 5-21| 每日一题

2769. 找出最大的可达成数字 考点: 暴力 数学式子计算 思维 题解 通过式子推导: 第一想法是二分确定区间在区间内进行查找是否符合条件的, 本题最关键的便是 条件确定 , 第二种方法: 一般是通过数学公式推导的,这种题目我称为数学式编程题 代码 条件判断式 class Solution {…...

vue3添加收藏网站页面

结构与样式 <template><div class"web_view"><ul><li v-for"web in webList" :key"web.title"><a :href"web.src" :title"web.title" target"_blank"><img :src"web.img&…...

吴恩达深度学习笔记:超 参 数 调 试 、 Batch 正 则 化 和 程 序 框 架(Hyperparameter tuning)3.4-3.5

目录 第二门课: 改善深层神经网络&#xff1a;超参数调试、正 则 化 以 及 优 化 (Improving Deep Neural Networks:Hyperparameter tuning, Regularization and Optimization)第三周&#xff1a; 超 参 数 调 试 、 Batch 正 则 化 和 程 序 框 架&#xff08;Hyperparameter …...

牛客NC362 字典序排列【中等 DFS Java/Go/PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/de49cf70277048518314fbdcaba9b42c 解题方法 DFS&#xff0c;剪枝Java代码 import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回…...

PHP获取文件路径getcwd()、__DIR__、__FILE__的区别

getcwd() getcwd() 是一个函数&#xff0c;它返回当前工作目录&#xff08;CWD&#xff09;的完整路径。当前工作目录是脚本开始执行时所在的目录&#xff0c;除非在脚本执行过程中通过 chdir() 函数进行了更改。 $cwd getcwd(); echo $cwd; // 输出当前工作目录的完整路径…...

Kafka(十三)监控与告警

目录 Kafka监控与告警1 解决方案1.2 基础知识JMX监控指标代理查看KafkaJMX远程端口 1.3 真实案例Kafka Exporter:PromethusPromethus Alert ManagerGrafana 1.3 实际操作部署监控和告警系统1.2.1 部署Kafka Exporter1.2.2 部署Prometheus1.2.3 部署AlertManger1.2.4 添加告警规…...

SBC3568启动升级,灵活更换动画logo

今天小智将会带着大家体验如何在openharmony sdk内替换开机logo和动态动画。 1. 更换开机logo 开机logo分为uboot阶段【logo.bmp】和kernel阶段【logo_kernel.bmp】的logo两个文件&#xff0c;对图片的要求是&#xff1a;必须为bmp格式&#xff0c;8或者24位深&#xff0c;且…...

v-if 与 v-show(vue3条件渲染)

v-if 是“真正”的条件渲染&#xff0c;因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。 v-if 也是惰性的&#xff1a;如果在初始渲染时条件为假&#xff0c;则什么也不做——直到条件第一次变为真时&#xff0c;才会开始渲染条件块。 相比之下&a…...

nuxt: generate打包后访问资源404问题

现象 使用Nuxt.js开发的个人页面&#xff0c;部署到nginx服务器中&#xff0c;/_nuxt/*.js、/_nuxt/*.css等静态问题不能访问&#xff0c;提示404错误。 而我们的这些资源文件是存在的。 解决方法 加上此处代码进行上下文配置 baseURL: /nuxt/ 此时在nginx配置 /nuxt 代理 lo…...

【图像超分】论文精读:Residual Non-local Attention Networks for Image Restoration(RNAN)

第一次来请先看这篇文章:【超分辨率(Super-Resolution)】关于【超分辨率重建】专栏的相关说明,包含专栏简介、专栏亮点、适配人群、相关说明、阅读顺序、超分理解、实现流程、研究方向、论文代码数据集汇总等) 文章目录 前言Abstract1 INTRODUCTION2 RELATED WORK3 RESIDU…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...