设计模式(小说版)——设计之巅,单例参上

代码之上,设计之巅。

你,静静地趟在耻辱柱上。作为研发标兵的你,纵然曾经凭着大成的 if-else 神功横扫天下,但此刻也被名为屎山的禁制控制得不能动弹。 你的身旁依次挺立着当世5大创建型模式,他们分别是:

1、根据入参生成对象的**⼯⼚模式**

2、创建相关或依赖对象的家族,而无需明确指定具体类的抽象工厂模式

3、封装一个复杂对象的构建过程,并可以按步骤构造的建造者模式

4、通过复制现有的实例来创建新的实例的原型模式

5、全局唯一实例的单例模式

"一坨,你这个代码的蛀虫,今天的代码评审大会就是你的死期!"单例模式的话语,掀起了 耻辱柱下一波又一波的声浪------

"死!死!死!"

你缄默不语,目光缓缓落在了工厂模式身上,现在她早已经不再是以前那个躲在你身后,不敢出现的小女孩了,在众多项目中,她都留下了自己的身影。这一刻你感到很奇怪,明明你已经没有心了,明明在心的地方只是一个空洞,可是为什么你还会有一种心痛的感觉呢?

"哼,你不说话,也没有关系",单例模式轻蔑一笑:"就让我们直接把你的记忆公布于天下吧!"

说罢,单例模式伸出右手食指轻轻往面前一点,一个巨大的圣杯缓缓从空中出现,并且从中流出了大量黑泥似的代码,将你瞬间侵蚀(PS:和冬木市那次一样?),同时你的意识也渐渐模糊......

"一坨,一坨"

"一坨,一坨"

......

你顺着那稚嫩的声音,缓缓睁开双眼,天边的流苏慵懒地撒在你身上,使你感到额外温暖。

"一坨,一坨,你再继续给我讲讲单例模式呗"

我刚刚不是在代码评审大会吗?算了,也没啥关系。你微微一笑,望着身边的小孩温柔地说,"好的,我们刚刚讲到哪里了?一小坨"

"还没开始,你就睡着了"小孩嘟囔着小嘴说道。

"(。・_・。)ノI'm sorry 那我从头和你说起吧~"

单例模式是五大创建者模式之一,该类模式提供创建对象的机制。说人话就是,该类模式的作用就是生产对象的,而单例模式就是生产全局唯一对象的模式。

单例第一式------饿汉式

实现要点:

①:项目启动时就创建这个类的实例

②:私有化构造函数,防止被外部实例化

③:对外提供获取实例的静态方法

java 复制代码
/**
 * 单例模式 - 饿汉式
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2023/11/14
 */
public class Singleton_01 {

    /**
     * 实现要点①:项目启动时就创建这个类的实例
     */
    private static Singleton_01 INSTANCE = new Singleton_01();

    /**
     * 实现要点②:私有化构造函数,防止被外部实例化
     */
    private Singleton_01() {
    }

    /**
     * 实现要点③:对外提供获取实例的静态方法
     *
     * @return {@link Singleton_01}
     */
    public static Singleton_01 getInstance() {
        return INSTANCE;
    }

}

"单例第二式------静态实现"

你袖子一挥,袖口凭空吐出了以下代码

java 复制代码
/**
 * 单例模式 - 静态实现
 * 其本质上也是一个饿汉式单例,在类加载的时候,就实例化一个对象交给自己的引用
 * 可以发散想一想Spring中大名鼎鼎的单例池与该实现的差别
 *
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2023/11/14
 */
public class Singleton_02 {

    private static final Singleton_02 INSTANCE;

    static {
        INSTANCE = new Singleton_02();
    }

    private Singleton_02() {}

    public static Singleton_02 getInstance(){
        return INSTANCE;
    }

}

你能看出它和饿汉式的联系吗?

他本质上也是一个饿汉式单例吧,在类加载的时候,就实例化一个对象交给自己的引用。

是的,很不错呀小朋友~

"单例第三式------使用懒汉模式实现"

本质思想是延迟创建实例的时间,在使用时再创建

实现要点

①:项目启动时不创建这个类的实例

②:私有化构造函数,防止被外部实例化

③:对外提供获取实例的静态方法,并且方法上加锁 - synchronized - 保证线程安全

④:在使用时,才延迟加载这个类,这也是懒汉式名字的由来

java 复制代码
/**
 * 单例模式 - 懒汉式
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2023/11/14
 */
public class Singleton_03 {

    /**
     * 实现要点①:项目启动时不创建这个类的实例
     */
    private static Singleton_03 INSTANCE;

    /**
     * 实现要点②:私有化构造函数,防止被外部实例化
     */
    private Singleton_03() {
    }

    /**
     * 实现要点③:对外提供获取实例的静态方法,并且方法上加锁 - synchronized - 保证线程安全
     *
     * @return {@link Singleton_03}
     */
    public static synchronized Singleton_03 getInstance() {
        // 实现点④:在使用时,才延迟加载这个类,这也是懒汉式名字的由来
        return null != INSTANCE ? INSTANCE : new Singleton_03();
    }

}

"单例第四式------使用内部类实现"

实现要点

①:创建一个静态内部类,该类中有一个静态属性,且为私有的

②:私有化构造函数,防止被外部实例化

③:对外提供获取实例的静态方法

java 复制代码
/**
 * 单例模式 - 内部类实现
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2023/11/14
 */
public class Singleton_04 {

    /**
     * 实现要点①:创建一个静态内部类,该类中有一个静态属性,且为私有的
     * 关注公众号【奔跑的码畜】,一起进步不迷路
     *
     * @author 第七人格
     * @date 2023/11/14
     */
    private static class SingletonInternalClass {
        private static Singleton_04 INSTANCE = new Singleton_04();
    }

