跳至主要內容

单例模式

约 573 字

单例模式

核心思想

单例模式可以确保一个类只有一个实例,并提供一个访问该实例的全局节点。

典型用例

全局缓存

单例模式提供了一个全局访问点,以便所有代码共同使用一个缓存实例,从而允许不同组件共享和操作相同的数据。

在这个例子中,缓存类包含一个私有的构造函数,以防止外部直接创建实例。这样,无论在应用程序的哪个部分获取缓存实例,都是同一个实例,从而确保了缓存数据的一致性和共享性。这对于管理全局状态、缓存、配置设置等场景非常有用。

// npm run code src/code/design-pattern/singleton/global-cache.ts

export {};

// 创建一个缓存类
class MyCache {
    private static instance: MyCache;
    private store: Record<string, any>;

    private constructor() {
        this.store = {};
    }

    public static getInstance(): MyCache {
        if (!MyCache.instance) {
            MyCache.instance = new MyCache();
        }
        return MyCache.instance;
    }

    set(key: string, value: any): void {
        this.store[key] = value;
    }

    get(key: string): any {
        return this.store[key];
    }
}

const cache1 = MyCache.getInstance();
cache1.set('key1', 'value1');

const cache2 = MyCache.getInstance();
console.log(cache2.get('key1')); // 输出: 'value1'


全局配置管理

单例模式可以用来管理全局状态或配置信息。例如:使用单例模式来管理应用程序的全局配置信息,比如数据库连接设置或其他配置参数。

// src/code/design-pattern/singleton/global-configuration-management.ts

export {};

class GlobalConfig {
    private static instance: GlobalConfig;
    private config: Record<string, any>;

    // 构造函数设为私有,防止外部使用 new 关键字创建实例
    private constructor() {
        this.config = {
            // 默认的配置项
            databaseConnection: 'DefaultConnection',
            applicationSetting: 'DefaultSetting',
            // 其他配置项...
        };
    }

    // 提供一个静态方法用于获取类的实例
    public static getInstance(): GlobalConfig {
        if (!GlobalConfig.instance) {
            GlobalConfig.instance = new GlobalConfig();
        }
        return GlobalConfig.instance;
    }

    // 获取配置项的方法
    public getConfig(key: string): any {
        return this.config[key];
    }

    // 设置配置项的方法
    public setConfig(key: string, value: any): void {
        this.config[key] = value;
    }
}

// 使用单例
const config = GlobalConfig.getInstance();
console.log(config.getConfig('databaseConnection')); // 输出默认的数据库连接配置

// 更改配置项
config.setConfig('databaseConnection', 'NewDatabaseConnection');
console.log(config.getConfig('databaseConnection')); // 输出新的数据库连接配置

日志记录

单例模式可以确保整个应用程序中使用一个统一的日志记录器实例,这样可以提高日志管理的一致性和效率。

// npm run code src/code/design-pattern/singleton/log-recording.ts

export {};

class Logger {
    private static instance: Logger;

    // 私有构造函数确保不会外部创建多个实例
    private constructor() {}

    // 公共静态方法提供全局访问点以获取日志记录器实例
    public static getInstance(): Logger {
        if (!Logger.instance) {
            Logger.instance = new Logger();
        }
        return Logger.instance;
    }

    // 日志记录方法
    public log(message: string): void {
        console.log(`${new Date().toISOString()}: ${message}`);
    }

    // 其他可能的方法,如错误记录、警告记录等
    public error(message: string): void {
        console.error(`${new Date().toISOString()}: ERROR: ${message}`);
    }

    public warn(message: string): void {
        console.warn(`${new Date().toISOString()}: WARNING: ${message}`);
    }
}

// 使用日志记录器
const logger = Logger.getInstance();
logger.log("这是一个日志消息。");
logger.error("这是一个错误消息。");
logger.warn("这是一个警告消息。");

数据库连接池

