【Day14-单例设计模式动态代理】
单例设计模式
什么是设计模式(Design pattern) ?
- 一个问题通常有n种解法,其中肯定有一种解法是最优的,这个最优的解法被人总结出来了,称之为设计模式。
- 设计模式有20多种,对应20多种软件开发中会遇到的问题。
单例设计模式
作用:确保一个类只有一个对象。
场景:计算机中的回收站、任务管理器、Java中的Runtime类等
写法
- 把类的构造器私有(保证别人不能new)
- 在类中自己创建一个对象,并赋值到一个变量
- 定义一个静态方法,返回自己创建的这个对象

/*
单例设计模式作用:确保一个类只有一个对象。场景:计算机中的回收站、任务管理器、Java中的Runtime类等饿汉式(提前创建对象)把类的构造器私有(保证别人不能new)在类中自己创建一个对象,并赋值到一个变量定义一个静态方法,返回自己创建的这个对象
*/
public class Demo {public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {User user = User.getUser();System.out.println(Thread.currentThread().getName() + "--" + user);}},"小白").start();new Thread(() -> {User user = User.getUser();System.out.println(Thread.currentThread().getName() + "--" + user);},"小紫").start();}
}class User{private String name;private Integer age;//2.创建自己的对象private static User user = new User();//构造器私有private User() {}//提供一个方法,返回对象public static User getUser(){return user;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public static void setUser(User user) {User.user = user;}
}
1、单例模式解决了什么问题 ?有啥场景和好处?
确保一个类只有一个对象。
任务管理器对象、获取运行时对象。
在这些业务场景下,使用单例模式,可以避免浪费内存。
2、单例怎么写?
3、饿汉式单例的特点是什么?
在获取类的对象时,对象已经创建好了。
懒汉式单例设计模式
写法
- 把类的构造器私有(保证别人不能new)
- 在类中定义一个类变量用于存储对象(注意:此时只定义,不创建)
- 提供一个类方法,在方法中创建并返回对象(要保证只创建一次)

/*
单例设计模式作用:确保一个类只有一个对象。场景:计算机中的回收站、任务管理器、Java中的Runtime类等懒汉式(第一次获取时创建对象)把类的构造器私有(保证别人不能new)在类中定义一个类变量用于存储对象(注意:此时只定义,不创建)提供一个类方法,在方法中创建并返回对象(要保证只创建一次)注意获取方法需要使用synchronized修饰,以保证只有一个线程可以成功创建出对象
*/
public class Demo {public static void main(String[] args) {new Thread(() -> {Teacher teacher = Teacher.getTeacher();System.out.println(Thread.currentThread().getName() + "--" + teacher);}).start();new Thread(() -> {Teacher teacher1 = Teacher.getTeacher();System.out.println(Thread.currentThread().getName() + "--" + teacher1);}).start();}
}class Teacher{private String name;private Integer age;private Teacher(){}//定义变量,不要创建private static volatile Teacher teacher;//提供静态方法,返回当前类的对象
// public static Teacher getTeacher() {
// if (teacher == null) {
// teacher = new Teacher();
// }
// return teacher;
// }//同步方法
// public static synchronized Teacher getTeacher() {
// if (teacher == null) {
// teacher = new Teacher();
// }
// return teacher;
// }//同步代码块public static Teacher getTeacher() {if (teacher == null) {synchronized (Teacher.class) {if (teacher == null) {teacher = new Teacher();}}}return teacher;}
}
1、懒汉单例模式的特点是什么?
要用类的对象时才创建对象(延迟加载对象)
2、懒汉单例模式怎么写?
- 把构造器私有
- 定义一个类变量用于存储对象
- 提供一个类方法,保证返回的是同一个对象
使用枚举实现单例设计模式
/*
单例设计模式作用:确保一个类只有一个对象。场景:计算机中的回收站、任务管理器、Java中的Runtime类等枚举实现单例直接在枚举中提供一个枚举项就可以实现单例注意Google首席Java架构师、(Effective Java》 一书作者Java集合框架的开创者Joshua Bloch在Effective Java一书中提到单元素的枚举类型,已经成为实现singleton的最佳方法在这种实现方式中,既可以避免多线程同步问题还可以防止通过反射和反序列化来重新创建新的对象在很多优秀的开源代码中,我们经常可以看到使用枚举方式来实现的单例模式类
*/
public class Demo {public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {School wangba = School.Wangba;System.out.println(Thread.currentThread().getName() + "--" + wangba.hashCode());}}).start();new Thread(() -> {School wangba = School.Wangba;System.out.println(Thread.currentThread().getName() + "--" + wangba.hashCode());}).start();new Thread(new Runnable() {@Overridepublic void run() {School wangba = School.Wangba;System.out.println(Thread.currentThread().getName() + "--" + wangba.hashCode());}}).start();}
}enum School{Wangba
}
动态代理

