首页 > 其他分享 >单例模式 (Singleton Pattern) - 设计模式精讲·面试必备

单例模式 (Singleton Pattern) - 设计模式精讲·面试必备

时间:2024-09-19 15:49:42浏览次数:11  
标签:Singleton return getInstance Pattern instance 实例 单例 new 设计模式

前言

最近整理了一份设计模式手册:从入门到精通的实用指南。
坦白说,我对网上那些过于理论化的教程感到有些失望。于是决定亲自动手,从基础概念到实际应用,把常用的设计模式都梳理了一遍。每种模式不仅包含核心原理,还附带了真实的代码示例,希望能帮助大家更好地理解和运用这些模式。
如果你正在学习软件设计,或想提升架构能力,不妨看看这份指南。也许对你有所启发,也可能觉得平平无奇,但这是我的一点小小心意。
欢迎随时分享你的想法,让我们一起探讨,共同进步!

定义

单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取该实例。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。单例模式不仅限制了一个类只能有一个实例,还负责自行创建这个实例。

单例模式的核心概念包括:

  1. 私有构造函数:确保类不能从外部被实例化。

  2. 私有静态实例:类的唯一实例作为类的私有静态成员存储。

  3. 公共静态访问方法:提供一个全局访问点来获取类的唯一实例。

在JavaScript中,由于语言的动态性和模块化特性,单例模式的实现可能会有所不同。通常,我们可以通过模块模式、闭包或ES6的类语法来实现单例。

代码实现

class Singleton {
  constructor() {
    if (Singleton.instance) {
      return Singleton.instance;
    }
    this.data = Math.random();
    Singleton.instance = this;
  }

  static getInstance() {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }
    return Singleton.instance;
  }

  getData() {
    return this.data;
  }
}

// 防止实例化
Object.freeze(Singleton);

使用示例

const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();

console.log(instance1 === instance2); // 输出: true
console.log(instance1.getData() === instance2.getData()); // 输出: true

详细解释

  1. 私有构造函数:构造函数检查是否已存在实例。如果存在,则返回现有实例;否则,创建新实例。

  2. 静态实例Singleton.instance 是静态属性,存储唯一实例。

  3. 静态访问方法getInstance() 是获取实例的唯一途径,确保只创建一个实例。

  4. 延迟初始化:实例在首次调用 getInstance() 时才被创建,实现懒加载。

  5. 防止修改:使用 Object.freeze() 防止 Singleton 类被修改。

优点

  1. 资源节约:只创建一个实例,节省了系统资源,特别是对于那些创建和销毁开销较大的对象。

  2. 全局访问点:提供了对唯一实例的全局访问点,方便对实例进行控制和管理。

  3. 严格控制:可以严格控制客户端如何访问实例以及何时访问实例。

  4. 灵活性:允许对实例的数量进行灵活控制。可以在运行时判断是否需要多个实例。

  5. 延迟实例化:单例模式可以延迟实例化,即在第一次使用时才实例化对象,有助于提高性能。

  6. 避免资源竞争:在多线程环境中,可以避免对共享资源的多重占用。

  7. 跨模块共享:在模块化的应用程序中,单例可以作为跨模块共享状态或功能的有效方式。

缺点

  1. 违反单一职责原则:单例类既要管理自身的职责,又要确保只有一个实例,可能导致类的职责过重。

  2. 隐藏依赖关系:单例模式可能隐藏了类之间的依赖关系,使得系统结构不够清晰,增加了系统的耦合度。

  3. 测试困难:单例模式的静态特性使得单元测试变得困难,因为许多测试框架依赖于继承和多态来完成测试。

  4. 扩展性差:单例类通常难以扩展。如果需要扩展单例类,往往需要修改原有类的代码。

  5. 与面向对象设计原则冲突:单例模式在某种程度上违背了一些面向对象的原则,如开闭原则。

  6. 并发问题:在多线程环境下,如果不谨慎处理,可能会出现多个实例的情况。

  7. 全局状态:引入了全局状态到应用程序中,可能导致代码的紧耦合和难以维护。

使用场景

1. 全局状态管理

例如在前端框架中的状态管理器(如Redux或Vuex)。

class Store {
  constructor() {
    if (Store.instance) return Store.instance;
    this.state = {};
    Store.instance = this;
  }

  static getInstance() {
    if (!Store.instance) {
      Store.instance = new Store();
    }
    return Store.instance;
  }

  setState(key, value) {
    this.state[key] = value;
  }

  getState(key) {
    return this.state[key];
  }
}

2. 数据库连接池

管理数据库连接,确保只有一个连接池实例。

class DatabasePool {
  constructor() {
    if (DatabasePool.instance) return DatabasePool.instance;
    this.pool = [];
    DatabasePool.instance = this;
  }