单例模式可以用于确保整个应用程序只创建一次数据库连接池,从而统一管理数据库连接并优化资源利用率。

// npm run code src/code/design-pattern/singleton/database-connection-pool.ts

export {};

class DatabaseConnectionPool {
    private static instance: DatabaseConnectionPool;
    private pool: any; // 这里假设为数据库连接池的实际类型

    // 私有构造函数,避免外部直接创建实例
    private constructor() {
        this.initPool(); // 初始化连接池
    }

    // 实例化连接池(具体实现根据实际数据库连接池来定)
    private initPool() {
        // 这里只是一个示例,实际的初始化代码将取决于所使用的数据库和连接池技术
        this.pool = {/* ... 初始化数据库连接池 ... */};
    }

    // 提供一个静态方法用于获取类的实例
    public static getInstance(): DatabaseConnectionPool {
        if (!DatabaseConnectionPool.instance) {
            DatabaseConnectionPool.instance = new DatabaseConnectionPool();
        }
        return DatabaseConnectionPool.instance;
    }

    // 获取数据库连接的方法(示例)
    public getConnection(): any {
        // 实际的获取连接逻辑依赖于所使用的数据库和连接池技术
        return {/* ... 获取一个数据库连接 ... */};
    }

    // 释放数据库连接的方法(示例)
    public releaseConnection(connection: any): void {
        // 实际的释放连接逻辑依赖于所使用的数据库和连接池技术
    }
}

// 使用数据库连接池
const connectionPool = DatabaseConnectionPool.getInstance();
const connection = connectionPool.getConnection();
// 使用 connection 进行数据库操作...
connectionPool.releaseConnection(connection);

访问硬件接口

单例模式适合用来控制对硬件接口的访问,例如:确保整个应用中只有一个实例来管理对打印机或文件系统的访问。这不仅保证了资源访问的一致性,还有助于防止资源冲突和数据不一致的问题。

// npm run code src/code/design-pattern/singleton/access-hardware-interface.ts

export {};

class Printer {
    private static instance: Printer;

    // 私有构造函数确保外部不能直接实例化
    private constructor() {
        // 初始化打印机设置
    }

    // 提供静态方法获取类的实例
    public static getInstance(): Printer {
        if (!Printer.instance) {
            Printer.instance = new Printer();
        }
        return Printer.instance;
    }

    // 打印方法
    public print(document: string): void {
        console.log(`Printing: ${document}`);
        // 实际的打印逻辑
    }

    // 其他与打印机相关的方法
    // ...
}

// 使用单例打印机
const printer = Printer.getInstance();
printer.print("Hello, world!"); // 执行打印操作

服务提供者

单例模式适用于需要确保整个应用程序中服务的一致访问和状态管理的场景,例如:网络服务、业务逻辑服务等。

// npm run code src/code/design-pattern/singleton/service-provider.ts

export {};

class NetworkService {
    private static instance: NetworkService;

    // 私有构造函数,防止外部创建多个实例
    private constructor() {
        // 初始化网络服务,比如设置API端点、认证信息等
    }

    // 静态方法获取类的实例
    public static getInstance(): NetworkService {
        if (!NetworkService.instance) {
            NetworkService.instance = new NetworkService();
        }
        return NetworkService.instance;
    }

    // 网络请求方法示例
    public fetchData(url: string): Promise<any> {
        // 实际的网络请求逻辑,这里简化为直接返回一个Promise
        return new Promise((resolve, reject) => {
            // 模拟网络请求
            console.log(`Fetching data from ${url}`);
            setTimeout(() => resolve(`Data from ${url}`), 1000); // 假设1秒后请求完成
        });
    }

    // 其他可能的网络服务方法
    // ...
}

// 使用网络服务
const networkService = NetworkService.getInstance();
networkService.fetchData("https://example.com/api/data")
    .then(data => console.log(data))
    .catch(error => console.error(error));

上次编辑于: