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();
            // 检查两个实例是否相同,预期输出为true
            System.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类的单例实例
         */
        // 定义方法,供外部调用,返回b
        public 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:返回类型的值
             */
            @Override
            public 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 唱的是哪首歌。
     */
    @Override
    public String sing(String name) {
        System.out.println("Ycy在舞台上正在唱"+name);

        return "Ycy唱的是:"+name;
    }

    /**
     * 让 Ycy 跳舞。
     * 此方法模拟了 Ycy 在舞台上跳舞的场景,通过控制台输出表现跳舞的场景。
     */
    @Override
    public 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 如果登录失败或线程被中断
     */
    @Override
    public 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 如果删除过程出错或线程被中断
     */
    @Override
    public void deleteUsers() throws Exception {
        System.out.println("成功删除了1万个用户~");
        // 模拟删除操作的处理时间
        Thread.sleep(1500);
    }

    /**
     * 查询用户方法。
     * 返回一个用户名称数组,模拟查询用户的过程。
     * 
     * @return 用户名称数组
     * @throws Exception 如果查询出错或线程被中断
     */
    @Override
    public 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创建InvocationHandler
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public 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.mfbz.cn/a/760295.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

华三(H3C)交换机堆叠配置

目录 一、相关理论 二、实验需求 三、实验组网 四、具体配置 4.1 堆叠配置 4.2 查看堆叠相关配置 4.3 MAD 检测配置 一、相关理论 H3C的堆叠称为IRF&#xff08;Intelligent Resilient Framework&#xff0c;智能弹性架构&#xff09; IRF中每台设备都称为成员设备。成…

架构师篇-7、企业安全架构设计及实践

摘要&#xff1a; 认识企业安全架构企业安全案例分析及实践 内容&#xff1a; 为什么做企业安全架构怎么做好安全架构设计案例实践分析&随堂练 为什么要做企业安全架构 安全是麻烦制造者&#xff1f; 整天提安全需求增加开发工作增加运维要求增加不确定性延后业务上线…

Datawhale机器学习day-1

赛题 在当今科技日新月异的时代&#xff0c;人工智能&#xff08;AI&#xff09;技术正以前所未有的深度和广度渗透到科研领域&#xff0c;特别是在化学及药物研发中展现出了巨大潜力。精准预测分子性质有助于高效筛选出具有优异性能的候选药物。以PROTACs为例&#xff0c;它是…

理想汽车提出3DRealCar:首个大规模3D真实汽车数据集

理想提出3DRealCar&#xff0c;这是第一个大规模 3D 实车数据集&#xff0c;包含 2500 辆在真实场景中拍摄的汽车。我们希望 3DRealCar 可以成为促进汽车相关任务的宝贵资源。 理想汽车提出3DRealCar&#xff1a;首个大规模3D真实汽车数据集! 我们精心策划的高质量3DRealCar数…

基于公有云部署wordpress

云平台选择 腾讯云 阿里云 华为云 项目部署 一、架构讲解 1.1、定义与组成 LNMP是Linux、Nginx、MySQL&#xff08;或MariaDB&#xff09;和PHP&#xff08;或Perl、Python&#xff09;的首字母缩写&#xff0c;代表在Linux系统下使用Nginx作为Web服务器&#xff0c;MySQL作为…

【SGX系列教程】(八)Intel-SGX 官方示例分析(SampleCode)——Seal Unseal

文章目录 一.Seal Unseal原理介绍1.1 Intel SGX supported Sealing Policies 二.源码分析2.1 README2.2 重点代码分析2.2.1 主要代码模块交互流程分析2.2.2 App/App.cpp2.2.3 Enclave_Seal/Enclave_Seal.cpp2.2.4 Enclave_Unseal/Enclave_Unseal.cpp 2.3 总结 三.参考文献四.感…

PMBOK® 第六版 结束项目或阶段

目录 读后感—PMBOK第六版 目录 不论是阶段的收尾还是项目整体的收尾&#xff0c;都应是令人振奋的事。然而&#xff0c;在实际生活中&#xff0c;收尾工作却相当艰难。会遭遇负责人调离、换任&#xff0c;导致不再需要已购产品&#xff1b;项目收尾时对照招标文件或合同&…

基于python的房价多元线性回归分析

1.导入必要的库 import pandas as pd import numpy as np import statsmodels.api as sm from sklearn.model_selection import train_test_split from sklearn.metrics import r2_score import matplotlib.pyplot as plt # 忽略Matplotlib的警告&#xff08;可选&…

SpringBoot实现文章点赞功能

