JAVA高级进阶14设计模板

第十四天、设计模板

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

  • 一个问题通常有n种解法,其中肯定有一种解法是最优的,这个最优的解法被人总结出来了,称之为设计模式

  • 设计模式有20多种,对应20多种软件开发中会遇到的问题

单例设计模式

单例设计模式

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

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

饿汉式单例

  • 拿对象时,对象早就创建好了。

写法

  • 把类的构造器私有(保证别人不能new)

  • 在类中自己创建一个对象,并赋值到一个变量

  • 定义一个静态方法,返回自己创建的这个对象

  • // 单例类
    public class A {// 2、定义一个类变量记住类的一个对象private static A a = new A();// 1、私有构造器private A(){}// 3、定义一个类方法返回对象public static A getObject(){return a;}
    }

懒汉式单例设计模式

  • 第一次拿对象时,才开始创建对象

写法

  • 把类的构造器私有(保证别人不能new)

  • 在类中定义一个类变量用于存储对象(注意:此时只定义,不创建)

  • 提供一个类方法,在方法中创建并返回对象(要保证只创建一次)

  • /*** 主类,用于演示单例模式的线程安全性。*/
    public class Main {
    ​public static void main(String[] args) {// 获取B类的实例,验证单例模式是否生效B b1 = B.getInstance();B b2 = B.getInstance();// 检查两个实例是否相同,预期输出为trueSystem.out.println(b1 == b2);
    ​// 启动两个线程,每个线程都会尝试获取B类的实例,用于测试单例模式的线程安全性new Thread(() -> {B b = B.getInstance();// 输出线程名和实例引用,用于验证是否为同一个实例System.out.println(Thread.currentThread().getName() + "==" + b);}).start();new Thread(() -> {B b = B.getInstance();// 输出线程名和实例引用,用于验证是否为同一个实例System.out.println(Thread.currentThread().getName() + "==" + b);}).start();}
    }
    /*** 使用懒汉模式实现的单例类,确保线程安全。* 该类的实例化将在第一次调用getInstance方法时完成,并且之后的所有调用都将返回相同的实例。*/
    class B {// 私有静态实例变量,用于存储单例实例// 定义私有静态的变量private static B b;//默认:null
    ​// 私有构造方法,防止外部实例化对象// 私有构造private B() {}/*** 静态方法,用于获取B类的单例实例。* 方法加同步锁,确保在多线程环境下仍然能正确地返回相同的实例。** @return B类的单例实例*/// 定义方法,供外部调用,返回bpublic synchronized static B getInstance() {// 如果尚未实例化,则创建新实例// 在第一次调用时需要创建对象if (b == null) {b = new B();}// 返回已有的实例return b;}
    }

多学一招

  • 使用枚举类实现单例设计模式

  • /*** 主程序入口。* 本程序演示了枚举类型的单例特性。* 通过比较两个枚举实例是否相等,验证了枚举的单例性质。*/
    public static void main(String[] args) {C instance1 = C.INSTANCE; // 获取C的实例C instance2 = C.INSTANCE; // 再次获取C的实例System.out.println(instance1 == instance2); // 比较两个实例是否相同
    }
    ​
    /*** 枚举C,实现了单例模式。* 由于枚举的天然单例属性,INSTANCE是C类的唯一实例。*/
    enum C {INSTANCE; // C类的唯一实例
    }

动态代理

如何为Java对象创建一个代理对象?

  • java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:

  • public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 参数一:用于指定用哪个类加载器,去加载生成的代理类 参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法 参数三:用来指定生成的代理对象要干什么事情

入门案例 :

//测试
public class Demo {//使用动态代理的方式,创建代理对象public static void main(String[] args) {//1.创建被代理对象Star star = new YcyStarImpl();//2.创建动态被代理对象,调用被代理对象Star proxy = StarProxyUtil.getProxy(star);//3.调用代理对象的方法,进行测试proxy.dance();
//        String sing = proxy.sing("");
//        System.out.println("返回:"+sing);System.out.println(proxy.sing("鸡你太美"));}
}//接口
public interface Star {//唱歌String sing(String name);//跳舞void dance();}//创建代理对象
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** 使用动态代理实现明星代理类* 该类提供了一个方法来创建明星的代理对象,代理对象可以在执行明星的方法前后添加额外的操作。*/
public class StarProxyUtil {/*** 创建一个明星的代理对象。* * @param star 需要被代理的明星对象。* @return 返回一个代理对象,该对象在调用明星的方法时会添加额外的操作。*/public static Star getProxy(Star star) {// 创建一个InvocationHandler实现类,用于处理代理对象的方法调用。//1创建InvocationHandler,编写代理对象的方法逻辑InvocationHandler handler = new InvocationHandler() {/*** 当调用代理对象的方法时,该方法会被执行。* * @param proxy 代理对象。* @param method 被调用的方法。* @param args 方法的参数。* @return 方法的返回值。* @throws Throwable 方法执行中抛出的异常。*//*执行代理方法中,要完成的业务逻辑proxy:代理对象  一般不用method:当前执行的方法对象args:当前执行的方法的参数返回object:返回类型的值*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 在执行明星的方法前,添加额外的操作,例如准备场地和收取劳务报酬。//1.非核心功能System.out.println("准备场地,收劳务报酬");// 调用原始明星对象的方法。//2.调用被代理对象方法Object obj = method.invoke(star, args);// 返回方法的执行结果。return obj;}//return method.invoke(star, args);};// 使用动态代理创建明星的代理对象。//2使用Proxy的newProxyInstance方法创建动态代理对象return (Star) Proxy.newProxyInstance(star.getClass().getClassLoader(),star.getClass().getInterfaces(),handler);}//        Star proxy = (Star) Proxy.newProxyInstance(//                star.getClass().getClassLoader(),//                star.getClass().getInterfaces(),//                handler//        );//        return proxy;
}//创建实现类
/*** YcyStarImpl 类实现了 Star 接口,代表了一个名为 Ycy 的明星的具体实现。* 该类提供了唱歌和跳舞的方法,模拟了明星在舞台上的表演行为。*/
public class YcyStarImpl implements Star{/*** 让 Ycy 唱歌。* 此方法模拟了 Ycy 在舞台上唱歌的场景,首先通过控制台输出表现唱歌的场景,然后返回唱歌的曲目名称。** @param name 歌曲名称,表示 Ycy 正在演唱的歌曲。* @return 返回一个字符串,表明 Ycy 唱的是哪首歌。*/@Overridepublic String sing(String name) {System.out.println("Ycy在舞台上正在唱"+name);return "Ycy唱的是:"+name;}/*** 让 Ycy 跳舞。* 此方法模拟了 Ycy 在舞台上跳舞的场景,通过控制台输出表现跳舞的场景。*/@Overridepublic void dance() {System.out.println("Ycy在舞台上跳舞");}
}

应用案例 :

/*** 测试类,用于演示用户服务的代理模式应用。*/
public class Test {/*** 程序入口。* @param args 命令行参数* @throws Exception 如果操作失败抛出异常*/public static void main(String[] args) throws Exception {// 创建 UserService 实例,用于后续的用户操作// 1、创建用户业务对象UserService userService = new UserServiceImpl();// 获取 UserService 的代理实例,用于动态增强 UserService 的功能// 2、调用用户业务的功能。UserService proxy = UserServiceProxy.getProxy(userService);// 通过代理实例调用登录方法,演示基本的用户操作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("----------------------------------");}
}/*** 用户服务接口定义了用户模块的基本操作。* 包括用户登录、删除用户和查询用户信息等功能。*/
public interface UserService {/*** 用户登录功能。* * @param loginName 用户登录名,用于标识用户。* @param passWord 用户密码,用于验证用户身份。* @throws Exception 如果登录名或密码不正确,或登录过程中出现其他错误,抛出异常。*/// 登录功能void login(String loginName, String passWord) throws Exception;/*** 删除用户功能。* * @throws Exception 如果删除过程中出现错误,抛出异常。*/// 删除用户void deleteUsers() throws Exception;/*** 查询用户信息功能。* * @return 返回用户信息数组,每个元素代表一个用户。* @throws Exception 如果查询过程中出现错误,抛出异常。*/// 查询用户,返回数组的形式。String[] selectUsers() throws Exception;
}/*** 用户服务的实现类,提供用户登录、删除用户和查询用户等功能。*/
public class UserServiceImpl implements UserService {/*** 用户登录方法。* 模拟登录验证过程,通过比较用户名和密码来确定登录是否成功。* * @param loginName 用户名* @param passWord  密码* @throws Exception 如果登录失败或线程被中断*/@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);}/*** 删除用户方法。* 模拟删除用户的过程,并给出反馈信息。* * @throws Exception 如果删除过程出错或线程被中断*/@Overridepublic void deleteUsers() throws Exception {System.out.println("成功删除了1万个用户~");// 模拟删除操作的处理时间Thread.sleep(1500);}/*** 查询用户方法。* 返回一个用户名称数组,模拟查询用户的过程。* * @return 用户名称数组* @throws Exception 如果查询出错或线程被中断*/@Overridepublic String[] selectUsers() throws Exception {System.out.println("查询出了3个用户");String[] names = {"张全蛋", "李二狗", "牛爱花"};// 模拟查询操作的处理时间Thread.sleep(500);return names;}
}import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** 用户服务代理类,用于生成UserService接口的动态代理实例。* 动态代理在运行时创建一个类,该类实现指定的接口,并将调用转发给指定的调用处理程序。*/
public class UserServiceProxy {/*** 生成UserService接口的动态代理实例。* 动态代理的作用是在不修改原有业务逻辑的情况下,增加额外的功能,例如日志、事务等。** @param userService 被代理的UserService实例。* @return 返回一个代理对象,该对象实现了UserService接口,并在方法调用前后添加了日志记录功能。*//*创建动态代理对象返回值UserService参数:被代理对象UserService*/public static UserService getProxy(UserService userService) {// 创建一个InvocationHandler实例,用于处理方法调用。//1创建InvocationHandlerInvocationHandler handler = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 记录方法开始执行的时间。// 记录开始时间long beg = System.currentTimeMillis();// 调用被代理对象的相同方法。// 执行被代理对象Object invoke = method.invoke(userService, args);// 记录方法执行结束的时间,并计算执行耗时。// 记录结束时间计算总耗时long end = System.currentTimeMillis();// 输出方法执行的日志信息,包括方法名和执行耗时。System.out.println("执行"+method.getName()+"方法,总耗时:"+(end-beg)+"毫秒");// 返回方法执行的结果。// 返回值(和被代理对象方法返回值一样return invoke;}};// 使用动态代理生成UserService接口的实现类实例。// 这里的参数分别指定了类加载器、接口列表和调用处理程序。//2.使用proxy的new方法创建代理对象UserService proxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),userService.getClass().getInterfaces(),handler);// 返回代理对象。return proxy;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/38275.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SA 注册流程

目录 1. UE开机后按照3GPP TS 38.104定义的Synchronization Raster搜索特定频点 2.UE尝试检测PSS/SSS&#xff0c;取得下行时钟同步&#xff0c;并获取小区的PCI&#xff1b;如果失败则转步骤1搜索下一个频点&#xff1b;否则继续后续步骤&#xff1b; 3.解析Mib&#xff0c;…

WDG看门狗

1 WDG 1.1 简介 WDG是看门狗定时器&#xff08;Watchdog Timer&#xff09;的缩写&#xff0c;它是一种用于计算机和嵌入式系统中的定时器&#xff0c;用来检测和恢复系统故障。 看门狗就像是一个忠诚的宠物狗&#xff0c;它时刻盯着你的程序&#xff0c;确保它们正常运行。…

SpringBoot启动出错:无法访问org.springframework.boot.autoconfigure.SpringBootApplication

无法访问org.springframework.boot.autoconfigure.SpringBootApplication类文件具有错误的版本 61.0&#xff0c;应为 52.0请删除该文件或确保该文件位于正确的类路径子目录中。 出现该问题是由于版本不兼容&#xff0c; 在pom.xml文件中&#xff0c;修改版本为2开头即可

一个用于Win的自动复制文本的工具:Auto_Copy

自动复制工具 这是一个用在 Windows 上的的小工具,会将你选中的任何文本保存下来,可以通过点击右键粘贴选中内容。 一、灵感来源: 在使用Mobaxterm时,我注意到其软件中具备选中即自动复制和右键直接粘贴的功能。但是,这种选中自动复制的功能仅在软件内部有效。由于这一功…

【wsl2】工作在nat模式安装miniconda

刚好当前是root 用户这里wsl说自己nat模式,不用系统代理 wsl: A localhost proxy configuration was detected but not mirrored into WSL. WSL in NAT mode does not support localhost proxies. Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.153.1-microsoft-standard-W…

数字图像处理之【高斯金字塔】与【拉普拉斯金字塔】

数字图像处理之【高斯金字塔】与【拉普拉斯金字塔】 1.1 什么是高斯金字塔&#xff1f; 高斯金字塔&#xff08;Gaussian Pyramid&#xff09;是一种多分辨率图像表示方法&#xff0c;用于图像处理和计算机视觉领域。它通过对原始图像进行一系列的高斯平滑和下采样操作&#x…

最新docker仓库镜像

目前下面的docker仓库镜像源还能使用。 vi /etc/docker/daemon.json添加如下配置{"registry-mirrors": ["https://hub.uuuadc.top", "https://docker.anyhub.us.kg", "https://dockerhub.jobcher.com", "https://dockerhub.icu&…

RTMP推流到SRS流媒体服务器消息处理

RTMP推流到SRS流媒体服务器消息处理 SRS和客户端是怎么交换消息的&#xff1f;各个消息有什么作用&#xff1f;握手成功后&#xff0c;SRS和客户端进行消息交换&#xff0c;对应wiresharek这部分截图&#xff1a; 流程图&#xff08;之前画的&#xff0c;可能不够详细&#xf…

IPC进程通信:QNX

引言 在现代操作系统中&#xff0c;进程间通信&#xff08;IPC&#xff09;机制是实现进程间数据交换和同步的关键技术。IPC允许多个进程共享信息和资源&#xff0c;从而协同工作完成复杂任务。在QNX Neutrino系统中&#xff0c;IPC尤为重要&#xff0c;因为QNX主要面向实时系…

在Linux (Ubuntu 16) 下安装LabVIEW

用户尝试在Ubuntu 16操作系统上安装LabVIEW&#xff0c;但找不到合适的安装文件来支持Ubuntu。已经下载了运行时文件&#xff0c;并尝试将.rpm包转换为.deb包并安装在Ubuntu上。然而&#xff0c;安装完成后&#xff0c;没有在应用程序中看到LabVIEW的图标。 用户希望能够在Ubu…

【操作系统】内存管理——页面分配策略(个人笔记)

学习日期&#xff1a;2024.6.28 内容摘要&#xff1a;页面分配策略和内存映射文件&#xff0c;内存映射文件 页面分配置换策略 基本概念 驻留集&#xff0c;指请求分页存储管理中给进程分配的物理块的集合&#xff0c;在采用了虚拟存储技术的系统中&#xff0c;驻留集大小一…

springcloud第4季 分布式事务seata实现AT模式案例2【经典案例】

一 seata案例 1.1 背景说明 本案例使用seata的at模式&#xff0c;模拟分布式事务场景&#xff1a;【下订单&#xff0c;减库存&#xff0c;扣余额&#xff0c;改状态】 AT模式原理&#xff1a;是2pc方案的演变&#xff0c; 一阶段&#xff1a;业务数据和回滚日志记录在同一…

力扣第217题“存在重复元素”

在本篇文章中&#xff0c;我们将详细解读力扣第217题“存在重复元素”。通过学习本篇文章&#xff0c;读者将掌握如何使用哈希表和排序方法来解决这一问题&#xff0c;并了解相关的复杂度分析和模拟面试问答。每种方法都将配以详细的解释&#xff0c;以便于理解。 问题描述 力…

Android studio 打包低版本的Android项目报错

一、报错内容 Execution failed for task :app:packageRelease. > A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade> com.android.ide.common.signing.KeytoolException: Failed to read key key0 from store "…

static修饰的对象在内存中的存储及其用法

一、static修饰的变量在内存中的存储位置 static关键字无论是在C语言还是C中都有着极其重要的作用&#xff0c;那么对于static来说&#xff0c;它修饰的对象是存储在内存的哪个位置呢&#xff1f;它的作用与它在内存中的位置有什么联系&#xff1f;还有它都适用于哪些场景&…

15.数据库简介+MySQl使用+SQL语句

文章目录 数据库简述一.数据库简介DB1.定义:2.DBMS数据库管理系统3.数据库分类 二.MySQL的安装1.安装步骤2.MySQL数据库图形管理工具3.mysql程序常用命令4.MySQL字符集及字符序5.Navicat快捷键操作 三.MySQL数据库基本操作 .........................................表管理一.…

RPC远程过程调用--Thrift

RPC远程过程调用–Thrift 简介 Thrift是一个由Facebook开发的轻量级、跨语言的远程服务调用框架&#xff0c;后进入Apache开源项目。支持通过自身接口定义语言IDL定义RPC接口和数据类型&#xff0c;然后通过编译器生成不同语言代码&#xff0c;用于构建抽象易用、可互操作的R…

黄子韬揭秘徐艺洋与EXO的不解之缘

黄子韬揭秘&#xff1a;徐艺洋与EXO的不解之缘在娱乐圈的繁华与喧嚣中&#xff0c;总有一些不为人知的故事&#xff0c;它们或温馨、或励志&#xff0c;或是感叹命运的奇妙。近日&#xff0c;黄子韬在一档热门综艺节目中意外爆料&#xff0c;揭开了徐艺洋与EXO之间鲜为人知的秘…

ffmpeg使用bmp编码器把bgr24编码为bmp图像

version #define LIBAVCODEC_VERSION_MAJOR 60 #define LIBAVCODEC_VERSION_MINOR 15 #define LIBAVCODEC_VERSION_MICRO 100 note 不使用AVOutputFormat code void CFfmpegOps::EncodeBGR24ToBMP(const char* infile, const char* width_str, const char* height_str…

IT之家最新科技热点

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…