设计模式-创建型模式(详解)

创建型模式

单例模式

一个类只允许创建一个对象,称为单例。

单例体现:配置类、连接池、全局计数器、id生成器、日志对象。

懒汉式
  1. (线程不安全) 单例:【不可用】

用到该单例对象的时候再创建。但存在很大问题,单线程下这段代码没有问题,但是在多线程下有很大问题。

public class LazyMan {private LazyMan(){};public static LazyMan lazyMan;   public static LazyMan getInstance(){if (lazyMan==null){lazyMan = new LazyMan();   //用到该单例对象的时候再创建,这里没加锁,如果多个线程进入,会并发产生多个实例}return lazyMan;}
}
  1. (线程安全)单例:【不推荐使用】

同步方法

缺点:效率低,每次getInstance时都要同步处理,存在性能问题,实际开发不推荐

public class LazyMan {private LazyMan(){};   //私有化构造函数,防止外部实例化public static LazyMan lazyMan;   public static synchroized LazyMan getInstance(){  //加锁if (lazyMan==null){lazyMan = new LazyMan();   //用到该单例对象的时候再创建}return lazyMan;}
}

双检锁(线程安全):【推荐使用】

  • 实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),不为空则直接return实例化对象。
  • 利用volatile关键字保证了可见性,利用双重检查机制减少了同步带来的性能损耗。
public class Singleton {private static volatile Singleton instance;// 私有构造函数,防止外部实例化private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}
饿汉式

(静态常量)【可用】

类一旦加载就创建一个单例,保证在调用getInstance方法之前单例已经存在,即没有延迟加载,这种饿汉式单例会造成空间浪费。

public class Hungry {private Hungry(){}private final static Hungry HUNGRY = new Hungry();    //在类内部就创建了一个静态对象,并且get方法返回该对象public static Hungry getInstance(){return HUNGRY;}
}
//或者 静态代码块形式
public class Hungry {static{private final static Hungry HUNGRY = new Hungry();    }     private Hungry(){}public static Hungry getInstance(){return HUNGRY;}
}Hungry in1=Hungry.getInstance()
Hungry in2=Hungry.getInstance()        //in1==in2
静态内部类
  • (线程安全)单例:【推荐使用】
  • 不仅线程安全,还实现了延迟加载
public class Inner {private Inner(){}//直到调用 getInstance() 方法之前,Inner 实例都不会被创建,实现了延迟初始化public static Inner getInstance(){return InnerClass.INNER;}private static class InnerClass{          private static final Inner INNER = new Inner();  //静态字段只会在类加载时被初始化一次,线程安全}
}
枚举
  • (线程安全)【推荐使用】不仅线程安全,还能防止反序列化导致重新创建新的对象
class SingletonEnum{// 1、创建一个枚举public enum CreateInstance{// 枚举实例,底层变量定义是public static final,因此它在 JVM 中只会被初始化一次,并且是线程安全的INSTANCE;private SingletonEnum instance;// 保证不能在类外部通过new构造器来构造对象private CreateInstance() {instance = new SingletonEnum();System.out.println(Thread.currentThread().getName());}// 创建一个公共的方法,由实例调用返回单例类public SingletonEnum getInstance() {return instance;}}public static void main(string[] args){Singleton instance = CreateInstance.INSTANCE.getInstance();singleton instance2= CreateInstance.INSTANCE.getInstance();System.out.println(instance == instance2);  //输出 true}
}

原型模式

通过拷贝来创建新的对象,而不是通过实例化一个类,减少创建对象的成本,适用于创建对象成本高,需要大量相似对象的情况。

  • Java 的 clone 仅是浅拷贝,默写场景需要 使用深拷贝避免共享数据的导致错乱
  • 在 Spring 中,将 Bean 的作用范围设置为 prototype,这样每次从容器中获取 Bean 时,都会返回一个新的实例。

一个简单的原型模式实现例子如下

先创建一个原型类:

public class Prototype implements Cloneable {     //一个原型类,只需要实现Cloneable接口,覆写clone方法@Overridepublic Object clone() throws CloneNotSupportedException { Prototype proto = (Prototype) super.clone();		   //因为此处的重点是super.clone()这句话return proto;}
}
Prototype pro=new Prototype();
Prototype pro1=(Prototype)pro.clone(); //克隆 二者地址不同
//不管深浅,拷贝出来的对象的地址是不一样的,只是若对象里面有引用,那么深浅拷贝会不一样
@Data
public class Prototype implements Cloneable, Serializable {private static final long serialVersionUID = 1L;private String string;private SerializableObject obj;/* 浅拷贝 */public Object clone() throws CloneNotSupportedException {Prototype proto = (Prototype) super.clone();return proto;}/* 深拷贝 */public Object deepClone() throws IOException, ClassNotFoundException {/* 写入当前对象的二进制流 */ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(this);/* 读出二进制流产生的新对象 */ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bis);return ois.readObject();}}
class SerializableObject implements Serializable {private static final long serialVersionUID = 1L;
}

工厂模式

简单工厂

简单工厂模式通过传入的不同的参数来控制创建哪个具体产品。它的实现较为简单,但不够灵活,违反了开放封闭原则。

