设计模式

注意:括号中为八股在每次面试中出现的概率

单例设计模式(357/1759=20.3%)

单例设计模式是一种创建型设计模式,核心思想是保证一个类在整个应用中只有一个实例,并提供一个全局的访问入口。它常用于管理共享资源,比如配置、缓存或数据库连接等场景。接下来,我将详细介绍单例模式的实现过程,以常用的懒汉式加双重检查锁定为例说明其设计原理:

首先,为了避免外部直接创建对象,我们将该类的构造方法设为私有。这一步确保了实例只能在类内部被创建,从而杜绝了通过 new 关键字产生多个实例的可能性。

其次,在类内部定义一个私有的静态变量,该变量用于存储单例实例。初始状态下,它的值为 null,这意味着实例尚未被创建。

然后,我们提供一个公共的静态方法来获取该实例。该方法首先判断静态变量是否为 null,如果不为 null,则说明实例已存在,直接返回即可;如果为 null,则进入同步代码块。在同步块内,再次检查实例是否为 null,若仍为 null,则创建该实例。通过双重检查锁定的方式,我们既保证了多线程环境下的线程安全,又避免了每次访问实例时都进行同步操作带来的性能开销。

最后,当实例创建完成后,后续调用获取实例的方法时,都会直接返回该唯一的实例。这样不仅保证了全局唯一性,也提高了系统性能,因为同步操作只在第一次创建实例时执行。

如何记忆:

1.联想记忆法

场景:

单身公寓

解释 :

单例模式就像一栋单身公寓,整栋楼只能住一个人(唯一实例)。为了保证这一点:

公寓的门钥匙(构造方法)被房东(类)保管,不允许租客(外部代码)私自复制钥匙。

房东在房间里放了一张床(静态变量),用来标记是否已经有人入住。

如果有人敲门(调用获取实例的方法),房东会先看看房间里是否有人(第一次检查),如果没有,他会锁上门再确认一次(双重检查锁定),然后安排人入住。

拓展:

1.单例模式的经典实现方式对比

(1)饿汉式(静态常量)