    /**
     * 实现要点②:私有化构造函数,防止被外部实例化
     */
    private Singleton_04() {
    }

    /**
     * 实现要点③:对外提供获取实例的静态方法
     *
     * @return {@link Singleton_03}
     */
    public static Singleton_04 getInstance() {
        return SingletonInternalClass.INSTANCE;
    }

}

"对了一小坨,给你留个作业。你知道【使用内部类实现单例】这种方式是懒汉式还是饿汉式呢?"你看了看一小坨,他没有说话,于是你继续讲道:

"单例第五式------使用双重锁校验实现"

实现要点

①:将自己的类作为自己的属性,并且加上volatile关键字

注意: 这里加上volatile关键字的原因是,防止指令重排序,保证单例的唯一性。 因为new这个操作,并不是原子性的,他有3步: 1、分配内存,在jvm堆中分配一段区域 2、初始化对象,在jvm堆中的内存中实例化对象 3、赋值,将对象指向堆中的内存地址 这里如果指令重排序,那么可能2和3的顺序会颠倒,在多线程下那么就可能出现多个对象,违背了单例模式

②:私有化构造函数,防止被外部实例化

③:第一层检查,检查是否有引用指向对象,高并发情况下会有多个线程同时进入

④:锁对象

⑤:第二层检查,防止除了进入的第一个线程的其他线程重复创建对象

⑥:对外提供获取实例的静态方法

java 复制代码
/**
 * 单例模式 - 双重锁校验(DCL)实现
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2023/11/14
 */
public class Singleton_05 {
    /**
     * 实现要点①:将自己的类作为自己的属性,并且加上volatile关键字
     * <p>
     * 注意:
     * 这里加上volatile关键字的原因是,防止指令重排序,保证单例的唯一性。
     * 因为new这个操作,并不是原子性的,他有3步:
     * 1、分配内存,在jvm堆中分配一段区域
     * 2、初始化对象,在jvm堆中的内存中实例化对象
     * 3、赋值,将对象指向堆中的内存地址
     * 这里如果指令重排序,那么可能2和3的顺序会颠倒,在多线程下那么就可能出现多个对象,违背了单例模式
     */
    private static volatile Singleton_05 INSTANCE;

    /**
     * 实现要点②:私有化构造函数,防止被外部实例化
     */
    private Singleton_05() {
    }

    /**
     * 实现要点⑥:对外提供获取实例的静态方法
     *
     * @return {@link Singleton_05}
     */
    public static Singleton_05 getInstance() {
        // 实现要点③:第一层检查,检查是否有引用指向对象,高并发情况下会有多个线程同时进入
        if (null == INSTANCE) {
            // 实现要点④:锁对象
            synchronized (Singleton_05.class) {
                // 实现要点⑤:第二层检查,防止除了进入的第一个线程的其他线程重复创建对象
                if (null == INSTANCE) {
                    INSTANCE = new Singleton_05();
                }
            }
        }
        return INSTANCE;
    }

}

该实现比较复杂,但是使用传播比较广泛。

好久没有讲得这么开心了,以至于你一回神,才发现整个世界仿佛静止了一般,只有那天边的太阳一直散发着暗红色的光,仿佛要滴出血来......

你垂下头,低语道:"单例,用我教你的知识,你是打不开我的心的。"

"大魔头,你以为我没有进步吗?"小孩摇身一变,变为了单例的样子,然后厉声说道。

"单例第六式------使用枚举实现"

实现要点

①:创建一个单元素的枚举

②:引入单例对象作为属性

③:私有化枚举的构造器,并初始化实例

④:对外提供获取实例的静态方法

java 复制代码
/**
 * 单例模式 - 枚举实现
 * 关注公众号【奔跑的码畜】,一起进步不迷路
 *
 * @author 第七人格
 * @date 2023/11/14
 */
public enum Singleton_06 {

    /**
     * 实现要点①:创建一个单元素的枚举
     */
    INSTANCE;
    /**
     * 实现要点②:引入单例对象作为属性
     */
    private Singleton singleton;

    /**
     * 实现要带你点③:私有化枚举的构造器,并初始化实例
     */
    Singleton_06() {
        singleton = new Singleton();
    }

    /**
     * 实现要点④:对外提供获取实例的静态方法
     *
     * @return {@link Singleton}
     */
    public Singleton getInstance() {
        return singleton;
    }


}

该实现方式是 我从《Effective Java》里学会的,无法通过反射创建对象,是特殊的饿汉式。

语毕,电闪雷鸣,大地崩裂,你跌入深渊,慢慢失去了意识......

相关推荐
Miqiuha39 分钟前
建造者设计模式学习
学习·设计模式
神仙别闹1 小时前
基于Java+MySQL实现的(GUI)酒店管理系统(软件工程设计)
java·mysql·软件工程
正在绘制中1 小时前
Java重要面试名词整理(十五):Dubbo
java·面试·dubbo
小羊小羊,遇事不难1 小时前
Error: near “112136084“: syntax
java·服务器·前端
逐星ing1 小时前
【AIGC】使用Java实现Azure语音服务批量转录功能:完整指南
java·人工智能·aigc·语音识别·azure
全栈师2 小时前
WinForm事件遇到异步方法的处理方式
java·开发语言·c#
2301_775602382 小时前
简易内存池
java·服务器·数据库
一二小选手3 小时前
【Redis】万字整理 Redis 非关系型数据库的安装与操作
java·数据库·redis
跳跳的向阳花3 小时前
04、JUC并发编程之:简单概述(四)
java·开发语言·cas·juc·volatile·原子引用·原子整数
潇凝子潇4 小时前
java基于ThreadLocal实现单例模式
java·开发语言·单例模式