  • 抽象产品接口: 定义了产品的规范,描述了产品的主要特性和功能
  • 具体产品实现类: 实现或者继承抽象产品的子类
  • 简单工厂: 提供了创建产品的方法,调用者通过该方法来获取产品。
// 产品接口
public interface Product {void use();
}
// 具体产品A
public class ConcreteProductA implements Product {@Overridepublic void use() {System.out.println("Using ConcreteProductA");}
}
// 具体产品B
public class ConcreteProductB implements Product {@Overridepublic void use() {System.out.println("Using ConcreteProductB");}
}// 简单工厂类
public class SimpleFactory {public static Product createProduct(String type) {switch (type) {case "A":return new ConcreteProductA();case "B":return new ConcreteProductB();default:throw new IllegalArgumentException("Unknown product type");}}
}
// 客户端代码
public class Client {public static void main(String[] args) {Product productA = SimpleFactory.createProduct("A");productA.use(); // Output: Using ConcreteProductAProduct productB = SimpleFactory.createProduct("B");productB.use(); // Output: Using ConcreteProductB}
}
工厂方法

一个具体的工厂类负责生产一种产品

抽象工厂==>具体工厂

抽象产品==>具体产品(由具体工厂创建)

// 抽象产品
interface Product {void use();
}
// 具体产品A
class ConcreteProductA implements Product {public void use() {System.out.println("Using ConcreteProductA");}
}
// 具体产品B
class ConcreteProductB implements Product {public void use() {System.out.println("Using ConcreteProductB");}
}// 抽象工厂
interface Factory {Product createProduct();
}
// 具体工厂A
class ConcreteFactoryA implements Factory {public Product createProduct() {return new ConcreteProductA();}
}
// 具体工厂B
class ConcreteFactoryB implements Factory {public Product createProduct() {return new ConcreteProductB();}
}// 使用工厂方法创建产品
public class Client {public static void main(String[] args) {new ConcreteFactoryA().createProduct();new ConcreteFactoryB().createProduct() ;}
}
抽象工厂
  • 是工厂方法的一种变体,创建一系列相关或相互依赖对象的接口,即生产一系列产品
  • 给具体工厂类 添加一个工厂接口,使得工厂类可以多实现
// 抽象产品A
public interface ProductA {void use();
}
// 具体产品A1
public class ConcreteProductA1 implements ProductA {@Overridepublic void use() {System.out.println("Using ConcreteProductA1");}
}
// 具体产品A2
public class ConcreteProductA2 implements ProductA {@Overridepublic void use() {System.out.println("Using ConcreteProductA2");}
}// 抽象产品B
public interface ProductB {void eat();
}
// 具体产品B1
public class ConcreteProductB1 implements ProductB {@Overridepublic void eat() {System.out.println("Eating ConcreteProductB1");}
}
// 具体产品B2
public class ConcreteProductB2 implements ProductB {@Overridepublic void eat() {System.out.println("Eating ConcreteProductB2");}
}// 抽象工厂
public interface AbstractFactory {ProductA createProductA();ProductB createProductB();
}// 具体工厂1
public class ConcreteFactory1 implements AbstractFactory {@Overridepublic ProductA createProductA() {return new ConcreteProductA1();}@Overridepublic ProductB createProductB() {return new ConcreteProductB1();}
}// 具体工厂2
public class ConcreteFactory2 implements AbstractFactory {@Overridepublic ProductA createProductA() {return new ConcreteProductA2();}@Overridepublic ProductB createProductB() {return new ConcreteProductB2();}
}// 使用抽象工厂创建产品
public class Client {public static void main(String[] args) {AbstractFactory factory1 = new ConcreteFactory1();ProductA productA1 = factory1.createProductA();ProductB productB1 = factory1.createProductB();productA1.use();productB1.eat();AbstractFactory factory2 = new ConcreteFactory2();ProductA productA2 = factory2.createProductA();ProductB productB2 = factory2.createProductB();productA2.use();productB2.eat();}
}
建造者模式

建造者模式使用相同的代码基础构建不同类型的对象,通过将对象构建过程分解为多个较小的步骤来实现此目的,如StringBuilder

两个主要组成部分:建造者和产品 建造者是负责构建产品的类,产品则是最终构建的对象

例如 hutool 内的 ExecutorBuilder 就提供了建造者模式创建线程池的方法

public ExecutorService buildTaskPool() {
return ExecutorBuilder.create().setCorePoolSize(10).setMaxPoolSize(20).setWorkQueue(new LinkedBlockingQueue<>(100)).setKeepAliveTime(3L, TimeUnit.SECONDS).setThreadFactory(new ThreadFactoryBuilder().setNamePrefix("task-pool-").build()).build();
}
public class Product {       //最终构建的对象,即产品private String partA;private String partB;private String partC;public void setPartA(String partA) {this.partA = partA;}public void setPartB(String partB) {this.partB = partB;} public void setPartC(String partC) {this.partC = partC;}// other product-related methods}public interface Builder {   //Builder接口或抽象类,定义了构建过程的关键步骤void buildPartA();void buildPartB();void buildPartC();Product getResult();
}public class ConcreteBuilder implements Builder {  //实现了Builder接口中定义的方法,以构建具体的Product对象private Product product = new Product();public void buildPartA() {product.setPartA("Part A");}public void buildPartB() {product.setPartB("Part B");}public void buildPartC() {product.setPartC("Part C");}    public Product getResult() {return product;} 
}public class Director {      //指导类,它负责使用Builder对象来构建最终的Product对象private Builder builder;public Director(Builder builder) {  //实现依赖倒置原则,依赖于抽象this.builder = builder; }public void construct() {   //确保Product对象按照指定的顺序创建builder.buildPartA();builder.buildPartB();builder.buildPartC();}
}Builder builder = new ConcreteBuilder();   //创建建造者
Director director = new Director(builder);  //创建指导
director.construct();     
Product product = builder.getResult();
//这将构建一个Product对象,并将其存储在product变量中。

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

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

相关文章

什么是BI?有哪些应用场景

BI&#xff08;Business Intelligence&#xff0c;商业智能&#xff09;是通过技术手段对海量业务数据进行采集、整合、分析和可视化的过程&#xff0c;旨在帮助企业从数据中获取洞察&#xff0c;支持决策。其核心是通过工具&#xff08;如Quick BI&#xff09;将原始数据转化为…

从零开始:使用Vite和Vue.js搭建一个空项目

进入node.js官网 https://nodejs.org/zh-cn 下载node.js 点击进行安装&#xff0c; 完成之后&#xff0c;按住shift鼠标右键&#xff0c;打开powershell窗口 输入node -v &#xff0c;出现版本号就是成功了 node -v 接下来&#xff0c;打开设置&#xff0c;搜索开发者设置&…

Redis 核心数据类型及典型使用场景详解

在日常开发中&#xff0c;Redis 不仅是缓存利器&#xff0c;更是一套高性能的数据结构服务。你是否真的了解 Redis 提供的五种核心数据类型&#xff1f;它们各自的底层结构和适用场景又有哪些差异&#xff1f;本篇博客将深入解析 Redis 的数据类型及其典型应用&#xff0c;助你…

threejs webVR获取相机正前方向量

通常获取相机正前方可以使用camera.getWorldDirection(new Vector3()) 函数来得到&#xff0c;但是在threejs0.139.2版本中进入VR后使用上面函数获取的数据是固定不变的&#xff0c;不管是否旋转了头盔&#xff0c;经过一番研究发现必须使用renderer.xr.getCamera() 此函数获取…

华为OD-2024年E卷-字符统计及重排[100分] -- python

问题描述&#xff1a; 给出一个仅包含字母的字符串&#xff0c;不包含空格&#xff0c;统计字符串中各个字母(区分大小写)出现的次数&#xff0c;并按照字母出现次数从大到小的顺序输出各个字母及其出现次数。如果次数相同&#xff0c;按照自然顺序进行排序&#xff0c;且小写…

MCP(模型上下文协议)协议和Http协议对比

MCP&#xff08;Model Context Protocol&#xff0c;模型上下文协议&#xff09;和 HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;是两种定位完全不同的协议&#xff0c;主要区别如下&#xff1a; 1. 核心定位 HTTP 通用网络通信协议&am…

C++打印乘法口诀表

int main()​​&#xff1a; 这是C 程序的入口点。每个C 程序都必须有一个 main 函数&#xff0c;程序从这里开始执行。 ​​外层 for 循环​​&#xff1a; for (int i 1; i < 10; i) { int i 1&#xff1a;定义并初始化循环变量 i 为 1。这里的 i 代表乘法表中的行…

RoGBAG 与 MCAP

RoGBAG 和 MCAP 都是机器人领域常用的二进制数据格式&#xff0c;用于存储传感器数据、控制命令和状态信息。两者主要区别在于&#xff1a; RoGBAG&#xff1a;ROS 1/2 的标准日志格式&#xff0c;采用 LZF/LZ4 压缩&#xff0c;适合中小型数据集 MCAP&#xff1a;新一代机器人…

Ubuntu 空间占用情况排查常用命令

查看当前目录总大小及子目录占用详情 du -sh * | sort -hr ​​du​​&#xff1a;磁盘使用统计命令​​-s​​&#xff1a;显示每个参数的总计&#xff08;不递归子目录&#xff09;​​-h​​&#xff1a;以人类可读格式&#xff08;KB/MB/GB&#xff09;显示​​*​​&…

C语言编译优化实战与技巧

一.概述 1.C语言编译优化介绍 C语言编译优化是提升程序性能的核心手段&#xff0c;涉及从源代码到机器码的多层次转换&#xff0c;下面从优化级别、常用技术、内存管理、指令调度等多个维度详细介绍。 2.编译器优化等级&#xff08;GCC/Clang&#xff09; 二.常用优化技术 1…

Seq2Seq理解

Seq2Seq理解 写在前面&#xff1a;学习Seq2Seq由于前面底子没打好导致理解起来非常困难&#xff0c;今天索性全部搞懂逻辑部分&#xff0c;后续我会把所学的一些算法全部以理解代码的形式发布出来&#xff0c;课程代码内容全部来自李沐老师的视频&#xff0c;再次感谢&#xf…

旅游规划智能体之ReAct Agent实战

引言 本文将系统性地介绍如何运用ReAct框架构建旅游规划智能体&#xff0c;通过LangChain的create_react_agent方法实现智能决策和多步骤任务处理。ReAct框架作为现代AI Agent开发的核心技术之一&#xff0c;为构建具备复杂推理能力的智能系统提供了重要的理论基础和实践指导。…

组合模式深度解析:Java设计模式实战指南与树形结构处理架构设计

组合模式深度解析&#xff1a;Java设计模式实战指南与树形结构处理架构设计 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 总有一行代码&#xff0c;能点亮万千星辰。 &#x1f50d; 在技术的宇宙中&#xff0c;我愿做永不停歇的探索者。 ✨ 用…

PHP设计模式实战:领域驱动设计与六边形架构

在前三篇关于电子商务系统、API服务和微服务架构的基础上,我们将深入探讨如何运用领域驱动设计(DDD)和六边形架构(Hexagonal Architecture)构建更加清晰、可维护的业务系统。随着业务复杂度增加,传统的分层架构往往难以清晰地表达业务逻辑,而DDD提供了一套方法论来解决这一问…

为什么在1080p的屏幕下,通常观看4K视频要比1080p的视频来的清晰?

一、分辨率与像素密度的底层逻辑 4K与1080p的像素差异 4K分辨率通常为38402160&#xff08;约830万像素&#xff09;&#xff0c;而1080p为19201080&#xff08;约207万像素&#xff09;&#xff0c;4K像素数量是1080p的4倍。当4K视频在1080p屏幕上播放时&#xff0c;需要将4倍…

C++ Json-Rpc框架 项目逻辑设计

Server • RpcServer&#xff1a;rpc功能模块与⽹络通信部分结合 RpcServer分为两部分 1.提供函数调用服务的服务端 2.提供服务注册的客户端 对内提供好rpc服务的路由关系管理map<method,服务描述对象>&#xff0c;以及rpc请求消息的分发处理函数。给Dispatcher提供onRpc…

Agent开发相关工具

LangChain LangChain LangGraph LangGraph LangSmith GraphRAG RAGFlow what-is-graphrag Dify n8n vLLM Model Context Protocol AutoGen CodeMirror Milvus Chroma

进程管理(一)

一. 进程的基本信息 1.1 进程的概念、组成及信息 1.1.1 概念 进程的概念与程序相对&#xff0c;程序是静态的而进程是动态的&#xff0c;一个程序执行多次会有多个不同的进程 1.1.2 组成 PCB&#xff08;程序控制块&#xff09;&#xff1a; 是一种保存下列信息的数据结构&…

k8s 中 cpu 核数的理解

物理核还是逻辑核 在 Kubernetes&#xff08;k8s&#xff09;编排文件&#xff08;如 Pod 或 Deployment 的 YAML 文件&#xff09;中设置的 CPU 核数&#xff0c;针对的是逻辑核数&#xff08;Logical Cores&#xff09;&#xff0c;而非物理核数&#xff08;Physical Cores&…

arcpy数据分析自动化(2)

数据处理 在提取数据后&#xff0c;我们需要对字段进行标准化处理&#xff0c;例如统一土地利用类型的命名。 # 定义字段映射字典 field_mapping {"Residential": "居住用地","Commercial": "商业用地","Industrial": &q…