当前位置: 首页 > 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…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文&#xff5c;DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色&#xff0c;华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型&#xff0c;能助力我们轻松驾驭 DeepSeek-V3/R1&#xff0c;本文中将分享如何…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...