最近在准备面试,发现单例模式几乎是每个面试官必问的设计模式。今天我就来聊聊单例模式到底是什么,为什么面试官这么爱问,以及如何用实际例子把它讲清楚。
什么是单例模式?简单来说就是“独一无二”
想象一下公司里的CEO职位——整个公司只能有一个CEO,不能同时存在两个。单例模式就是这个道理:确保一个类只有一个实例,并且提供全局访问点。
为什么需要单例?因为有些情况下,多个实例会造成资源浪费或者状态不一致。比如全局配置管理、缓存系统、登录弹窗这些场景,只需要一个实例就够了。
面试真题:实现基于LocalStorage的Storage单例
这道题我最近在面试中真的遇到过!题目要求实现一个Storage类,让它成为单例,并基于LocalStorage封装setItem和getItem方法。
先来看看代码实现
class Storage {
// 静态属性,用于存储唯一实例
static instance = null;
// 获取单例实例的静态方法
static getInstance() {
if (!Storage.instance) {
Storage.instance = new Storage();
}
return Storage.instance;
}
// 设置存储项
setItem(key, value) {
localStorage.setItem(key, JSON.stringify(value));
}
// 获取存储项
getItem(key) {
const value = localStorage.getItem(key);
return value ? JSON.parse(value) : null;
}
}
// 使用示例
const storage1 = Storage.getInstance();
const storage2 = Storage.getInstance();
console.log(storage1 === storage2); // true,确实是同一个实例
storage1.setItem('name', '小明');
console.log(storage2.getItem('name')); // '小明'
面试官为什么爱考这道题?
这道题看似简单,但实际上考察了很多知识点:
- 对单例模式的理解:是否能正确实现单例模式
- LocalStorage的操作:是否熟悉本地存储API
- 数据序列化:是否知道LocalStorage只能存字符串,需要JSON序列化
- 代码封装能力:是否能设计出易用的API
真实应用场景:登录弹窗的优化
单例模式不只是面试题,在实际项目中也非常有用。比如实现登录弹窗:
class LoginModal {
static instance = null;
static getInstance() {
if (!LoginModal.instance) {
LoginModal.instance = new LoginModal();
}
return LoginModal.instance;
}
constructor() {
this.modal = this.createModal();
this.isShowing = false;
}
createModal() {
// 创建弹窗的DOM元素和样式
const modal = document.createElement('div');
modal.innerHTML = `
<div class="modal-content">
<h2>登录</h2>
<form>
<input type="text" placeholder="用户名">
<input type="password" placeholder="密码">
<button type="submit">登录</button>
</form>
</div>
`;
modal.style.display = 'none';
document.body.appendChild(modal);
return modal;
}
show() {
this.modal.style.display = 'block';
this.isShowing = true;
}
hide() {
this.modal.style.display = 'none';
this.isShowing = false;
}
}
// 在整个应用中任何地方需要登录弹窗,都使用同一个实例
const loginModal = LoginModal.getInstance();
document.getElementById('login-btn').addEventListener('click', () => {
loginModal.show();
});
这样做有什么好处?
- 性能优化:推迟到第一次使用时才创建弹窗(懒加载)
- 避免重复创建:整个应用共用同一个弹窗实例
- 保持状态一致:无论从哪里调用,操作的都是同一个弹窗
面试中可能会问到的深入问题
- 懒加载 vs 饿汉式:单例模式有两种实现方式——懒加载(第一次使用时创建)和饿汉式(类加载时就创建)。JavaScript中通常使用懒加载。
- 线程安全:在Java等语言中,单例模式需要考虑多线程环境。虽然JavaScript是单线程的,但面试官可能会问到这个概念,以考察你的知识广度。
- 单例模式的缺点:全局状态难以测试、可能造成耦合度高等问题。能提到这些说明你思考全面。
- 其他实现方式:除了类静态方法,还可以使用闭包、模块模式等方式实现单例。