当前位置: 首页 > news >正文

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

创建型模式

单例模式

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

单例体现:配置类、连接池、全局计数器、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.xdnf.cn/news/1034011.html

相关文章:

  • 11_13小结
  • 每天一个前端小知识 Day 1
  • 迁移数据库服务器和应用服务器步骤
  • Vue3中v-bind=“$attrs“应用实例
  • 最小费用最大流算法
  • 架构下的最终瓶颈:数据库如何破局?
  • ARDM:一款国产跨平台的Redis管理工具
  • React项目常用目录结构
  • 细节致胜:如何重塑反向海淘用户体验
  • MongoDB 事务有哪些限制和注意事项?
  • 系统学习·PHP语言
  • sqli-labs靶场46-53关(综合)
  • c 语言如何将 uint8_t *tg_pFrames的数据给 uint8_t **ppJpg
  • YOLO11中的C3K2模块
  • AORSA关键文件及参数解释
  • Go语言---闭包
  • golang字符串拼接
  • 【MFC 突然被问到,怎么实现一个星星按钮】原来问的是继承xs
  • CTF题目:Apache Flink目录遍历漏洞实战及CVE-2020-17519漏洞分析
  • 标准库转hal库
  • Kafka - 并发消费拉取数据过少故障分析
  • PyTorch张量操作中dim参数的核心原理与应用技巧:
  • 【机械视觉】Halcon—【十三、实例找各个区域面积和中心点】
  • 大模型成长过程-预训练tokenizer
  • 2.5 Rviz使用教程
  • 人工智能学习13-Numpy-规律数组生成
  • pytorch基本运算-梯度运算:requires_grad_(True)和backward()
  • 多个项目的信息流如何统一与整合
  • Spring AI Chat Tool Calling 指南
  • MySQL使用EXPLAIN命令查看SQL的执行计划