day14-单例设计模式动态代理

devtools/2024/9/19 11:08:46/ 标签: 单例模式, java, 开发语言

一、单例设计模式

单例设计模式作用:确保一个类只有一个对象。场景:计算机中的回收站、任务管理器、Java中的Runtime类等好处:在这些业务场景下,使用单例模式,可以避免浪费内存。

1.1 饿汉式

饿汉式(提前创建对象)把类的构造器私有(保证别人不能new)在类中自己创建一个对象,并赋值到一个变量定义一个静态方法,返回自己创建的这个对象饿汉式单例的特点:    在获取类的对象时,对象已经创建好了。
​单例设计模式:单线程下是一个对象,多线程下也是一个对象
java">public class Demo {public static void main(String[] args) {//单线程下,只有一个对象
//        User user = User.getUser();
//        System.out.println(Thread.currentThread().getName()+":"+user);
//        User user1 = User.getUser();
//        System.out.println(Thread.currentThread().getName()+":"+user1);
​//多线程下,也是一个对象new Thread(new Runnable() {@Overridepublic void run() {User user = User.getUser();System.out.println(Thread.currentThread().getName()+":"+user);}},"A").start();
​new Thread(() -> {User user = User.getUser();System.out.println(Thread.currentThread().getName()+":"+user);},"B").start();
​}
}
class User{private String name;private Integer age;//2. 创建一个自己的对象private static User user = new User();
​// 1. 私有的构造器private User(){}
​// 3. 定义一个静态方法,返回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;}
}

1.2 懒汉式

懒汉式(第一次获取时创建对象)把类的构造器私有(保证别人不能new)在类中定义一个类变量用于存储对象(注意:此时只定义,不创建)提供一个类方法,在方法中创建并返回对象(要保证只创建一次)
​
注意获取方法需要使用synchronized修饰,以保证只有一个线程可以成功创建出对象
java">public class Demo {public static void main(String[] args) {// 单线程
//        Teacher teacher1 = Teacher.getTeacher();
//        System.out.println(teacher1);
//        Teacher teacher2 = Teacher.getTeacher();
//        System.out.println(teacher2);
​//多线程,不能保证返回的是同一个对象(可以加锁解决该问题)for (int i = 0; i < 100; i++) {new Thread(new Runnable() {@Overridepublic void run() {Teacher teacher1 = Teacher.getTeacher();System.out.println(Thread.currentThread().getName()+":"+teacher1);}}).start();}
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                Teacher teacher1 = Teacher.getTeacher();
//                System.out.println(Thread.currentThread().getName()+":"+teacher1);
//            }
//        },"t1").start();
//
//        new Thread(new Runnable(){
//            @Override
//            public void run() {
//                Teacher teacher2 = Teacher.getTeacher();
//                System.out.println(Thread.currentThread().getName()+":"+teacher2);
//            }
//        },"t2").start();
​
​
​}
​
}
class Teacher{private String name;private Integer age;//1. 私有化构造器private Teacher(){}
​//2. 定义一个类变量,用于存储对象private static Teacher teacher;
​//3. 定义一个静态方法,返回当前类的对象//3.1 同步方法public static synchronized Teacher getTeacher(){if(teacher==null){teacher = new Teacher();}return teacher;}
//    //3.2 同步代码块
//    public static Teacher getTeacher(){
//        if (teacher == null) {
//            synchronized (Teacher.class) {
//                if (teacher == null) {
//                    teacher = new Teacher();
//                }
//            }
//        }
//        return teacher;
//    }}

1.3 枚举实现单例

枚举实现单例直接在枚举中提供一个枚举项就可以实现单例
​
注意Google首席Java架构师、(Effective Java》 一书作者Java集合框架的开创者Joshua Bloch在Effective Java一书中提到单元素的枚举类型,已经成为实现singleton的最佳方法在这种实现方式中,既可以避免多线程同步问题还可以防止通过反射和反序列化来重新创建新的对象在很多优秀的开源代码中,我们经常可以看到使用枚举方式来实现的单例模式
java">public class Demo {public static void main(String[] args) {// 单线程
//        School school1 = School.ShunYi;
//        System.out.println(Thread.currentThread().getName()+"-->"+school1);
//        School school2 = School.ShunYi;
//        System.out.println(Thread.currentThread().getName()+"-->"+school2);
​// 多线程new Thread(()->{School school = School.ShunYi;System.out.println(Thread.currentThread().getName()+":"+school);},"A").start();
​new Thread(()->{School school = School.ShunYi;System.out.println(Thread.currentThread().getName()+":"+school);},"B").start();}
}
enum School{ShunYi
}

