Java常用的几种设计模式

单例模式:

        volatile /ˈvɒlətaɪl/  不稳定的;Java中的一个关键字,主要用于修饰变量。其主要作用是保证变量的可见性和有序性。
 

        单例模式有两种模式,懒汉模式和饿汉模式。一个类private修饰其构造方法使其无法对外new出来。

         饿汉模式先声明一个static finaly的变量并在class内部new好一个对象。public对外获取变量的方法。

public class Singleton{private static final instance = new Singleton();private Singleton() {// 私有构造方法}public static Singleton getInstance() {return instance;}
}

         而懒汉模式在声明static finaly变量时为null,在public对外获取变量的方法内加入判断,判断当前变量是否为空,只有为空才new一个对象出来,否则就直接return 变量;

class Singleton{private static final Singleton singleton = null;private Singleton(){}public Singleton getSingleton() {if (singleton==null){this.singleton = new Singleton();}return singleton;}}

        最优解是DCL模式(doublecheck lock)双重锁检,即声明变量时为 static volatile 【变量】 【变量名称】;对外获得方法内先判断【变量名称】是否为空,再判断synchronized 【当前类.class】,再判断变量名称是否为空,为空则 return new对象

        那为什么要用双重锁检和volatile,因为多线程的情况下,会有两个线程同时拿到变量名称为null从而进入锁内,涉及到内存声明时会发生指令重排,1分配对象内存地址,2初始化,3指向内存地址。这三步会变换顺序,1分配到了对象的内存地址,2也拿到地址,直接指向内存地址但是未进行初始化,1直接执行发现变量名称不为空直接返回。volatile的作用就包装变量指令不重排。

        在Spring IoC容器中管理的Bean的默认作用域就是单例的

public class Singleton {  private static volatile Singleton singleton;  private Singleton (){}  public static Singleton getSingleton() {  if (singleton == null) {  synchronized (Singleton.class) {  if (singleton == null) {  singleton = new Singleton();  }  }  }  return singleton;  }  
}

代理模式

        Invocation /ˌɪnvəˈkeɪʃn/      调用          InvocationHandler

        Proxy        /ˈprɒksi/             代理

        Interceptor/ˌɪntəˈseptə(r)/   拦截器      methodInterceptor

        Enhancer  /ɪnˈhɑːnsə(r)/     增强器

        代理模式分为静态代理和动态代理两张模式。

        静态代理,一个业务接口用来完成实际的业务,我这个类实现业务接口,即我结婚这个实际业务。代理类也实现业务接口,但是在代理类声明时构造函数需要传入我这个类(被代理的)。在代理类实现我结婚时业务时完成前后增强业务。

// 代理类,也实现了UserService接口  
public class UserServiceProxy implements UserService {  private UserService userService;  public UserServiceProxy(UserService userService) {  this.userService = userService;  }  @Override  public void addUser(String username, String password) {  // 在调用目标方法前添加一些逻辑  System.out.println("UserServiceProxy: before addUser");  // 调用目标对象的方法  userService.addUser(username, password);  // 在调用目标方法后添加一些逻辑  System.out.println("UserServiceProxy: after addUser");  }  }

        动态代理-jdk动态代理,被代理对象与业务接口不变,实际代理对象需要实现invocationHandler接口,重写invoke在此完成前后增强业务。调用时,需要利用Proxy反射proxy.newProxyInstance来获取当前被代理的对象,传递参数是三个当前被代理对象的classLoad(),interfaces(),还有一个就是传入当前被代理对象UserServiceImpl。

接口

// 定义接口
interface UserService {void addUser(String username);
}

实现

// 实现接口的具体类
class UserServiceImpl implements UserService {public void addUser(String username) {System.out.println("添加用户:" + username);}
}

实现invoctionHandler接口

// 实现InvocationHandler接口
class MyInvocationHandler implements InvocationHandler {// 声明一个私有变量private Object target;// 构造函数public MyInvocationHandler(Object target) {this.target = target;}//  实现InvocationHandler接口的invoke方法,该方法在代理对象调用方法时被触发。public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("动态代理前置操作");Object result = method.invoke(target, args);System.out.println("动态代理后置操作");return result;}
}

代理实现

public class DynamicProxyExample {public static void main(String[] args) {// 创建目标对象UserService userService = new UserServiceImpl();// 创建InvocationHandler实例MyInvocationHandler handler = new MyInvocationHandler(userService);// 创建动态代理对象UserService proxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),userService.getClass().getInterfaces(),handler);// 通过代理对象调用方法proxy.addUser("Alice");}
}

