Singleton class

本文介绍了一种使用模板实现的单例类,该类能够确保在程序运行期间仅创建一个实例。通过具体示例展示了如何使用此类来管理线程局部存储(TLS)功能,并提供了测试代码验证其实现的有效性。

From the name we can see that a singleton class is a kind of class that only has one class object. Why we need to use this pattern? Sometimes we can use it instead of the global variables.

 

Here is an implementation of singleton class:

template <typename TData>

class CThreadData

{

    // construction / destruction

private:

    CThreadData(CThreadData const&);       // prevent copy construction

    TData *m_pTData;

 

protected:

    CThreadData()                      // disallow illegal construction

    {}

 

public:

    virtual ~CThreadData()                 // this should be private: VC++ bug!

    {}

 

    // singleton operations, get the reference of the only class object

public:

    static CThreadData<TData>& Instance(void);

 

    // operations

public:

    void AllocData(void)

    {

       // only once

       _ASSERTE(GetValue() == 0);

       SetValue(new TData());

    }

 

    void FreeData(void)

    {

       TData* pData = GetValue();

       if (pData != 0) {

           delete pData;

           SetValue(0);

       }

    }

 

    void SetValue(TData* pvData)

    { m_pTData = pvData;}

 

    TData *const GetValue(void) const

    { return m_pTData;}

 

    TData *GetValue(void)

    { return m_pTData;}

 

    // data members

protected:

    static CThreadData *m_pInstance;

};

 

template <typename TData> CThreadData<TData>* CThreadData<TData>::m_pInstance = 0;

 

template <typename TData>

CThreadData<TData>& CThreadData<TData>::Instance(void)

{

    if (m_pInstance == 0) {

       static CThreadData<TData> instance;

       m_pInstance = &instance;

    }

 

    return (*m_pInstance);

}

 

Here is the test code

template <typename TData>

class ThreadData

{

public:

    ThreadData() {m_dwData = 1;};

 

    TData  GetValue() {return m_dwData;};

    void   SetValue(TData pData)    {m_dwData = pData;};

private:

    TData  m_dwData;

};

 

typedef ThreadData<DWORD> ThreadDataDWORD;

 

int _tmain(int argc, _TCHAR* argv[])

{

    CThreadData<ThreadDataDWORD> &rOnlyOne = CThreadData<ThreadDataDWORD>::Instance();

 

    rOnlyOne.AllocData();

 

    ThreadData<DWORD> *pTD = rOnlyOne.GetValue();

    printf ("data: %d/n", pTD->GetValue());

    pTD->SetValue(8);

    printf ("data: %d/n", pTD->GetValue());

 

    rOnlyOne.FreeData();

}

 

We may use this structure to manage the TLS functions.

More details: http://www.codeproject.com/KB/threads/threaddata.aspx

 

在 Python 中,单例装饰器通过封装类的实例化过程来确保一个类在整个程序运行期间只有一个实例存在。其实现原理主要依赖于装饰器的闭包特性以及对类创建逻辑的控制。 ### 单例装饰器的基本实现原理 单例装饰器的核心思想是在装饰器内部维护一个缓存机制,用于记录某个类是否已经被实例化。如果尚未实例化,则进行实例化并缓存;如果已经实例化,则直接返回缓存的实例。 例如,一个常见的单例装饰器实现如下: ```python def singleton(cls): instances = {} def _singleton(*args, **kwargs): if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return _singleton ``` 在该实现中,`singleton` 是一个装饰器函数,它接收一个类 `cls` 并返回一个新的函数 `_singleton`。当使用 `@singleton` 装饰一个类时,类的实例化过程会被封装到 `_singleton` 函数中。每次调用被装饰的类时,装饰器会检查是否已经存在该类的实例。如果存在,则直接返回缓存的实例;如果不存在,则调用类的构造函数创建实例并缓存[^2]。 ### 如何确保一个类只有一个实例 单例装饰器确保类只有一个实例的关键在于缓存机制和条件判断。具体来说: 1. **缓存机制**:装饰器内部使用一个字典 `instances` 来存储类的实例。键是类本身,值是该类的实例。这种方式可以支持多个类的单例管理,而不会发生冲突。 2. **条件判断**:在每次调用被装饰的类时,装饰器会检查该类是否已经在 `instances` 字典中存在。如果不存在,则调用类的构造函数创建实例并存入字典;如果已经存在,则直接返回字典中的实例。 这种机制确保了无论调用多少次被装饰的类,最终只会创建一个实例。例如: ```python @singleton class Apple: def __init__(self, color, price): self.color = color self.price = price apple1 = Apple("red", 1.2) apple2 = Apple("green", 0.7) print(apple1 is apple2) # 输出 True,表示两个变量指向同一个实例 ``` 在上述代码中,尽管两次调用了 `Apple` 类并传入了不同的参数,但最终 `apple1` 和 `apple2` 指向的是同一个实例,这表明单例装饰器成功确保了类只有一个实例[^3]。 ### 单例装饰器的扩展功能 为了进一步增强单例装饰器的功能,可以在装饰器中添加额外的方法,例如清理缓存的方法。这种扩展可以通过在装饰器中定义一个 `clean` 方法实现,用于删除缓存的实例。例如: ```python def singleton(cls): def wrapper(*args, **kwargs): if not hasattr(cls, "__single_instance"): setattr(cls, "__single_instance", cls(*args, **kwargs)) return getattr(cls, "__single_instance") wrapper.clean = lambda: delattr(cls, "__single_instance") return wrapper @singleton class Apple: def __init__(self, color, price): self.color = color self.price = price apple1 = Apple("red", 1.2) apple2 = Apple("green", 0.7) print(apple1 is apple2) # 输出 True,表示两个变量指向同一个实例 Apple.clean() # 清理缓存 apple3 = Apple("green", 1.5) print(apple1 is apple3) # 输出 False,表示清理后重新创建了实例 ``` 在该实现中,`wrapper` 函数通过检查类是否具有 `__single_instance` 属性来判断是否已经创建实例。如果尚未创建,则调用类的构造函数并设置该属性;如果已经创建,则直接返回该属性。同时,`wrapper` 函数还定义了一个 `clean` 方法,用于删除 `__single_instance` 属性,从而允许后续重新创建实例[^3]。 ### 单例装饰器的优势 1. **灵活性**:单例装饰器可以轻松地应用于任何类,只需在类定义前添加 `@singleton` 装饰器即可。 2. **可维护性**:通过装饰器模式,可以将单例逻辑与具体类的实现分离,提高代码的可维护性。 3. **可扩展性**:装饰器可以进一步扩展功能,例如支持清理缓存、动态配置等。 综上所述,Python 单例装饰器通过缓存机制和条件判断确保一个类只有一个实例,并通过装饰器模式提供灵活、可维护和可扩展的实现方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值