当前位置 博文首页 > Scissors_初夏的博客:初夏小谈:设计模式之单例模式

    Scissors_初夏的博客:初夏小谈:设计模式之单例模式

    作者:[db:作者] 时间:2021-08-28 13:15

    一、何为设计模式?

    ? ? ? ?所谓设计模式就是一种被反复使用,被频繁使用的代码经验的总结。设计模式的出现使得代码更容易被理解,保证了代码的可靠性。它让代码变得工程化。就如打仗用的兵书一样(孙子兵法)。

    二、单例模式

    ? ? ? 单例模式就是一个类只能创建一个对象。这种模式可以确保一个类只有一个对象,不能再创建其它对象。并且会提供一个可以访问它的全局访问点。只要有程序需要就会调用它。它是共享的。

    单例模式中包含两种模式即:①饿汉模式②懒汉模式

    三、饿汉模式

    ? ? ? ?插曲:饿汉模式太形象了,一听就知道一个饿鬼整天就想着吃,所以他不管去哪都会带着自己碗筷。虽然这样会增加麻烦。但他为了吃也是够拼的哈哈。

    ? ? ? ?1.可以类推过来饿汉模式就像上面说的那样。它在程序一启动就会创建对象,不管有没有其它程序去用它。? ?

    ? ? ? ?2.由于饿汉模式的点是:①:程序启动就创建对象

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?②:只能创建一个对象

    ? ? ? ?3. 所以在设计这样的类时要考虑:

    ? ? ? ? ? ?①:要将对象实例化时加上static目的是在程序一启动就会创建这个对象。

    ? ? ? ? ? ?②:根据只能创建一个对象的特点,我们就需要对构造函数和拷贝构造函数进行私有化,防止在类外创建对象。

    ? ? ? ? ? ?③:一旦在里面创建这个对象我们就需要给一个接口来在外面使用这个对象。并且这个接口也得给成静态的。因为静态不受对象的限制,假如是普通模式,如果在外面调用的话就需要用对象来调,显然这不可能。

    class Singleton
    {
    public:
    	static Singleton& GetSingleton()
    	{
    		return Object;
    	}
    private:
    	//构造函数
    	Singleton()
    	{}
    	//拷贝构造函数
    	Singleton(const Singleton& S)
    	{}
    	//赋值
    	Singleton& operator=(const Singleton& S)
    	{}
    private:
    	static Singleton Object;
    };
    
    Singleton Singleton::Object;

    ? ? ? ?饿汉模式?在多线程高并发环境下频繁使用对象的话,它可以避免资源竞争,提升响应速度。

    四.说完饿汉模式来说说懒汉模式

    ? ? ? ?1.懒汉就是太懒了呵呵,每次吃饭时才去找碗筷并且上一次吃了饭都没洗碗,洗了碗再去打饭。

    ? ? ? ?2.懒汉模式就是在程序启动时不创建对象,而在使用时才会去创建。

    ? ? ? ?3.在创建懒汉模式的单例模式时,要注意:

    ? ? ? ? ? ? ①:不能在类外创建对象也就是封装构造和拷贝

    ? ? ? ? ? ? ②:不能直接在程序一启动创建对象,那可以创建一个指向对象的指针提前准备着。

    ? ? ? ? ? ? ③:如果需要创建对象那么该怎么办呢?还是需要一个不依赖对象的接口来创建类对象

    ? ? ? ? ? ? ④:这个对象需要一直存在,并且需要时才创建,所以我们再堆上创建这个对象。

    ? ? ? ? ? ? ⑤:再堆上创建对象就需要释放该空间。

    class Singleton
    {
    public:
    	
    	static Singleton* GetObject()
    	{
    		if (object == nullptr)
    		{
    			object = new Singleton;
    		}
    		return object;
    	}
    private:
    	//将构造函数和拷贝构造函数私有
    	Singleton()
    	{}
    	Singleton(const Singleton& d)
    	{}
    private:
    	static Singleton* object;
    };
    
    Singleton* Singleton::object = nullptr;

    ? ? ? ?4.在上面的单线程运行时没什么问题,那么多线程下呢?

    ? ? ? ?在多线程下,①可能会在创建第一个对象时该线程的时间片刚好用完,下一个线程进来,这样就会导致创建多个对象的问题。

    ? ? ?加一把互斥锁后,②会造成一种情况就是当第一个线程创建对象后后面线程在调用会遇到互斥锁会被迫停下来,很明显已经有对象,还要等待这也显然不合理。所以再加上判断语句,如果已经有对象就不用阻塞直接调用对象。③:在何时释放堆上的空间,显然是最后一个线程调用完毕。程序结束时,我们就在这个类中在定义一个静态类,当这个类结束时也就是程序结束时,在内部类中释放堆上的空间。

    class Singleton
    {
    public:
    	
    	static Singleton* GetObject()
    	{
    		if (object == nullptr)
    		{
    			Mutex.lock();
    			if (object == nullptr)
    			{
    				object = new Singleton;
    			}
    			Mutex.unlock();
    		}
    
    		return object;
    	}
    
    	//负责释放对象空间:
    	class Clear
    	{
    		~Clear()
    		{
    			if (object)
    			{
    				delete object;
    			}
    		}
    	};
    
    private:
    	//将构造函数和拷贝构造函数私有
    	Singleton()
    	{}
    	Singleton(const Singleton& d)
    	{}
    private:
    	static Singleton* volatile object;
    	//互斥锁
    	static mutex Mutex;
    	//
    	static Clear clear;
    };
    
    Singleton* volatile Singleton::object = nullptr;
    mutex Singleton::Mutex;
    Singleton::Clear Singleton::clear;

    ? ? ? ?懒汉模式:①:线程不安全时就加锁

    ? ? ? ? ? ? ? ? ? ? ? ? ?②:只要一个线程在获取对象,所有的线程将会被阻塞,双检测,降低阻塞概率

    ? ? ? ? ? ? ? ? ? ? ? ? ?③:如果编译器对代码进行指令重排,对象可能创建不完整可以使用voliate

    ? ? ? ? ? ? ? ? ? ? ? ? ?④:.什么时机释放单例对象:保证所有线程都不用,在程序退出时

    ? ? ? ? ? ? ? ? ? ? ? ? ?⑤:封装内部类,在内部类的析构函数中释放对象空间

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 珍&源码

    cs