C++ 设计模式-单例-工厂

本文介绍了设计模式的六大原则,重点讨论了C++中的单例模式,包括懒汉式和饿汉式的实现,以及它们的问题与解决方法。单例模式的应用场景包括多线程共享资源、全局变量、资源密集型对象创建等。
摘要由CSDN通过智能技术生成

设计模式的六大原则

(1)几种设计原则的小结(6个原则的首字母组合单词(S.O.L.I.D,表示稳定)

①单一职责原则告诉我们实现类要职责单一

②里氏替换原则告诉我们不要破坏继承体系;所有使用基类的地方必须能透明地使用子类替换,而程序的行为没有任何变化

③依赖倒置原则告诉我们要面向接口编程

④接口隔离原则告诉我们在设计接口的时候要精简单一

⑤迪米特法则告诉我们要降低耦合

⑥开闭原则是总纲,他告诉我们要对扩展开放,对修改关闭

(2)建立稳定、灵活、健壮的设计,开闭原则是最基础的原则,也是精神领袖

(3)开闭原则是最基础的一个原则,前五个原则都是开闭原则的具体形态,而开闭原则才是灵魂。换一个角度,借用OOP的说法,开闭原则是抽象类,其他五大原则是具体的实现类。

单例模式

(1)懒汉式:

  ①其特点是延迟加载,典型的以“时间换空间”做法。即只会在全局访问方法首次被调用时才被创建。

  ②问题:new出来的实例不能自动释放,可能存在内存泄漏问题。其解决方法有2种。

    A.方法1:在单例类内部定义专有的嵌套类,并在单例类定义一个私有的专门用于释放的静态成员,当程序结束析构全局变量时,会自动调用并释放这个单例。

    B.方法2:在单例类提供一个专门用于释放的静态成员函数,并在需要时手动释放。

  ③在实际项目中,单例一般是个全局变量,它的生命期随软件运行结束而自然终止。也就没有内存泄漏,但是如果单例中用到了一个文件锁、文件句柄或数据库连接,这些并不会随程序的关闭而立即关闭,必须在程序关闭前进行手动释放。

代码-懒汉式B
#include <iostream>
using namespace std;


class singleton{
protected:
    singleton(){}   //为了防止在外部调用类的构造函数而创建实例,需要将构造函数的访问权限设为protected或private;
    singleton(const singleton&other){};
    singleton& operator=(const singleton&other){}; //单例类一般不会主动要求被复制的,因此复制构造函数和赋值构造函数一般也设为私有。
private:
    static singleton *p;   
public:
    static singleton *instance();  //全局访问点
    static void clearinstance();
};

singleton* singleton::p = NULL;
singleton* singleton::instance()
{
    if (p == NULL)
    {
        cout << "开始创建实例" << endl;
        p = new singleton();
        return p;
    }
    return p;
}

void singleton::clearinstance()
{
    if (p != NULL)
    {
        cout << "执行删除操作" << endl;
        delete p;
        p = NULL;
    }
}

int main()
{
    singleton *p1 = singleton::instance();
    singleton *p2 = p1->instance();
    singleton *p3 = singleton::instance();
    printf("p1 = %p\n", p1);
    printf("p2 = %p\n", p2);
    printf("p3 = %p\n", p2);
    p1->clearinstance();
    p2->clearinstance();
    return 0;
}
结果

这里写图片描述

代码-懒汉式A

在单例类内部定义专有的嵌套类,并在单例类定义一个私有的专门用于释放的静态成员,当程序结束析构全局变量时,会自动调用并释放这个单例。


class sigleton{
private:
    sigleton(){}
    sigleton(const sigleton& other){}
    sigleton& operator=(const sigleton& other){}
    static sigleton* instance;
    class GC{
        public:

        ~GC(){
            if (instance != NULL)
            {
                cout << "执行删除操作" << endl;
                delete instance;
                instance = NULL;
            }
        }
    };
public:
    static sigleton* getinstance();
    static GC gc;

};

sigleton* sigleton::getinstance()
{
    if (instance == NULL)
    {
        cout << "执行创建实例" << endl;
        instance = new sigleton();
        return instance;
    }
    return instance;
}

sigleton* sigleton::instance = NULL;
sigleton::GC sigleton::gc;

int main()
{
    sigleton* p1 = sigleton::getinstance();
    sigleton* p2 = p1->getinstance();
    sigleton* p3 = sigleton::getinstance();
    printf("p1 = %p\n", p1);
    printf("p2 = %p\n", p2);
    printf("p3 = %p\n", p2);

    return 0;
}
结果

这里写图片描述

(2)饿汉式

其特点是一开始就加载了,典型的“空间换时间”作法。因为一开始就创建了实例,所以每次用时直接返回就好了.

//创建型模式:单例模式

#include <stdio.h>

//饿汉式:多线程安全
class CSingleton
{
public:
    //提供全局访问的访问点
    static CSingleton* getInstance()
    {
        //cout << "执行创建操作"<<endl;
        static CSingleton instance;
        return &instance;
    }

private:
    //将构造函数设为私有属性
    CSingleton(){};
};

int main()
{
    CSingleton* s1 = CSingleton::getInstance();
    CSingleton* s2 = CSingleton::getInstance();

    printf("s1 = %p\n", s1);
    printf("s2 = %p\n", s2);

    return 0;
}

双重锁

线程安全

class Lock
{
private:
    HANDLE m_hMutex;
public:
    Lock()
    {
        m_hMutex = CreateMutex(NULL, false, NULL);//安全性,true创建线程立刻获得所有权,匿名
    }
    ~Lock(){CloseHandle(m_hMutex);}
    void lock(){ WaitForSingleObject(m_hMutex,INFINITE); }
    void unlock(){ ReleaseMutex(m_hMutex); }
};


class singleton{
private:
    singleton(){}
    static singleton* instance; //声明
    static Lock m_lock;  //锁成为静态变量 声明
public:
    static singleton* getInstance()
    {
        if (instance == NULL)
        {
            m_lock.lock();
            if (instance == NULL)
            {
                instance = new singleton();             
            }
            m_lock.unlock();
        }
        return instance;
    }
};

singleton* singleton::instance = NULL;  //定义初始化
Lock singleton::m_lock;   //定义

DWORD WINAPI ThreadProc(PVOID pvParam)
{
    singleton* s = singleton::getInstance();

    printf("thread:%d, address = %p\n", (int)pvParam, s);

    Sleep(1000);

    return 0;
}

int main()
{
    const int iCount = 64;
    HANDLE hThread[iCount];

    for (int i = 0; i < iCount; i++)
    {
        hThread[i] = CreateThread(NULL, 0, ThreadProc, (LPVOID)i, 0, NULL);
        //安全性,初始栈大小,线程处理函数,传递参数,线程创建标记,线程id
    }

    //注意:WaitForMultipleObjects最多能等待64个内核对象
    WaitForMultipleObjects(iCount, hThread, TRUE, INFINITE);

    for (int i = 0; i < iCount; i++)
        CloseHandle(hThread[i]);

    return 0;
}

单例模式的使用场景

(1)多线程之间共享一个资源或者操作同一个对象

(2)在整个程序空间中使用全局变量,共享资源

(3)在创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源。

(4)大规模系统中,为了性能的考虑,需要节省对象的创建时间

(5)要求生成唯一序列号的环境或用单例做为一个计数器。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值