  static getInstance() {
    if (!DatabasePool.instance) {
      DatabasePool.instance = new DatabasePool();
    }
    return DatabasePool.instance;
  }

  getConnection() {
    // 实现获取连接的逻辑
  }

  releaseConnection(connection) {
    // 实现释放连接的逻辑
  }
}

3. 日志记录器

确保应用程序只使用一个日志记录器实例。

class Logger {
  constructor() {
    if (Logger.instance) return Logger.instance;
    this.logs = [];
    Logger.instance = this;
  }

  static getInstance() {
    if (!Logger.instance) {
      Logger.instance = new Logger();
    }
    return Logger.instance;
  }

  log(message) {
    const timestamp = new Date().toISOString();
    this.logs.push(`${timestamp}: ${message}`);
    console.log(`${timestamp}: ${message}`);
  }

  getLogs() {
    return this.logs;
  }
}

4. 配置管理

/**
 * 配置管理器
 * 用于集中管理应用程序的全局配置
 * 确保整个应用中只有一个配置实例,避免配置不一致
 */
class ConfigManager {
  constructor() {
    this.config = {};
  }

  static getInstance() {
    if (!ConfigManager.instance) {
      ConfigManager.instance = new ConfigManager();
    }
    return ConfigManager.instance;
  }

  setConfig(key, value) {
    this.config[key] = value;
  }

  getConfig(key) {
    return this.config[key];
  }
}

const configManager = ConfigManager.getInstance();

5. 缓存管理

/**
 * 缓存管理器
 * 实现一个全局的缓存系统,用于存储和检索数据
 * 单例模式确保所有组件使用同一个缓存实例,提高效率
 */
class CacheManager {
  constructor() {
    this.cache = new Map();
  }

  static getInstance() {
    if (!CacheManager.instance) {
      CacheManager.instance = new CacheManager();
    }
    return CacheManager.instance;
  }

  set(key, value, ttl) {
    this.cache.set(key, {
      value,
      expiry: Date.now() + ttl
    });
  }

  get(key) {
    const item = this.cache.get(key);
    if (item && item.expiry > Date.now()) {
      return item.value;
    }
    this.cache.delete(key);
    return null;
  }
}

const cacheManager = CacheManager.getInstance();

6. 线程池

/**
 * 线程池管理器
 * 在支持Web Workers的环境中管理线程池
 * 单例模式确保整个应用使用同一个线程池,避免资源浪费
 */
class ThreadPool {
  constructor(size) {
    this.size = size;
    this.tasks = [];
    this.workers = [];
  }

  static getInstance(size = 4) {
    if (!ThreadPool.instance) {
      ThreadPool.instance = new ThreadPool(size);
    }
    return ThreadPool.instance;
  }

  addTask(task) {
    this.tasks.push(task);
    this.runTask();
  }

  runTask() {
    if (this.workers.length < this.size && this.tasks.length > 0) {
      const worker = new Worker('worker.js');
      this.workers.push(worker);
      const task = this.tasks.shift();
      worker.postMessage(task);
    }
  }
}

const threadPool = ThreadPool.getInstance();

7. 设备管理器

/**
 * 设备管理器
 * 用于管理硬件设备的连接和状态
 * 单例模式确保所有组件通过同一个实例访问设备,避免冲突
 */
class DeviceManager {
  constructor() {
    this.devices = new Map();
  }

  static getInstance() {
    if (!DeviceManager.instance) {
      DeviceManager.instance = new DeviceManager();
    }
    return DeviceManager.instance;
  }

  connectDevice(id, device) {
    this.devices.set(id, device);
  }

  disconnectDevice(id) {
    this.devices.delete(id);
  }

  getDevice(id) {
    return this.devices.get(id);
  }
}

const deviceManager = DeviceManager.getInstance();

8. 游戏管理器

/**
 * 游戏管理器
 * 管理游戏的全局状态,如分数和关卡
 * 单例模式确保游戏中只有一个状态管理实例,保持数据一致性
 */
class GameManager {
  constructor() {
    this.score = 0;
    this.level = 1;
  }

  static getInstance() {
    if (!GameManager.instance) {
      GameManager.instance = new GameManager();
    }
    return GameManager.instance;
  }

  increaseScore(points) {
    this.score += points;
  }

  nextLevel() {
    this.level++;
  }
}

const gameManager = GameManager.getInstance();

9. 文件系统

/**
 * 文件系统管理器
 * 提供统一的文件操作接口,模拟简单的文件系统
 * 单例模式确保整个应用使用同一个文件系统实例,避免数据不一致
 */
class FileSystem {
  constructor() {
    this.files = new Map();
  }

  static getInstance() {
    if (!FileSystem.instance) {
      FileSystem.instance = new FileSystem();
    }
    return FileSystem.instance;
  }

  writeFile(path, content) {
    this.files.set(path, content);
  }

  readFile(path) {
    return this.files.get(path);
  }

