设计模式系列之一__单例模式(1)__基本定义以及实现

本文详细介绍了单例模式的概念及其在Java中的实现方式,包括懒汉式和饿汉式的具体应用场景和代码示例。

单例模式定义

  单例模式(singleton)顾名思义,就是一个类只有一个实例。

  作为对象的创建模式[GOF95], 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。

单例模式的实现原理

  1.一个类能够被创建多个实例,问题的根源在于类的构造方法是公开的,在类的外部可以通过构造方法创建多个实例。

  2.要想控制一个类只被创建一个实例,那么首要的问题就是要把创建实例的权限收回来,让类自身来负责自己类实例的创建工作,然后由这个类来提供外部可以访问这个类实例的方法,这就是单例模式的实现方式。

具体实现方式

 在Java中,单例模式的实现又分为两种,一种称为懒汉式,一种称为饿汉式,其实就是在具体创建对象实例的处理上,有不同的实现方式。

懒汉式:

  所谓懒汉式,既然是懒,那么在创建对象实例的时候就不着急,会一直等到马上要使用对象实例的时候才会创建,懒人嘛,总是推托不开的时候才去真正执行工作,因此在装载对象的时候不创建对象实例,到第一次使用的时候,才去创建实例。

    类图如下:

    

    写法如下:

    private static Singleton uniqueInstance = null

示例代码如下:

public class Singleton {  
    /**  
     * 定义一个变量来存储创建好的类实例  
     */  
    private static Singleton uniqueInstance = null;  
    /**  
     * 私有化构造方法,可以在内部控制创建实例的数目  
     */  
    private Singleton(){  
        //  
    }  
    /**  
     * 定义一个方法来为客户端提供类实例  
     * @return 一个Singleton的实例  
     */  
    public static synchronized Singleton getInstance(){  
        //判断存储实例的变量是否有值  
        if(uniqueInstance == null){  
            //如果没有,就创建一个类实例,并把值赋值给存储类实例的变量  
            uniqueInstance = new Singleton();  
        }  
        //如果有值,那就直接使用  
        return uniqueInstance;  
    }  
 } 


饿汉式:
所谓饿汉式,既然饿,那么在创建对象实例的时候就比较着急,饿了嘛,于是就在装载类的时候就创建对象实例
类图如下:


写法如下:

  private static Singleton uniqueInstance = new Singleton();

示例代码如下:

public class Singleton {  
    /**  
     * 定义一个变量来存储创建好的类实例,直接在这里创建类实例,只能创建一次  
     */  
    private static Singleton uniqueInstance = new Singleton();  
    /**  
     * 私有化构造方法,可以在内部控制创建实例的数目  
     */  
    private Singleton(){  
        //  
    }  
    /**  
     * 定义一个方法来为客户端提供类实例  
     * @return 一个Singleton的实例  
     */  
    public static Singleton getInstance(){  
        //直接使用已经创建好的实例  
        return uniqueInstance;  
    }  
 } 


参考文章:

 1. http://book.51cto.com/art/201010/232011.htm

  2.http://baike.baidu.com/view/1859857.htm