        动态代理-cglib代理,需要实现methodInterceptor接口,重写intercept方法在此完成增强业务。调用时用enhancer。但是不能代理final类,因为cglib是动态创建子类进行代理,final没有子类。这两种动态代理模式也是AOP的原理

import net.sf.cglib.proxy.Enhancer;  
import net.sf.cglib.proxy.MethodInterceptor;  
import net.sf.cglib.proxy.MethodProxy;  
import java.lang.reflect.Method;  
import java.lang.reflect.Modifier;  public class CglibProxyExample implements MethodInterceptor {  private Object target;  public CglibProxyExample(Object target) {  this.target = target;  }  public Object getInstance() {  Enhancer enhancer = new Enhancer();  enhancer.setSuperclass(this.target.getClass());  enhancer.setCallback(this);  return enhancer.create();  }  @Override  public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {  System.out.println("Before method " + method.getName()); // 调用父类的方法,即被代理类的方法  Object result = proxy.invokeSuper(obj, args);         System.out.println("After method " + method.getName());  return result;  }  public static void main(String[] args) {  // 假设MyServiceImpl是MyService的一个实现类 MyService myService = new MyServiceImpl(); CglibProxyExample proxy = new CglibProxyExample(myService);  MyService proxyInstance = (MyService) proxy.getInstance();  proxyInstance.doSomething(); // 调用代理对象的方法,会触发intercept方法  }  
}

工程模式

        简单工厂:一个业务接口,两个实现类。一个工具类,工具类实现对外获取实现类方法。但是需要根据传递参数来返回某一个实现类。接口 = 工具类.获取实现类方法(传递参数)

        工厂模式:对工具类的优化,简单工厂的工具类抽象为一个工厂接口。两个类别的实现类,就分别实现工厂接口返回对应产品。只需知道什么类型就使用对应的实现工厂生产商品。

        抽象工厂:生产电脑业务接口,对应两个实现类。生产操作系统业务接口,对应两个实现类。生产工厂业务接口内有两个方法一个是实现生产系统,一个是生产电脑,两个实现类。工厂实现类,实现对生产什么电脑的实现,生产什么操作系统的实现。这样在声明什么生产工厂的时候就已经能确定生产什么电脑和操作系统了。始于简单工厂,工厂模式是对简单工厂模式的纵向优化,

抽象工厂是对简单工厂的横向优化

// 抽象产品 A  
interface ProductA {  void use();  
}  // 具体产品 A1  
class ProductA1 implements ProductA {  @Override  public void use() {  System.out.println("Using Product A1");  }  
}  // 具体产品 A2  
class ProductA2 implements ProductA {  @Override  public void use() {  System.out.println("Using Product A2");  }  
}  // 抽象产品 B  
interface ProductB {  void use();  
}  // 具体产品 B1  
class ProductB1 implements ProductB {  @Override  public void use() {  System.out.println("Using Product B1");  }  
}  // 具体产品 B2  
class ProductB2 implements ProductB {  @Override  public void use() {  System.out.println("Using Product B2");  }  
}  // 抽象工厂  
interface AbstractFactory {  ProductA createProductA();  ProductB createProductB();  
}  // 具体工厂 1  
class Factory1 implements AbstractFactory {  @Override  public ProductA createProductA() {  return new ProductA1();  }  @Override  public ProductB createProductB() {  return new ProductB1();  }  
}  // 具体工厂 2  
class Factory2 implements AbstractFactory {  @Override  public ProductA createProductA() {  return new ProductA2();  }  @Override  public ProductB createProductB() {  return new ProductB2();  }  
}  // 客户端代码  
public class AbstractFactoryDemo {  public static void main(String[] args) {  // 使用工厂 1 创建产品族  AbstractFactory factory1 = new Factory1();  ProductA product

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

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

相关文章

Methoxy PEG Glutaric Acid可以改善物质的溶解性、稳定性和生物相容性

【试剂详情】 英文名称 mPEG-GA,mPEG-Glutaric Acid, Methoxy PEG GA, Methoxy PEG Glutaric Acid 中文名称 聚乙二醇单甲醚戊二酸, 甲氧基-聚乙二醇-戊二酸 外观性状 由分子量决定,固体或液体 分子量 400&…

浅谈Java的synchronized 锁以及synchronized 的锁升级

在Java中,synchronized关键字用于实现线程间的同步,确保同一时刻只有一个线程能够访问被同步的代码块或方法。当一个线程获得synchronized锁定后,其他试图访问同一锁的线程将被阻塞,直到锁被释放。 synchronized锁有两种基本形式…

为什么说六西格玛培训公司是企业问题的“终结者”

随着六西格玛管理方法的走红,六西格玛培训公司应运而生,致力于帮助企业解决各种核心问题,实现业绩的飞跃。那么,六西格玛培训公司究竟能为企业解决哪些问题?又为什么说六西格玛培训公司是企业问题的“终结者”呢&#…

深入理解全链路监控:技术驱动的业务保障

全链路监控是一种技术手段,通过监控应用程序从用户请求入口到后端服务的完整调用路径,实现对整个系统性能和健康状况的实时掌握。那么,为什么我们需要全链路监控呢? 为什么需要全链路监控 在传统的单一应用系统中,我…

配电站房黄色灯智能识别:原理与应用---豌豆云

今天豌豆云将深入探讨配电站房黄色灯智能识别的原理及其应用,为大家揭示这一技术在电力系统中的作用。 关键词:配电站房;黄色灯;智能识别;原理;应用 在配电站房的日常运维中,黄色灯作为重要的指示信号,对于运维人员来说具有极高…

第47期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区,集成了生成预训练Transformer(GPT)、人工智能生成内容(AIGC)以及大语言模型(LLM)等安全领域应用的知识。在这里,您可以找…

Spring中事务的详细介绍,附带代码示例

文章目录 1、事务的四大特性2、Spring事务的实现方式3、数据库怎么处理事务4、处理事务的方式4、事务的隔离级别5、事务的超时时间6、事务的传播行为7、Spring事务处理方案1、中小项目使用2、大型项目使用AspectJ框架 4、Spring项目实现事务示例5、SpringBoot项目实现事务示例 …

为什么要将原始数据从bufPtr复制到data中

if (memcpy_s(data DWORD_SERIALIZE_SIZE, sizeNewBuf - DWORD_SERIALIZE_SIZE, bufPtr, size)) {delete[] data;return;} 将原始数据从bufPtr复制到data中是为了构建一个完整的待发送数据包,其中包含了额外的头部信息(如数据大小)&#x…

【第3期】PMC对话标杆用户:兆原数通在SeaTunnel的应用实践

📣随着技术快速发展,企业对数据系统的现代化改造需求日益增加。在这种背景下,如何在保持业务连续性的同时,实现数据系统的平滑迁移与升级呢?加入我们的本期技术访谈节目,来听听李洪军老师分享他们如何利用S…

算法题解记录11+++从前序与中序遍历序列构造二叉树(百日筑基)

题目描述: 给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。 示例 1: 输入: preorder [3,9,20,15,7], inorder [9,3,15,20,7] 输出: [3,…

树莓派驱动开发--iic篇(JY901S陀螺仪的三轴角度简单读取)

前言:既然大家都到了这步,想必对驱动开发有着一定的理解啦吧!!那我在前面说一下流程: 修改编译设备树》》》编写编译驱动文件》》》编写编译app文件》》》ftp挂载将前面3复制到树莓派的对应位置》》》加载驱动模块》》…

2024软件测试自动化框架都有哪些?

软件行业正迈向自主、快速、高效的未来。为了跟上这个高速前进的生态系统的步伐,必须加快应用程序的交付时间,但不能以牺牲质量为代价。快速实现质量是必要的,因此质量保证得到了很多关注。为了满足卓越的质量和更快的上市时间的需求&#xf…

策略者模式(代码实践C++/Java/Python)————设计模式学习笔记

文章目录 1 设计目标2 Java2.1 涉及知识点2.2 实现2.2.1 实现两个接口飞行为和叫行为2.2.2 实现Duck抽象基类(把行为接口作为类成员)2.2.3 实现接口飞行为和叫行为的具体行为2.2.4 具体实现鸭子2.2.5 模型调用 3 C(用到了大量C2.0的知识&…

linux nohup命令启动jar包 如何取消nohup日志打印

你好,如果你想在使用nohup启动jar包时不输出日志,可以将标准输出和标准错误重定向到/dev/null,这样日志就不会显示在终端上了。你可以这样做: 日志目录指向/dev/null系统空文件,不可改其他路径必须dev nohup java -ja…

数据库SQL语言实战(三)

删除操作 本篇文章重点在于SQL中的各种删除操作 题目一 删除表中的学号不全是数字的那些错误数据,学号应该是数字组成,不能够包含字母空格等非数字字符。方法之一:用substr函数,例如Substr(sid,1,1)返回学号的第一位&#xff0…

Claude3与GPT4全面对比

Claude 3是由人工智能公司Anthropic推出的最新大语言模型,一经推出就在学术界和普通用户中引起轰动。Claude 3在逻辑推理、数学、编程、多语言理解和视觉等方面表现出色,被认为全面超越了此前的GPT-4模型。一些用户甚至认为Claude 3展现出了自我意识的迹象,但专家们对此持怀疑态…

C++常考面试题(第二篇)

【题目 16】拷贝构造函数的格式和作用,自动调用拷贝构造函数的几种情形? 格式:没有返回值 函数名和类名相同 参数:const person& 类型引用 作用:逐个给成员变量进行赋值三种情形下会调用拷贝构造函数 (1) 当用一…

Zynq学习笔记--AXI 总线仿真(AXI VIP)

目录 1. 概述 2. Simulation with AXI VIP 2.1 axi_vip_pkg 2.2 design_1_axi_vip_0_0_pkg 2.3 参数指定 3. 实例化注意事项 3.1 名称对应关系 3.2 寄存器地址 3.3 block design 1. 概述 AXI Verification IP(AXI VIP)是一种用于验证AXI总线协议的…

ubuntu配置springboot+vue环境

ubuntu 22.04 配置springbootvuenginx(出码生成)项目环境 准备工作:VMware 系统镜像:ubuntu-22.04.1-live-server-amd64.iso 一、jdk-1.8环境配置 sudo apt-get install openjdk-8-jdk #查看安装版本 java -version安装失败出现以下问题,更…

09 SQL进阶 -- SQL高级处理 -- 窗口函数等

1. 窗口函数 1.1 窗口函数概念及基本的使用方法 窗口函数也称为 OLAP 函数。OLAP 是 OnLine AnalyticalProcessing 的简称,意思是对数据库数据进行实时分析处理。 为了便于理解,称之为窗口函数。常规的 SELECT 语句都是对整张表进行查询,而窗口函数可以让我们有选择的去某…