如何为Java对象创建一个代理对象?
- java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:

/*
接口
*/
public interface Star {String sing(String name);void dance();
}
public class ProxyUtil {public static Star createProxy(Star star){//1.获取被代理对象,参数中已经传入//2.编写代理类的业务逻辑InvocationHandler invocationHandler = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//调用代理对象的方法名字String methodName = method.getName();if (methodName.equals("sing")) {System.out.println("经纪人---买个话筒,收钱");} else {System.out.println("经纪人---盘一块地,收钱");}Object obj = method.invoke(star, args);return obj;}};//3.生成代理对象Object obj = Proxy.newProxyInstance(star.getClass().getClassLoader(),star.getClass().getInterfaces(),invocationHandler);//返回代理对象return (Star) obj;}
}
public class Cln implements Star{@Overridepublic String sing(String name) {System.out.println("ccc唱:" + name);return name;}@Overridepublic void dance() {System.out.println("ccc💃💃💃💃💃");}
}
public class ProxyUtilTest {public static void main(String[] args) {//创建被代理对象Cln cln = new Cln();//生成代理对象Star star = ProxyUtil.createProxy(cln);//调用代理对象,让被代理对象干活star.sing("大香蕉");star.dance();}
}
案例:
使用代理优化用户管理类
场景
某系统有一个用户管理类,包含用户登录,删除用户,查询用户等功能,系统要求统计每个功能的执行耗时情况,以便后期观察程序性能。需求
现在,某个初级程序员已经开发好了该模块,请观察该模块的代码,找出目前存在的问题,并对其进行改造。
public class UserServiceProxyUtil {public static UserService createProxy(UserService userService) {//获得被代理对象//编写相关业务逻辑代码InvocationHandler invocationHandler = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//调用代理对象的方法名字String methodName = method.getName();if (methodName.equals("login")) {System.out.println(new Date() + "==" + Arrays.toString(args) + "登录了");}//进行计时long begin = System.currentTimeMillis();//调用真正的方法Object obj = method.invoke(userService, args);//进行计时,结束long end = System.currentTimeMillis();//计算差值long time = end - begin;System.out.println("【" + methodName + "】方法,执行了:【" + time + "毫秒】");return obj;}};//调用Proxy生成代理对象UserService user = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),userService.getClass().getInterfaces(),invocationHandler);//返回代理对象return user;}
}
/*** 用户业务实现类*/
public class UserServiceImpl implements UserService {@Overridepublic void login(String loginName, String passWord) throws Exception {if ("admin".equals(loginName) && "123456".equals(passWord)) {System.out.println("您登录成功,欢迎光临本系统~");} else {System.out.println("您登录失败,用户名或密码错误~");}Thread.sleep(1000);}@Overridepublic void deleteUsers() throws Exception {System.out.println("成功删除了1万个用户~");Thread.sleep(1500);}@Overridepublic String[] selectUsers() throws Exception {System.out.println("查询出了3个用户");String[] names = {"张全蛋", "李二狗", "牛爱花"};Thread.sleep(500);return names;}
}
/*** 用户业务接口*/
public interface UserService {// 登录功能void login(String loginName, String passWord) throws Exception;// 删除用户void deleteUsers() throws Exception;// 查询用户,返回数组的形式。String[] selectUsers() throws Exception;
}
/*** 目标:使用动态代理解决实际问题,并掌握使用代理的好处。*/
public class Test {public static void main(String[] args) throws Exception{// 1、创建用户业务对象UserService userService = new UserServiceImpl();UserService proxy = UserServiceProxyUtil.createProxy(userService);// 2、调用用户业务的功能。proxy.login("admin", "123456");System.out.println("----------------------------------");proxy.deleteUsers();System.out.println("----------------------------------");String[] names = proxy.selectUsers();System.out.println("查询到的用户是:" + Arrays.toString(names));System.out.println("----------------------------------");}
}
相关文章:
【Day14-单例设计模式动态代理】
单例设计模式 什么是设计模式(Design pattern) ? 一个问题通常有n种解法,其中肯定有一种解法是最优的,这个最优的解法被人总结出来了,称之为设计模式。设计模式有20多种,对应20多种软件开发中会遇到的问题…...
代码随想录训练营Day7 | 454.四数相加II | 383. 赎金信 | 15. 三数之和 | 18. 四数之和
代码随想录 (programmercarl.com) Leetcode 454. 四数相加 II 题目描述 给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] B[j] C[k] D[l] 0。 为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N&#…...
C++和OpenGL实现3D游戏编程【目录】
欢迎来到zhooyu的专栏。 个人主页:【zhooyu】 文章专栏:【OpenGL实现3D游戏编程】 贝塞尔曲面演示: 贝塞尔曲面演示zhooyu 本专栏内容: 我们从游戏的角度出发,用C去了解一下游戏中的功能都是怎么实现的。这一切还是要…...
03-Mac系统PyCharm主题设置
目录 1. 打开PyCharm窗口 2. Mac左上角点击PyCharm,点击Settings 3. 点击第一项Appearance& Behavior 4. 点击Appearance 5. 找到Theme进行设置 1. 打开PyCharm窗口 2. Mac左上角点击PyCharm,点击Settings 3. 点击第一项Appearance& Behavi…...
Java并发的四大定律
每一个进入 Java 并发世界的人,都会不可避免地面临一系列问题:线程安全、并发控制、锁,以及共享资源。这些概念复杂又抽象,往往让人无从下手。幸运的是,业界早已总结出一些法则,这些法则为我们处理并发问题…...
java项目之基于springboot的贸易行业crm系统(源码+文档)
风定落花生,歌声逐流水,大家好我是风歌,混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的基于springboot的贸易行业crm系统。项目源码以及部署相关请联系风歌,文末附上联系信息 。 项目简介: 基于sp…...
General OCR Theory: Towards OCR-2.0 via a Unified End-to-end Model
摘要 传统的OCR系统(OCR-1.0)越来越无法满足人们对智能处理人造光学字符的需求。在本文中,我们将所有人造光学信号(例如,普通文本、数学/分子公式、表格、图表、乐谱,甚至是几何形状)统称为“字…...
二十种编程语言庆祝中秋节
二十种编程语言庆祝中秋节 文章目录 二十种编程语言庆祝中秋节中秋快乐!家人们 🥳一 Python二 C三 C四 Java五 C#六 Perl七 Go八 Asp九 PHP十 JavaScript十一 JavaScript HTML十二 Visual Basic十三 早期 VB十四 Visual C十五 Delphi十六 Shell十七 Cobo…...
202409012在飞凌的OK3588-C的核心板上使用Rockchip原厂的Buildroot点MIPI屏【背光篇】
202409012在飞凌的OK3588-C的核心板上使用Rockchip原厂的Buildroot点MIPI屏【背光篇】 2024/9/12 10:44 缘起,拿到一块MIPI屏,需要使用飞凌的OK3588-C的核心板在Android12下点亮。 在飞凌的Linux R4下修改部分屏参之后即可直接点亮。 但是在飞凌的Andro…...
DMDRS搭建
DMDRS搭建 本次进行DMDRS工具的部署搭建以及使用 环境配置 操作系统及数据库配置 操作系统:使用CentOS7数据库:dm8_20240408_x86_rh7_64 服务器配置 实例名服务器IPDM1192.168.19.7(源DMDRS)DM2192.168.19.4(目的…...
【油猴脚本】00006 案例 Tampermonkey油猴脚本自定义表格列名称,自定义表格表头,自定义表格的thead里的td
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 【油…...
JS - 获取剪切板内容 Clipboard API
目录 1,需求最终效果 2,实现示例 3,注意点1,只支持安全上下文环境2,只能读取当前页面的剪切板3,权限获取问题4,获取内容的 MIME_TYPE 问题1,文本内容2,图片内容 5&#x…...
Qt自动打开文件夹并高亮文件
在Qt中,如果你想要打开一个文件夹并在文件管理器中高亮显示(选中)某个文件,你可以使用以下方法: 对于Windows系统,你可以使用QProcess来启动explorer命令,并带上/select,参数来高亮显示文件。以…...
神经网络-MNIST数据集训练
文章目录 一、MNIST数据集1.数据集概述2.数据集组成3.文件结构4.数据特点 二、代码实现1.数据加载与预处理2. 模型定义3. 训练和测试函数4.训练和测试结果 三、总结 一、MNIST数据集 MNIST数据集是深度学习和计算机视觉领域非常经典且基础的数据集,它包含了大量的手…...
数据结构二
求 sizeof(name1)?(晟安信息) struct name1{ char str; short x; int num; }; sizeof name1内存对齐 8个字节 char分配8个字节 然后 short节省空间在4个字节中 而这个int独自分配分配内存 4个字节所以共8个字节 (电工时代) typedef struct _a { char c1; long i…...
Python|基于Kimi大模型,删除已上传的“指定文档”或“全部文档”(6)
前言 本文是该专栏的第6篇,后面会持续分享AI大模型干货知识,记得关注。 在本专栏上一篇《Python|基于Kimi大模型,实现上传文档并进行对话(5)》中,笔者有详细介绍“基于kimi大模型,上传指定文档并结合prompt,获取目标文本数据”。对此感兴趣的同学,可以直接点击翻阅查…...
CenterPoint-KITTI:环境配置、模型训练、效果展示;KITTI 3D 目标检测数据集下载
目录 前言 Python虚拟环境创建以及使用 KITTI3D目标检测数据集 CenterPoint-KITTI编译遇到问题合集 ImportError: cannot import name VoxelGenerator from spconv.utils 失败案例 最终解决方案 对于可选参数,road plane的处理 E: Unable to locate packag…...
【Android】ViewPager
1.ViewPager的简介和作用 ViewPager是android扩展包v4包中的类,这个类可以让用户左右切换当前的view,用于允许用户在几个页面(或称为碎片)之间左右滑动切换。它通常用于创建像画廊或轮播图那样的用户体验。 ViewPager类直接继承了…...
[go] 命令模式
命令模式 将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。 模型说明 触发者类负责对请求进行初始化,其中必须包含一个成员变量来存储对于命令对象的引用。触发命令,而不同接受者直接…...
代码随想录冲冲冲 Day48 单调栈Part2
42. 接雨水 关键点有以下几个 首先是怎么去理解接雨水 其实就是找每一个段的左边第一个最大值和右边第一个最大值 既然是最大值 那么单调栈就是递增的 左边第一个最大值其实就是pop掉中间的之后st.top 由于是出现大于等于情况时候进行操作 所以右边最大值就是i 接下来就…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
协议转换利器,profinet转ethercat网关的两大派系,各有千秋
随着工业以太网的发展,其高效、便捷、协议开放、易于冗余等诸多优点,被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口,具有实时性、开放性,使用TCP/IP和IT标准,符合基于工业以太网的…...
flow_controllers
关键点: 流控制器类型: 同步(Sync):发布操作会阻塞,直到数据被确认发送。异步(Async):发布操作非阻塞,数据发送由后台线程处理。纯同步(PureSync…...