<think>好的,用户问如何用__call__实现单例模式。我之前已经给他讲过__call__的基本用法,覆盖过程和应用场景,现在需要扩展到单例模式。 首先,我得回忆单例模式的核心,确保一个类只有一个实例,并提供全局访问点。传统实现可能用__new__或者装饰器,但用户想知道如何用__call__来做。 可能的方法是让类的实例本身成为单例,或者通过元类控制实例创建。但__call__通常是在实例被调用时触发,这里可能需要一个中间类来管理实例。 比如,设计一个Singleton类作为基类,当子类被实例化时,Singleton的__call__方法控制实例的创建。每次实例化时检查是否已有实例存在,如果有就返回现有的,否则创建新的。 这样,Singleton类的__call__方法会被触发,因为当创建子类实例时,实际上是调用元类的__call__方法?或者可能用户混淆了元类和普通类的__call__方法? 可能需要用元类的方式。元类的__call__方法在创建类实例时被调用,所以可以通过重写元类的__call__来确保只创建一个实例。 或者,使用一个工厂类,其__call__方法返回单一实例。例如,Singleton类的实例作为装饰器,在调用时返回单例。 不过更常见的做法可能是通过元类。例如,定义一个Singleton元类,重写它的__call__方法,在创建类实例时检查是否已经存在,存在则返回,否则新建。 具体步骤:创建元类,覆盖__call__方法,在其中加入实例检查逻辑。然后让目标类使用这个元类。 代码示例: class Singleton(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super().__call__(*args, **kwargs) return cls._instances[cls] class MyClass(metaclass=Singleton): pass 这样,每次创建MyClass实例时,都会通过Singleton元类的__call__方法,确保只有一个实例。 但用户的问题是用__call__方法实现,可能需要确认是否必须直接在类中定义__call__,还是通过元类。可能用户希望用类的__call__来控制实例化,但通常实例化是通过元类的__call__来管理的,而普通类的__call__是当实例被调用时才触发。 所以正确的做法应该是使用元类的__call__方法。这时候需要解释元类中的__call__在实例创建时的作用,以及如何通过这种方式实现单例。 但用户可能对元类不太熟悉,所以需要一步步解释,从传统方法到使用元类,并说明为什么__call__在这里是关键。 可能还需要比较其他实现方式,比如使用装饰器或者__new__方法,然后说明用元类和__call__的优势。 此外,需要确保代码示例正确,并解释每个步骤的作用,比如检查类是否在_instances字典中,如果没有则创建并存储,否则返回现有的实例。 总结,用户的问题核心是结合__call__方法和单例模式,正确的实现方式是使用元类覆盖__call__,从而控制实例的创建过程,确保单例。</think>在Python中,通过覆盖`__call__`方法实现单例模式的核心思路是:**控制类的实例化过程,确保始终返回同一个实例**。以下是两种典型实现方式及详细解析: --- ### 方法一:使用元类(推荐方案) ```python class SingletonType(type): _instances = {} # 存储所有单例类实例的字典 def __call__(cls, *args, **kwargs): if cls not in cls._instances: # 检查是否已有实例 # 创建新实例并存入字典 cls._instances[cls] = super().__call__(*args, **kwargs) return cls._instances[cls] # 始终返回已存在的实例 class Database(metaclass=SingletonType): def __init__(self, connection_str): self.connection = self._connect(connection_str) def _connect(self, conn_str): print(f"建立数据库连接: {conn_str}") return "连接对象" ``` #### 验证效果 ```python db1 = Database("mysql://localhost:3306") db2 = Database("postgres://localhost:5432") print(db1 is db2) # 输出: True print(db1.connection) # 输出: 连接对象 print(db2.connection) # 输出: 连接对象(与db1相同) ``` --- ### 方法二:通过装饰器类 ```python class Singleton: _instance = None def __call__(self, cls): def wrapper(*args, **kwargs): if not self._instance: self._instance = cls(*args, **kwargs) return self._instance return wrapper @Singleton() # 使用装饰器 class Logger: def __init__(self, logfile="app.log"): self.logfile = logfile self._init_logger() def _init_logger(self): print(f"初始化日志系统: {self.logfile}") ``` #### 验证效果 ```python logger1 = Logger() logger2 = Logger("debug.log") print(logger1 is logger2) # 输出: True print(logger1.logfile) # 输出: app.log print(logger2.logfile) # 输出: app.log(参数被忽略) ``` --- ### 关键机制解析 | 机制 | 元类方案 | 装饰器方案 | |-----------------|-----------------------------------|-----------------------------------| | 控制点 | 元类的`__call__`方法 | 装饰器类的`__call__`方法 | | 实例存储位置 | 元类的类属性字典 | 装饰器类的实例属性 | | 参数处理 | 首次初始化参数有效 | 后续实例化参数被忽略 | | 继承兼容性 | 子类自动继承单例特性 | 需要显式添加装饰器 | | 线程安全性 | 需加锁实现线程安全 | 需加锁实现线程安全 | --- ### 最佳实践建议 1. **优先选择元类方案** - 天然支持类继承体系 - 代码结构更清晰直观 2. **线程安全改进** 添加线程锁确保多线程环境安全: ```python from threading import Lock class SingletonType(type): _instances = {} _lock = Lock() def __call__(cls, *args, **kwargs): with cls._lock: # 加锁保证线程安全 if cls not in cls._instances: cls._instances[cls] = super().__call__(*args, **kwargs) return cls._instances[cls] ``` 3. **参数处理策略** - 在元类方案中,第一次实例化参数生效,后续参数无效 - 若需要动态参数,需设计参数验证机制 --- ### 典型应用场景 - 数据库连接池管理 - 系统配置管理器 - 日志记录器 - 硬件设备控制类 - 缓存系统入口 通过合理使用`__call__`方法实现单例模式,既能保持代码简洁,又能有效管理系统中的全局唯一资源。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值