【Day14-单例设计模式动态代理】

news/2024/9/21 22:06:28/

 单例设计模式

 什么是设计模式(Design pattern) ?

  • 一个问题通常有n种解法,其中肯定有一种解法是最优的,这个最优的解法被人总结出来了,称之为设计模式
  • 设计模式20多种,对应20多种软件开发中会遇到的问题。

单例设计模式 

作用:确保一个类只有一个对象。 

场景:计算机中的回收站、任务管理器、Java中的Runtime类等

写法

  • 把类的构造器私有(保证别人不能new)
  • 在类中自己创建一个对象,并赋值到一个变量
  • 定义一个静态方法,返回自己创建的这个对象

java">/*
单例设计模式作用:确保一个类只有一个对象。场景:计算机中的回收站、任务管理器、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">/*
单例设计模式作用:确保一个类只有一个对象。场景:计算机中的回收站、任务管理器、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">/*
单例设计模式作用:确保一个类只有一个对象。场景:计算机中的回收站、任务管理器、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类:提供了为对象产生代理对象的方法: 

java">/*
接口
*/
public interface Star {String sing(String name);void dance();
}
java">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;}
}
java">public class Cln implements Star{@Overridepublic String sing(String name) {System.out.println("ccc唱:" + name);return name;}@Overridepublic void dance() {System.out.println("ccc💃💃💃💃💃");}
}
java">public class ProxyUtilTest {public static void main(String[] args) {//创建被代理对象Cln cln = new Cln();//生成代理对象Star star = ProxyUtil.createProxy(cln);//调用代理对象,让被代理对象干活star.sing("大香蕉");star.dance();}
}

案例:

使用代理优化用户管理类

场景

某系统有一个用户管理类,包含用户登录,删除用户,查询用户等功能,系统要求统计每个功能的执行耗时情况,以便后期观察程序性能。

需求

现在,某个初级程序员已经开发好了该模块,请观察该模块的代码,找出目前存在的问题,并对其进行改造。
java">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;}
}
java">/*** 用户业务实现类*/
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;}
}

java">/*** 用户业务接口*/
public interface UserService {// 登录功能void login(String loginName, String passWord) throws Exception;// 删除用户void deleteUsers() throws Exception;// 查询用户,返回数组的形式。String[] selectUsers() throws Exception;
}
java">/*** 目标:使用动态代理解决实际问题,并掌握使用代理的好处。*/
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("----------------------------------");}
}


http://www.ppmy.cn/news/1528573.html

相关文章

【LLM】吴恩达『微调大模型』代码笔记(03_Instruction_tuning_lab_student)【如何进行推断函数定义】

关注B站可以观看更多实战教学视频:hallo128的个人空间 【LLM】吴恩达『微调大模型』代码笔记(03_Instruction_tuning_lab_student) 指令微调(代码详解-代码及输出结果) 1. 推断函数定义 # 通过 AutoTokenizer 从预训…

TCP四大拥塞控制算法总结

四大算法:1.慢启动,2.拥塞避免,3.拥塞发生,4.快速恢复。 慢启动: 首先连接建好的开始先初始化拥塞窗口cwnd大小为1,表明可以传一个MSS大小的数据。 每当收到一个ACK,cwnd大小加一&#xff0c…

二级C语言2024-3易错题

1 结构 一个C语言程序是由( )。 A. 一个主程序和若干子程序组成 B. 函数组成 C. 若干过程组成 D. 若干子程序组成 一个C语言程序是由多个部分组成的,其中最核心的部分是函数。在C语言中,函数是实现特定功能的代码块,…

人才有约,职为你:颐年集团携手粤荣学校共绘养老行业的美好未来

摘要:广州市白云区粤荣职业培训学校成功举办“人才有约,职为你”颐年集团养老机构线下招聘会 2024年9月19日下午2点30分,广州市白云区金骊城二楼热闹非凡。粤荣职业培训学校携手颐年集团,共同举办了主题为“人才有约,…

Redis基本命令详解

1. 基本命令 命令不区分大小写,而key是区分大小写的 # select 数据库间的切换 数据库共计16个 127.0.0.1:6379> select 1# dbsize 返回当前数据库的 key 的数量 127.0.0.1:6379[1]> dbsize# keys * 查看数据库所有的key 127.0.0.1:6379[1]> keys *# fl…

前端web端项目运行的时候没有ip访问地址

我们发现 没有netWork 的地址 导致 团队内其他同学无法打开我们的地址 进行访问 在page.json 中的运行 指令中 添加 --host 记得加上空格 这样我们就可以看到这个地址了 团队其他同学 就可以访问我们这个地址了

今日leetCode 18. 四数之和

18. 四数之和 给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复)&#xff…

【MPC】无人机模型预测控制复现Data-Driven MPC for Quadrotors项目(Part 1)

无人机模型预测控制复现Data-Driven MPC for Quadrotors项目 参考链接背景和问题方法与贡献实验结果安装ROS创建工作空间下载RotorS仿真器源码和依赖创建Python虚拟环境下载data_driven_mpc仓库代码下载并配置ACADO求解器下载并配置ACADO求解器的Python接口下载并配置rpg_quadr…