您现在的位置是:首页 >技术交流 >【设计模式】| 修炼内功 | 23种设计模式——单例模式网站首页技术交流

【设计模式】| 修炼内功 | 23种设计模式——单例模式

狮子也疯狂 2024-06-14 17:17:37
简介【设计模式】| 修炼内功 | 23种设计模式——单例模式

设计模式如同织锦之艺术,精心构筑,展示优美。
学习设计模式,犹如追逐清晨的曙光,扉页掀开了人生的新篇章。当你学会设计模式的奥秘,就如同走进了灯火通明的城市,丰富多彩的建筑,让你大开眼界,拥有了整个世界般的视野。
设计模式如同一面明镜,让人自省和反思,看清自己的不足;同时也是一盏明灯,照亮你前行的道路。
它像是一座桥,将你从学生的世界带入到职业的殿堂,让你稳步前行。
学习设计模式,让你的代码更有灵魂,更有温度,更有品味。
它是一种成长,是一种提升,更是一种追求卓越的态度。
让我们一起学习设计模式,饱览编程之美!

快来和?一起学习设计模式叭,修炼内功无上心法!!!
在这里插入图片描述

一. ? 设计模式?知道

23种设计模式可以按照其功能划分为三类,分别是创建型模式、结构型模式和行为型模式,具体如下:

1. 创建型模式:

  • 工厂方法模式(Factory Method)
  • 抽象工厂模式(Abstract Factory)
  • 单例模式(Singleton)
  • 建造者模式(Builder)
  • 原型模式(Prototype)

2. 结构型模式:

  • 适配器模式(Adapter)
  • 桥接模式(Bridge)
  • 组合模式(Composite)
  • 装饰器模式(Decorator)
  • 外观模式(Facade)
  • 享元模式(Flyweight)
  • 代理模式(Proxy)

3. 行为型模式:

  • 职责链模式(Chain of Responsibility)
  • 命令模式(Command)
  • 解释器模式(Interpreter)
  • 迭代器模式(Iterator)
  • 中介者模式(Mediator)
  • 备忘录模式(Memento)
  • 观察者模式(Observer)
  • 状态模式(State)
  • 策略模式(Strategy)
  • 模板方法模式(Template Method)
  • 访问者模式(Visitor)

以上23种设计模式都是经典的设计模式,它们被广泛应用于软件开发中,以提高代码的可复用性、扩展性、灵活性和可维护性。
今天我们先来研究一下单例模式

二. ? 目标掌握?单例模式

Ⅰ. 懒汉模式

延迟加载,只有在真正使用的时候,才开始实例化

  1. 线程安全问题

  2. double check 加锁优化

  3. 编译器(JIT),CPU 有可能对指令进行重排序,导致使用到尚未初始化的实例,可以通过添加volatile 关键字进行修饰对于volatile 修饰的字段,可以防止指令重排

class LazySingleton{
    //  加volatile 防止多线程情况下,CPU 有可能对指令进行重排序
    private volatile static LazySingleton instance;
    private LazySingleton(){}
    public  static LazySingleton getInstance(){
        if (instance == null){
            synchronized (LazySingleton.class){
                if (instance == null){
                    instance = new LazySingleton();
                }
            }
        }
        return instance;
    }

}

这样输出的实例都会是同一个,如图:

image-20230423104901755

Ⅱ. 饿汉模式

类加载的 初始化阶段就完成了 实例的初始化 。本质上就是借助于JVM类加载机制,保证实例的唯一性。

类加载过程:

  1. 加载二进制数据到内存中,生成对应的Class数据结构

  2. 连接: a.验证,b.准备 (给类的静态成员变量赋默认值),c.解析

  3. 初始化: 给类的静态变量赋初值

class HungarySingleton{
    private static HungarySingleton instance = new HungarySingleton();
//    使用私有构造函数,防止从外部实例化实例。
    private HungarySingleton (){};
    public static   HungarySingleton getInstance(){
        return instance;
    }

}

只有在真正使用对应的类时,才会触发初始化 如(当前类是启动类即main函数所在类,直接进行new 操作,访问静态属性、访问静态方 法,用反射访问类,初始化一个类的子类等.)

image-20230423112544508

Ⅲ. 静态内部类

静态内部类模式将单例对象的创建和getInstance()方法的调用分开,只有在第一次调用getInstance()方法时,才会触发静态内部类的加载,进而创建单例对象。由于一个类的静态内部类只会被加载一次,因此静态内部类模式也是线程安全的。

  1. 本质上是利用类的加载机制来保证线程安全
  2. 只有在实际使用的时候,才会触发类的初始化,所以也是懒加载的一种形式
public class InnerClassSingletonTest {
    public static void main(String[] args) {
        new Thread(()->{
            InnerClassSingleton instance = InnerClassSingleton.getInstance();
            System.out.println(instance);
        }
        ).start();
        new Thread(()->{
            InnerClassSingleton instance = InnerClassSingleton.getInstance();
            System.out.println(instance);
        }
        ).start();

    }

}
// 静态内部类模式
class InnerClassSingleton{
    private static class InnerClassSingleHolder{
        private static InnerClassSingleton instance = new InnerClassSingleton();
    }
    private InnerClassSingleton(){}
    public static InnerClassSingleton getInstance(){
        return InnerClassSingleHolder.instance;
    }
}

即使是在多线程模式下,获取的也是同一个实例,运行结果如下:

image-20230423113006567

Ⅳ. 枚举类型

是一种利用枚举类型实现的单例模式,它可以保证在任何情况下都只有一个实例对象存在。枚举类型在Java中天生是单例的,所以枚举实现的单例模式非常简单,同时也具有线程安全、防止反射和序列化攻击的特点。但是,它不太灵活,不能继承其他类或者实现接口。

public enum EnumSingleton {
    INSTANCE;

    public static EnumSingleton getInstance() {
        return INSTANCE;
    }
}

Ⅴ. 使用场景

  • 要求生成唯一序列号的环境;

  • 在整个项目中需要一个共享访问点或共享数据,例如一个Web页面上的计数器,可以不用把每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的;

  • 创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源;

  • 需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(当然,也可以直接声明为static的方式)。

三. ? 学习总结?

本文分享了23种设计模式之一的单例模式,小伙伴们一起干起来叭!!!

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。