  deleteFile(path) {
    this.files.delete(path);
  }
}

const fileSystem = FileSystem.getInstance();

10. 打印机后台处理程序

/**
 * 打印机后台处理程序
 * 管理打印任务队列,确保打印作业的有序执行
 * 单例模式确保只有一个打印队列管理器,避免打印任务冲突
 */
class PrinterSpooler {
  constructor() {
    this.queue = [];
  }

  static getInstance() {
    if (!PrinterSpooler.instance) {
      PrinterSpooler.instance = new PrinterSpooler();
    }
    return PrinterSpooler.instance;
  }

  addJob(job) {
    this.queue.push(job);
  }

  processNextJob() {
    if (this.queue.length > 0) {
      const job = this.queue.shift();
      console.log('打印作业:', job);
    }
  }
}

const printerSpooler = PrinterSpooler.getInstance();

这些场景都利用了单例模式的特性,如全局访问点、资源共享和状态管理等。然而,使用单例模式时需要谨慎考虑其对系统设计的影响,权衡其带来的便利性和可能引入的问题。

9. 更多内容推荐

标签:Singleton,return,getInstance,Pattern,instance,实例,单例,new,设计模式
From: https://blog.csdn.net/qq_35732986/article/details/142361211

相关文章

  • 设计模式——命令模式
    设计模式——命令模式1.智能生活需求看一个具体的需求我们买了一套智能家电,有照明灯、风扇、冰箱、洗衣机,我们只要在手机上安装app就可以控制对这些家电工作。这些智能家电来自不同的厂家,我们不想针对每一种家电都安装一个App,分别控制,我们希望只要一个app就可以控......
  • 巨巨巨实用的设计模式-策略模式
    策略模式策略模式是一种常见的设计模式,用于封装不同的算法,并使其可以相互替换。通过使用策略模式,可以使代码更加灵活、可扩展和易于维护。在实际开发中,我们可以使用策略模式来解决各种不同的问题。主要是规范化代码,避免if,else的来回嵌套。比如,我们所在的是个做早餐的公司,......
  • 设计模式之——代理模式
    代理模式前言:我们一般在租房子时会去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做;再比如我们打官司需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们的想法;再比如在淘宝上面买东西,你使用支付宝平台支付,卖家请物流公司发货,......
  • 活动系统开发之采用设计模式与非设计模式的区别-后台功能总结
    1、数据库ER图2、后台功能字段题目功能字段数据列表编号题目名称选项数量状态1=启用0=禁用创建时间修改时间保存题目名称选项集选项内容是否正确答案1=正确0=错误启禁用删除素材图库功能字段数据列表编号原文件名称文件类型文件大小加密后文件名文件具体路径上传类......
  • 设计模式——代理模式
    设计模式——代理模式1.代理模式(Proxy)1.1代理模式的基本介绍代理模式:为一个对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。被代理的对象可以是远程对象、......
  • 23种设计模式
    23种设计模式设计模式是软件工程中用于解决特定问题的通用解决方案。常见的设计模式有24种,通常分为三大类:创建型、结构型和行为型。下面是对这24种设计模式的详细解释及其归类:1.创建型模式1.1单例模式(Singleton)目的:确保一个类只有一个实例,并提供一个全局访问点。适用场......
  • 设计模式---- 门面模式
    门面模式门面模式(FacadePattern)是一种结构型设计模式,用于为复杂子系统提供一个统一、简单的接口,隐藏系统的复杂性。通过门面模式,客户端无需直接与系统的内部组件交互,而是通过门面类与系统打交道,简化了客户端的使用,降低了系统的复杂性和耦合度。门面模式的主要概念定义:门面模......
  • 设计模式---- 工厂模式
    工厂模式工厂模式是一种创建型设计模式,它的主要目的是将对象的创建过程与对象的使用过程分离。工厂模式通过引入工厂类或者工厂方法,隐藏对象创建的复杂性,使得代码更加灵活、可扩展。工厂模式的使用场景主要在于:当我们需要对创建的对象进行封装或延迟创建时,工厂模式是一个很好的选......
  • 重生之我在Java世界------学单例设计模式
    什么是单例设计模式?单例模式是面向对象编程中最简单却又最常用的设计模式之一。它的核心思想是确保一个类只有一个实例,并提供一个全局访问点。本文将深入探讨单例模式的原理、常见实现方法、优缺点,以及在使用过程中可能遇到的陷阱。单例模式的核心原理单例模式的实现主要......
  • 原型模式(Prototype Pattern)
    原型模式是一种创建型设计模式,使用克隆方法来复制现有对象,从而避免重复的初始化操作,特别适用于创建重复对象的场景。适用场景:当一个系统需要创建新对象的对象系统中,可通过克隆一个原型并对其进行改造。当对象的创建成本比较大(如复杂的初始化)时。示例代码:abstractclassSha......