二、动态代理

java">/*** ClassName:Star* Description:*  明星接口*      唱歌*      跳舞*/
public interface Star {// 唱歌public String sing(String name);// 跳舞void dance();
}
/*** ClassName:Yct* Description:*  明星实现类*/
public class Yct implements Star{@Overridepublic String sing(String name) {System.out.println("Yct开始唱歌,歌名" + name);return name;}
​@Overridepublic void dance() {System.out.println("Yct开始跳舞");}
}
/*** ClassName:ProxyUtil* Description:*  创建明星的代理类*/
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 {//生成的代理对象,代理的方法,代理方法的参数// 1. 获取方法名(调用代理对象的方法名字)String name = method.getName();// 2. 判断是否是唱歌方法if ("sing".equals(name)){// 3. 执行代理方法System.out.println("经纪人-准备话筒-收钱");}else {System.out.println("经纪人-准备场地-收钱");}Object o = method.invoke(star, args);//调用目标对象的方法return o;}};//3. 生成代理对象Object obj = Proxy.newProxyInstance(//用于指定用哪个类加载器,去加载生成的代理类star.getClass().getClassLoader(),//获取当前类加载器,把类加载到JVM中//用于指定代理类需要实现的接口star.getClass().getInterfaces(),//获取当前类实现的接口,代理有哪些行为//用于指定代理类对应的处理器,处理代理类上的方法调用(用来指定生成的代理对象要干什么事情)invocationHandler);//4. 返回代理对象return (Star) obj;}
​
}
/*** ClassName:ProxyUtilTest* Description:*  测试类*/
public class ProxyUtilTest {public static void main(String[] args) {//1. 创建明星对象Yct yct = new Yct();//2. 创建代理对象Star proxy = new ProxyUtil().createProxy(yct);
​//3. 调用代理对象的方法proxy.dance();proxy.sing("小苹果");}
}

使用代理优化用户管理类

场景某系统有一个用户管理类,包含用户登录,删除用户,查询用户等功能,系统要求统计每个功能的执行耗时情况,以便后期观察程序性能。
需求现在,某个初级程序员已经开发好了该模块,请观察该模块的代码,找出目前存在的问题,并对其进行改造。
​
java">/*** 用户业务接口*/
public interface UserService {// 登录功能void login(String loginName, String passWord) throws Exception;
​// 删除用户void deleteUsers() throws Exception;
​// 查询用户,返回数组的形式。String[] selectUsers() throws Exception;
}
​
/*** 用户业务实现类*/
public class UserServiceImpl implements UserService {@Overridepublic void login(String loginName, String passWord) throws Exception {//  long time1 = System.currentTimeMillis();if ("admin".equals(loginName) && "123456".equals(passWord)) {System.out.println("您登录成功,欢迎光临本系统~");} else {System.out.println("您登录失败,用户名或密码错误~");}Thread.sleep(1000);// long time2 = System.currentTimeMillis();// System.out.println("login方法耗时:" + (time2 - time1));}
​@Overridepublic void deleteUsers() throws Exception {//long time1 = System.currentTimeMillis();System.out.println("成功删除了1万个用户~");Thread.sleep(1500);//long time2 = System.currentTimeMillis();//System.out.println("deleteUsers方法耗时:" + (time2 - time1));}
​@Overridepublic String[] selectUsers() throws Exception {//long time1 = System.currentTimeMillis();System.out.println("查询出了3个用户");String[] names = {"张全蛋", "李二狗", "牛爱花"};Thread.sleep(500);//long time2 = System.currentTimeMillis();//System.out.println("selectUsers方法耗时:" + (time2 - time1));return names;}
}
/*** ClassName:UserServiceProxy* Description:*  生成代理对象* @version 1.0* @Author wang* @Creat 2024/9/13 14:52*/
public class UserServiceProxyUtil {public static UserService createProxy(UserService userService){// 1.获取被代理对象----userService
​// 2.创建代理的业务逻辑InvocationHandler invocationHandler = new InvocationHandler(){@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 2.1 获取调用代理对象的方法名String methodName = method.getName();if(methodName.equals("login")){System.out.println( new Date() + "--" + Arrays.toString(args) + "登录了");}// 2.2 进行计时开始long begin = System.currentTimeMillis();
​// 2.3 调用被代理对象的方法Object o = method.invoke(userService, args);
​// 2.4 进行计时结束long end = System.currentTimeMillis();
​// 2.5 计算差值long time = end - begin;System.out.println("方法" + methodName + "耗时:" + time + "毫秒");
​return o;}};// 3.调用Java的API,生成代理对象UserService userService1 = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(), // 类加载器userService.getClass().getInterfaces(),  // 接口invocationHandler);// 4.返回代理对象return userService1;}
}
/*** 目标:使用动态代理解决实际问题,并掌握使用代理的好处。*/
public class Test {public static void main(String[] args) throws Exception{// 1、创建用户业务对象UserService userService = new UserServiceImpl();// 2、创建代理对象UserService userServiceProxy = UserServiceProxyUtil.createProxy(userService);
​// 2、调用用户业务的功能。userServiceProxy.login("admin", "123456");System.out.println("----------------------------------");
​userServiceProxy.deleteUsers();System.out.println("----------------------------------");
​String[] names = userServiceProxy.selectUsers();System.out.println("查询到的用户是:" + Arrays.toString(names));System.out.println("----------------------------------");
​}
}


http://www.ppmy.cn/devtools/114117.html

相关文章

828华为云征文|华为云Flexus X实例docker部署Rocket.Chat构建属于自己的团队通讯协作平台

828华为云征文&#xff5c;华为云Flexus X实例docker部署Rocket.Chat构建属于自己的团队通讯协作平台 华为云最近正在举办828 B2B企业节&#xff0c;Flexus X实例的促销力度非常大&#xff0c;特别适合那些对算力性能有高要求的小伙伴。如果你有自建MySQL、Redis、Nginx等服务…

闲鱼网页版开放,爬虫的难度指数级降低。

爬虫&#xff0c;可以说是程序员最基础的热手项目。 之前我也一直说阿里系的签名系统搞得太复杂&#xff0c;风控太高&#xff0c;很不利于正常的自动化工具开发&#xff0c;这对于需要阿里应用的客户来说&#xff0c;也是一个很难覆盖的成本支出不是。 当然&#xff0c;我做项…

iPhone 16系列:摄影艺术的全新演绎,探索影像新境界

在科技的浪潮中&#xff0c;智能手机摄影功能的进化从未停歇。 苹果公司即将推出的iPhone 16系列&#xff0c;以其卓越的相机升级和创新特性&#xff0c;再次站在了手机摄影的前沿。 从硬件到软件&#xff0c;从拍照体验到图像处理&#xff0c;iPhone 16系列都展现了其在移动…

python毕业设计基于django+vue医院社区医疗挂号预约综合管理系统7918h-pycharm-flask

目录 技术栈和环境说明预期达到的目标具体实现截图系统设计Python技术介绍django框架介绍flask框架介绍解决的思路性能/安全/负载方面可行性分析论证python-flask核心代码部分展示python-django核心代码部分展示操作可行性技术路线感恩大学老师和同学详细视频演示源码获取 技术…

数据结构与算法-18算法专向(hash)

话题引入&#xff1a; 给你N&#xff08;1<N<10&#xff09;个自然数,每个数的范围为&#xff08;1~10000000000&#xff09;。现在让你以最快的速度判断某一个数是否在这N个数内&#xff0c;不得使用已经封装好的类&#xff0c;该如何实现。 A[] new int[N1]&#xff…

k8s1.27.7部署higress,代理非k8s集群业务

一、简介 Higress是基于阿里内部的Envoy Gateway实践沉淀、以开源Istio + Envoy为核心构建的云原生API网关,实现了流量网关 + 微服务网关 + 安全网关三合一的高集成能力,深度集成Dubbo、Nacos、Sentinel等微服务技术栈,能够帮助用户极大的降低网关的部署及运维成本且能力不…

使用llama.cpp 在推理MiniCPM-1.2B模型

llama.cpp 是一个开源项目&#xff0c;它允许用户在C中实现与LLaMA&#xff08;Large Language Model Meta AI&#xff09;模型的交互。LLaMA模型是由Meta Platforms开发的一种大型语言模型&#xff0c;虽然llama.cpp本身并不包含LLaMA模型的训练代码或模型权重&#xff0c;但它…

SQL数据库(MySQL)

一、在Ubuntu系统下安装MySQL数据库 1、更新软件源&#xff0c;在确保ubuntu系统能正常上网的情况下执行以下命令 sudo apt-get update 2、安装MySQL数据库及相关软件包 # 安装过程中设置root用户的密码 123456 sudo apt-get install mysql-server ​ # 安装访问数据库的客…

scanf()函数的介绍及基础用法

目录 scanf&#xff08;&#xff09;函数的介绍及基础用法 一&#xff1a;头文件 二&#xff1a;一般用法 三&#xff1a;返回值 1. 正整数的情况&#xff1a; 2. 0 的情况&#xff1a; 3. EOF的情况&#xff1a; 四&#xff1a;说明 scanf&#xff08;&#xff09;函数…

IP池对数据爬取工作的帮助

在数据爬取的过程中&#xff0c;IP池&#xff08;也称为代理IP池&#xff09;是一个极为重要的工具&#xff0c;它为数据抓取工作提供了多方面的支持和便利。本文将详细探讨IP池在数据爬取工作中的具体作用&#xff0c;以及它如何帮助提升数据抓取的效率、稳定性和合规性。 一…

新手教学系列——基于统一页面的管理后台设计(一)

在现代企业级应用中,后台管理系统往往是核心组成部分,特别是随着业务规模的扩展,如何在多个后端服务模块的基础上实现统一的登录验证、权限控制和页面管理,成为许多开发者面对的挑战。本文将以实际项目为例,详细讲解如何设计一个多模块的后台管理系统,满足不同服务模块的…

部署Prometheus+Grafana批量监控Linux服务器

在 Linux 服务器上使用 Docker 容器快速部署 Prometheus 和 Grafana 监控系统&#xff0c;同时通过 node_exporter 采集全面的系统性能数据。整个流程涵盖了从环境配置到搭建一个全面监控平台的每个步骤。 一键安装Node Exporter Node Exporter 是 Prometheus 生态系统中的一个…

上线跨境电商商城的步骤

上线一个跨境电商商城涉及多个步骤&#xff0c;从前期准备到上线后的维护。以下是一些关键步骤&#xff1a; 1. 市场调研与规划 目标市场分析&#xff1a;研究目标市场的需求、竞争对手和消费者行为。法律法规&#xff1a;了解并遵守目标市场的法律法规&#xff0c;包括税收、…

Unity携程Coroutine用法

一.携程概述 官方的解释是&#xff0c;携程允许你可以在多个帧中执行任务。在Unity中&#xff0c;携程是一个可以暂停并在后续帧中从暂停处继续执行的方法。 二.携程写法 下面示例使用携程和Update打印前5帧的时间间隔&#xff0c;展示了携程的基础写法 using System.Colle…

CentOS 入门必备基础知识

CentOS 是 Linux 发行版之一&#xff0c;基于 Red Hat Enterprise Linux&#xff08;RHEL&#xff09;&#xff0c;提供免费的企业级操作系统。对于初学者和系统管理员来说&#xff0c;了解 CentOS 的基础知识是必不可少的。本文将带你快速掌握 CentOS 的入门要点&#xff0c;帮…

vue-ts-demo

npm i -g vue/cli PS D:\kwai\vue3\project> vue create vue3-te-demo element-plus 一个 Vue 3 UI 框架 | Element Plus https://element-plus.org/zh-CN/guide/installation.html 安装&#xff1a; npm install element-plus --save 完整引入使用&#xff1a; 使用&…

STM32 芯片启动过程

目录 一、前言二、STM32 的启动模式三、STM32 启动文件分析1、栈 Stack2、堆 Heap3、中断向量表 Vectors3.1 中断响应流程 4、复位程序 Reset_Handler5、中断服务函数6、用户堆栈初始化 四、STM32 启动流程分析1、初始化 SP、PC 及中断向量表2、设置系统时钟3、初始化堆栈并进入…

判断变量是否为有限数字(非无穷大或NaN)math.isfinite() 判断变量是否为无穷大(正无穷大或负无穷大)math.isinf()

【小白从小学Python、C、Java】 【考研初试复试毕业设计】 【Python基础AI数据分析】 判断变量是否为有限数字&#xff08;非无穷大或NaN&#xff09; math.isfinite() 判断变量是否为无穷大&#xff08;正无穷大或负无穷大&#xff09; math.isinf() 请问关于以下代码表述错误…

qt信号与槽(自定义)

自定义信号与槽 在qt里&#xff0c;我们可以自己去定义信号与槽。 这里举个栗子&#xff1a; 信号的定义 在我们类里边定义一个信号&#xff0c;我们需要用signals&#xff1a;来声明&#xff0c;不用再去cpp文件里边定义。而且返回值必须是void&#xff0c;可以有参数。 槽…

构建自己的文生图工具:Python + Stable Diffusion + CUDA

构建自己的文生图工具&#xff1a;Python Stable Diffusion CUDA 前言概述环境搭建安装PyTorch安装Stable Diffusion编写Python代码结论结语 前言 在这个数字化和人工智能飞速发展的时代&#xff0c;图像生成技术正逐渐成为现实。想象一下&#xff0c;只需输入几个关键词&…