提示&#xff1a;今日是2024年的6月30日&#xff0c;未来的你看到这篇文章&#xff0c;希望你依旧快乐 文章目录 前言 首先在这里前缀部分我就不做要求了,比如说登录信息什么的 数据库表格 这里实现点赞功能&#xff0c;主要是围绕论坛项目完成的 user_info代表用户信息表 for…

20240630每日一题-组合数学-平均分组问题

更多资源请关注纽扣编程微信公众号 将6个小球&#xff0c;其中1个红球&#xff0c;2个黑球&#xff0c;3个白球拍成一列&#xff0c;相同颜色的球没区别&#xff0c;那么有多少种排法&#xff1f; 答案 60种 分析 相同颜色的小球可以看作平均分组&#xff0c;去除对应排序的…

Zookeeper:Zookeeper JavaAPI操作与分布式锁

文章目录 一、Zookeeper JavaAPI操作1、Curator介绍2、创建、查询、修改、删除节点3、Watch事件监听 二、Zookeeper分布式锁原理 一、Zookeeper JavaAPI操作 1、Curator介绍 Curator是Apache Zookeeper的Java客户端。常见的Zookeeper Java API&#xff1a; 原生Java API。ZkC…

基于PHP的酒店管理系统(改进版)

有需要请加文章底部Q哦 可远程调试 基于PHP的酒店管理系统(改进版) 一 介绍 此酒店管理系统(改进版)基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端jquery插件美化。系统角色分为用户和管理员。系统在原有基础上增加了注册登录注销功能&#xff0c;增加预订房间图片…

临时文件上传系统Plik

什么是 Plik &#xff1f; Plik 是一个基于 Go 语言的可扩展且用户友好的临时文件上传系统&#xff08;类似于 Wetransfer&#xff09;。 软件主要特点&#xff1a; 强大的命令行客户端易于使用的 Web 用户界面多个数据后端&#xff1a;文件、OpenStack Swift、S3、Google Clo…

Swift中的二分查找:全面指南

Swift中的二分查找&#xff1a;全面指南 简介 二分查找是计算机科学中的经典算法&#xff0c;被广泛用于在已排序的数组中高效地搜索目标值。与线性查找逐个检查每个元素不同&#xff0c;二分查找不断将搜索区间减半&#xff0c;因此在处理大数据集时要快得多。 在这篇博客中…

java基于ssm+jsp 固定资产管理系统

1前台首页功能模块 固定资产管理系统&#xff0c;在系统首页可以查看首页、设备信息、论坛信息、我的、跳转到后台等内容&#xff0c;如图1所示。 图1前台首页功能界面图 注册&#xff0c;在注册页面可以填写用户名、密码、姓名、性别、头像、身份证、手机等详细内容&#xff…

基于Ollama Python的本地多模态大模型

0&#xff0c;背景 最近测试Ollama&#xff0c;发现之前直接下载开源模型在我电脑上都跑不动的模型&#xff0c;居然也能运行了&#xff08;AMD 7840HS核显/32GB内存&#xff09;&#xff0c;突发奇想那些多模态大模型能不能基于Python接口使用&#xff0c;所以决定尝试一下。…

Qt之Pdb生成及Dump崩溃文件生成与调试(含注释和源码)

文章目录 一、Pdb生成及Dump文件使用示例图1.Pdb文件生成2.Dump文件调试3.参数不全Pdb生成的Dump文件调试 二、个人理解1.生成Pdb文件的方式2.Dump文件不生产的情况 三、源码Pro文件mian.cppMainWindowUi文件 总结 一、Pdb生成及Dump文件使用示例图 1.Pdb文件生成 下图先通过…

Springboot+vue电商平台

管理员权限操作的功能包括管理商家&#xff0c;管理商家星级信息&#xff0c;管理用户&#xff0c;管理商品等。 商家权限操作的功能包括管理商品&#xff0c;回复商品评价&#xff0c;管理商品订单等。 用户权限操作的功能包括查看商家&#xff0c;购买商品&#xff0c;提交…

Django之邮箱注册

目录 一、邮箱验证-环境搭建 1.1、注册流程 1.2、环境搭建 二、封装工具类 三、发送邮件接口开发 四、用户调用发送邮件接口 4.1、Fetch API 4.1.1、GET请求 4.1.2、POST请求 五、完成注册功能 一、邮箱验证-环境搭建 1.1、注册流程 1.2、环境搭建 创建项目 django-a…

Variables Reference for vscode

Predefined variables Visual Studio Code 支持在调试、任务配置文件以及一些特定的设置中使用变量替换。这些变量可以使用 ${variableName} 语法在 launch.json 和 tasks.json 文件的某些键和值字符串中使用。 Predefined variables Visual Studio Code 支持以下预定义变量…
最新文章