public class Singleton {
    private static final Singleton INSTANCE = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

特点:类加载时立即初始化,线程安全。

优点:实现简单,无并发问题。

缺点:即使未使用也会占用资源,可能造成浪费。

(2)懒汉式(线程安全)

public class Singleton {
    private static Singleton instance;
    private Singleton() {}
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

特点:首次调用时初始化,通过synchronized保证线程安全。

缺点:每次调用getInstance()都会同步,性能较低。

(3)双重检查锁(Double-Check Locking)

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

关键点:通过两次判空减少同步开销,volatile防止指令重排。

适用场景:高并发环境下的延迟初始化。

(4)静态内部类

public class Singleton {
    private Singleton() {}
    private static class Holder {
        static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}

优势:利用类加载机制保证线程安全,同时实现延迟初始化。

推荐场景:兼顾性能与安全性的通用方案。

(5)枚举单例

public enum Singleton {
    INSTANCE;
    // 添加业务方法
}

特点:天然线程安全,支持序列化,防止反射攻击。

最佳实践:Effective Java推荐的实现方式。

2.Spring 单例 Bean 存在线程安全问题吗?

在多线程环境下,单例 Bean 是否会出现线程安全问题,主要取决于该 Bean 是否维护了可变的共享状态。换句话说,如果一个单例 Bean 中包含可变成员变量,并且多个线程会同时对这些变量进行读写操作,那么就有可能发生线程安全问题。反之,如果该 Bean 不存在可变共享数据,或者所有操作都在内部做好了线程安全的保护,就不会出现线程安全隐患。

常见的处理思路包括:

保持 Bean 的无状态化:尽量只使用不可变成员变量,或者在需要存储状态时,将这些状态放到方法内部,避免多线程同时访问同一份数据。

使用 ThreadLocal:为每个线程提供独立的变量副本,从而隔离线程之间的共享数据,避免竞争。

加锁或其他同步手段:如果必须在 Bean 中操作可变状态,可以使用 synchronized、ReentrantLock 等机制来保证并发操作的安全性。

因此,如果你的单例 Bean 仅用于提供一些纯计算或无状态的业务逻辑(例如常见的 Dao、Service 等),通常无需额外处理多线程问题;但如果其中包含可变共享资源,就需要通过合适的线程安全措施来保证应用的正确性和稳定性。

工厂设计模式(411/1759=23.4%)

工厂设计模式是一种创建型设计模式,它主要用于封装对象的创建过程,从而使客户端不需要直接实例化具体的类,而是通过工厂来获取对象。这种模式提高了代码的灵活性和扩展性。接下来我会详细讲述工厂设计模式的实现过程。

当我们需要创建一个产品对象时,

首先,我们会定义一个抽象的产品接口或者抽象类,明确规定产品的公共行为和属性。这样,无论后续添加多少具体产品,客户端都可以通过同一接口来操作它们。

其次,我们实现具体的产品类,这些类分别实现了抽象产品接口,包含各自独特的业务逻辑和功能。

接着,我们定义一个工厂接口或者抽象工厂类,声明一个创建产品对象的方法。该方法的职责是隐藏具体产品对象的实例化过程,客户端只需要调用这个方法即可获得产品实例。

然后,我们实现具体的工厂类,它们根据传入的参数或内部逻辑,决定创建哪一种具体的产品对象。这样,具体产品的创建细节完全被封装在工厂内部,客户端无需关心对象的创建过程。

最后,当客户端需要一个产品时,它只需调用工厂提供的创建方法,获得对应的产品对象,并直接使用。这种方式不仅降低了客户端与具体产品实现之间的耦合,也方便了系统的扩展和维护。

如何记忆:

1.联想记忆法

场景:

餐厅点餐

解释 :

抽象产品 :菜单上的菜品名称和描述(比如“牛排”)。

具体产品 :厨房实际制作的牛排、意大利面等具体菜品。

抽象工厂 :服务员的职责是接受订单并通知厨房制作菜品。

具体工厂 :厨师根据订单制作具体的菜品。

客户端 :顾客只需要点餐,不需要知道牛排是怎么做出来的。

拓展:

1.分类与实现方式

(1)简单工厂模式(Simple Factory)

简单工厂模式并不是一种正式的设计模式,但它是最基础的形式。它通过一个工厂类根据传入的参数决定创建哪种具体产品。

public class SimpleFactory {
    public static Product createProduct(String type) {
        if ("A".equals(type)) {
            return new ConcreteProductA();
        } else if ("B".equals(type)) {
            return new ConcreteProductB();
        }
        throw new IllegalArgumentException("Unknown type");
    }
}

// 抽象产品
public interface Product {
    void use();
}

// 具体产品A
public class ConcreteProductA implements Product {
    @Override
    public void use() {
        System.out.println("Using Product A");
    }
}

// 具体产品B
public class ConcreteProductB implements Product {
    @Override
    public void use() {
        System.out.println("Using Product B");
    }
}

特点:集中管理对象创建逻辑,易于理解和实现。

缺点:违反开闭原则,新增产品时需修改工厂类。

(2)工厂方法模式(Factory Method)

工厂方法模式通过定

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

【神品八股】1759篇面经精华 文章被收录于专栏

神哥引路,稳稳起步!!早鸟特惠,仅剩177名额!晚了就涨到29.9了! 核心亮点: 1.数据驱动,精准高频:基于1759篇面经、24139道八股题,精准提炼真实高频八股。 2.科学记忆,高效掌握:融合科学记忆法和面试表达技巧,记得住,说得出。 3.提升思维,掌握财商:不仅可学习八股,更可教你变现,3个月赚不回购买价,全额退。 适宜人群: 在校生、社招求职者及自学者。

全部评论
接好运
1 回复 分享
发布于 2025-03-31 16:35 河南
神哥会出高频场景题吗
1 回复 分享
发布于 2025-03-10 19:06 四川
完结撒花
1 回复 分享
发布于 2025-03-07 10:12 江苏
生产者消费者可以当作设计模式吗,并不在23种设计模式里面
1 回复 分享
发布于 2025-03-06 16:47 山东
好耶
1 回复 分享
发布于 2025-03-06 16:26 江苏
刚自己找完设计模式的八股就更新了
1 回复 分享
发布于 2025-03-06 10:08 山西
加起来才60%+啊,剩下概率稍微低一点点的呢
点赞 回复 分享
发布于 01-24 09:15 宁夏

相关推荐

01-08 11:19
已编辑
深圳职业技术学院 护士
我是从大一下学期5月开始转互联网的,原因很简单,对本专业的就业薪资与前景非常不满,而我特别想赚钱,所以选了互联网,而又因为带我的师兄都是前端,所以阴差阳错就做了前端当时的梦想就是进腾讯,进腾讯,进腾讯!大一下学期学了3个月的前端的基础知识后,开始参加学校工作室的考核,当时整个暑假都没回家,跑去自习室和考研的同学坐一下,那段时间我敢说我去的比大多数人早,走的比大多数人晚,把所有的时间精力都扑在做工作室考核上面,不过结果非常遗憾,我竞争不过两个超级大神,最后进不去了(广工的anyview是我一身之痛)不过进了物理学院的软件组,有了自己的工位还有好多转码师兄的指导后,开始长达半年的实验室之旅......在这半年,我几乎没有上课,没有去哪里玩,我像一个被写了程序的机器人一样,7点半起床,去实验室学前端,一直到晚上10点 11点。我太笨了,太笨了,学东西太慢了,coderwhy的网课看了一遍又一遍,项目代码写了一遍又一遍,红宝书也是一遍一遍的看......就这样,过完了这打了鸡血的半年,寒假也只回去十天左右,然后就到了24年的3月我开始焦虑,非常非常的焦虑与害怕,因为我开始刷牛客了,开始去网上了解各种就业信息,一大堆负面信息朝我涌来,我不知道怎么区分就全盘接收前端已死,互联网完蛋了,非科班别想了,双非别想了,没有学历就等于判了死刑......有半个月我半夜都会被吓醒,后面想到的一个破局之路就是刷实习,大量的堆实习,弥补我双非的学历,非科班的专业带来的巨大劣势于是开始转战图书馆,找了考研的人一起坐,他们什么时候去我就什么时候去,开始背八股,前端三件套,框架,工程化,算法,计算机网络......这些对我当时的我来说太多了太多了,也太难太难了,越看越焦虑,越焦虑我越不敢停下来,每天晚上都要去跑5公里来让自己平静下来就这样过了一个多月,我准备的七七八八开始投实习了,第一次面试,我整个人紧张的止不住的颤抖,喝了一杯又一杯的水,上了一次又一次的厕所,皇天不负有心人,在四月底找到了自己的第一份外包实习,很大程度地缓解了我的焦虑,回去休息了半个月五一后入职,实习了一个星期左右,感觉太难受了,工作氛围及其压抑,同事也是感觉都乱来的,而且喜欢打压我,我在写算法的时候,他们老说不用写这个,这些是大厂才要的,你又进不去大厂...... 后面我只能偷偷跑楼下写,过了小半个月我实在呆不下去就离职回学校了,第一段实习就这样结束了,而且老板不给我发工资......于是我开始在学校二次沉淀了,开始大量刷leetcode 代码随想录 codetop 准备更强的项目 更深入地背八股,于是一直学啊学啊,那个暑假就回去两个星期学车,其他时间都呆在学校的实验室里24年8月开始全面投实习,拿了古茗 卓望数码的offer,本来打算去杭州古茗的,结果美团打电话说面试通过,阴差阳错地去了上海美团,开启了自己的第一段实习刚去没多久,还没适应那里的生活工作环境,学校传来噩耗,外出实习被抓到了,老师逼我回去,说不回去毕不了业,我当时听完电话后,整个人崩溃了,我跑去公司楼道间一直哭,我不甘心,我太不甘心了,我不甘心来之不易的实习泡汤,幸好后面申请了一门实验课重修,如愿留在上海于是就在上海美团实习了四个月,一直到了25年1月,我开始飘了,我感觉自己牛逼坏了,感觉美团平台不够高,想去更高的腾讯和字节,放弃了美团核心部门,而且高转正率的机会,选择了离职,当时还在牛客写了一篇长文于是回家休息到年后,2月多开始回学校全力准备暑期实习,一直面一直挂,直到5月份才找到字节的实习,这三个月是我最痛苦最煎熬的日子,我的自信心被不断的击碎,一直面一直挂,而身边朋友开始接连上岸,我开始怀疑自己,开始后悔当时的决定,开始觉得自己就是一个看不清自己的傻逼然后呢,4月底 在没招了,万念俱灰的时候,字节约面试了,一点也不想复习,裸面,结果阴差阳错给我干进去了5月中开始字节的实习,虽然压力比较大,但还可以接受,平平稳稳能干了三个月,自我感觉良好,以为转正稳了,结果到八月初的时候,通知转正失败,当时天都塌了,然后开始找其他部门的机会,后面活水成功,去另一个部门实习了一个月,其实转正概率也不小,但是当时也是心比天高,以为自己牛逼坏了,所以选择离职秋招9月中开始全面秋招,结果大家也知道,秋招大溃败,各种终面挂 hr面挂 排序挂 有时候也不知道为什么挂,问题也都答出来了,算法也都写出来了,但就是挂哈哈哈哈其中很多时间都是在打字节的复活赛,反复仰卧起坐,反复鞭尸,后面感觉面字节跟回家和亲戚聊天一样,他会问什么我都知道,甚至我可以抢答,面完还能聊天开点玩笑......在12月中的时候,字节又约面了,阴差阳错又到了三面,结果还给整挂了,当时确实破防的要死,然后转部门面试,本来打算拒绝的,因为实在太心累,太折磨了,但还是咬咬牙去面了,然后莫名其妙问的也就那些,三面还整了几道脑筋急转弯,本来以为又要挂了,结果过了,据说是因为我的竞争对手三面ai作弊被发现了,所以只面了她16分钟,所以就轮到我了,我也不用hr面直接审批,然后审批半天,隔天直接谈薪,hr开了个我拒绝不了的薪资,而且表达出来的意思是无论其他开多少字节都能match的意思,诚意满满回望这两年多的经历,真的是非常非常感慨,我想和大家说的是每个人都会有属于自己花期,只是时间的问题而已,努力踏实做事,终究会有回报!我也曾在这条路上迷茫、焦虑、崩溃与无助,但我做的唯一的一件事情就是,整理好心情,重新出发,坚持下去,光脚的不怕穿鞋的,拼了兄弟们!
码农索隆:我感觉兄弟你所处在环境已经算是双非中比较好的了,双非院校中很少有实验室,也鲜有师哥师姐会带着去学习,而你也很争气抓住了这次机会,一飞冲天
现在前端的就业环境真的很...
点赞 评论 收藏
分享
评论
12
42
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务