zoukankan      html  css  js  c++  java
  • 设计模式C++达到 1.辛格尔顿

    实现类的单个案件的Singleton模式。该系统有一个类只有一个实例,而本实施例是容易的外部访问。所以容易控制的实例的数量,并且节省系统资源。

    单的情况下通常与一些非本地静态对象的使用,对于这些对象,计划是难以控制。对于那些具有全球影响,持久对象和一般的存在,根据某些约束有时需要被初始化或顺序,始化这些对象假设不使用单例方法的话会极度不安全。这个时候就要使用单例模式来解决问题。

    实现单例的方法有非常多,最简单的一个是将对象放入函数中作为其静态成员:

    class SingleTon;
    SingleTon* getSingleTonInstance(){
    	static SingleTon* instance = new SingleTon(); 
    	return instance;
    }
    class SingleTon{
    	friend SingleTon* getSingleTonInstance();
    private:
    	SingleTon(){}
    };
    这是我觉得的最简单的实现单例模式的方法,不足的地方在于这个获得单例对象的函数不在类内。

    首先要实现单例模式,将构造函数声明为稀有。这样构造函数就不能被方法,也不能任意创建单例类的对象。而这里获得实例为函数的静态对象,所以其仅仅有一个。且存在时间为创建到程序结束。

    当然。也能够将函数中的静态对象改为类中的静态对象,而将这个全局的函数设置为类中的静态函数,这样就得到一个更加普遍经常使用的形式:

    class SingleTon{
    public:
    	static SingleTon* getInstance(){
    		static SingleTon* instance = new SingleTon();
    		return instance;
    	}
    	~SingleTon(){}
    private:
    	SingleTon(){	}
    	SingleTon(const SingleTon&);
    	SingleTon& operator=(const SingleTon&);
    };
    这里还是使用了函数中的静态成员,使用类中的静态成员也是能够的:

    class SingleTon{
    public:
    	static SingleTon* getInstance(){
    		if(NULL == instance)
    			instance = new SingleTon();
    		return instance;
    	}
    
    private:
    	SingleTon(){	}
    	SingleTon(const SingleTon&);
    	SingleTon& operator=(const SingleTon&);
    	static SingleTon* instance;
    };
    SingleTon* SingleTon::instance;// = new SingleTon();类内的静态成员初始化能够调用类中的私有的构造函数。

    为了安全性,这里将复制构造函数和赋值操作符都给隐藏了。可是析构函数还是可见的,程序猿还是会误用delete来删除这个单例实体,这样是不安全的,能够选择将析构函数放入私有中。隐藏析构函数,对于一些对象在最后结束时析构。则不用关心其释放过程。

    可是假设在程序运行中要调用析构函数进行实例的删除的话,就使用一个公有的函数来封装析构函数,且将析构函数置为私有:

    class SingleTon{
    public:
    	static SingleTon* getInstance(){
    		if(NULL == instance)
    			instance = new SingleTon();
    		return instance;
    	}
    	static void delelteInstance(){
    		if(NULL != instance){
    			delete instance;
    			instance = NULL;
    		}
    	}
    private:
    	SingleTon(){	}
    	SingleTon(const SingleTon&);
    	SingleTon& operator=(const SingleTon&);
    	static SingleTon* instance;
    	~SingleTon();
    };
    SingleTon* SingleTon::instance ;

    这里就已经基本上在单线程上安全了,然后就考虑多线程。当多个线程企图同一时候初始化 单例实例时,就出现了问题,要使用相互排斥来解决这个问题。这里就使用临界区来解决:

    CRITICAL_SECTION cs;
    class SingleTon{
    public:
    	static SingleTon* getInstance(){
    		if(NULL == instance){
    			EnterCriticalSection(&cs); 
    			if(NULL == instance){//双检锁。在进入临界区后再检測一次是否对象已经建立
    				instance = new SingleTon();
    			}
    			LeaveCriticalSection(&cs);  
    		}
    		return instance;
    	}
    	static void delelteInstance(){
    		if(NULL != instance){
    			EnterCriticalSection(&cs);
    			if(NULL != instance){
    				delete instance;
    				instance = NULL;
    			}
    			LeaveCriticalSection(&cs);  
    		}
    	}
    private:
    	SingleTon(){	}
    	SingleTon(const SingleTon&);
    	SingleTon& operator=(const SingleTon&);
    	static SingleTon* instance;
    	~SingleTon();
    };
    SingleTon* SingleTon::instance ;
    这里使用双检锁的机制,第一次是推断是否须要对实例进行操作,第二次是在进入临界区即对数据加锁后,推断在数据已经不会再被外界干扰的情况下。第一次推断和第二次推断之间是否被其它线程进行了操作,这样两次推断保证了实例的安全。

    可是这样还是不够安全。由于多线程中还是会有一些特殊情况,在类中一些文件被锁了,如文件句柄,数据库连接等,这些随着程序的关闭并不会马上关闭资源。必需要在程序关闭前,进行手动释放。

    这里的指不会自己主动关闭。是对于析构函数是私有的情况下,由于系统无法訪问私有的析构函数。对于没有这些连接时。即类仅仅在内存中占领了一些地址,则系统将其视为全局变量。在结束时释放其所在内存资源,所以没有内存泄漏。而若类中有文件句柄和数据库连接这些东西。系统并不会帮忙关闭这些。所以必须手动的调用析构函数中对这些文件的关闭操作。

    对于这种情况,通常会使用一种私有内嵌类Garbo,意为垃圾工人。在单例类中包括一个私有的静态垃圾工人对象,当程序结束时。系统会调用这个对象的析构函数,而这个析构函数中对单例类对象实现析构。

    CRITICAL_SECTION cs;
    class SingleTon{
    public:
    	static SingleTon* getInstance(){
    		if(NULL == instance){
    			EnterCriticalSection(&cs); 
    			if(NULL == instance){//双检锁。在进入临界区后再检測一次是否对象已经建立
    				instance = new SingleTon();
    			}
    			LeaveCriticalSection(&cs);  
    		}
    		return instance;
    	}
    	static void delelteInstance(){
    		if(NULL != instance){
    			EnterCriticalSection(&cs);
    			if(NULL != instance){
    				delete instance;
    				instance = NULL;
    			}
    			LeaveCriticalSection(&cs);  
    		}
    	}	
    	
    private:
    	SingleTon(){	}
    	SingleTon(const SingleTon&);
    	SingleTon& operator=(const SingleTon&);
    	static SingleTon* instance;
    	~SingleTon(){}//对应的关闭连接等操作
    	class GarBo{
    		public:
    			~GarBo(){
    				if(NULL != instance){
    					EnterCriticalSection(&cs);
    					if(NULL != instance){
    						delete instance;
    						instance = NULL;
    					}
    				LeaveCriticalSection(&cs);  
    				}
    			}
    	};
    	static GarBo gc ;
    };
    SingleTon* SingleTon::instance ;
    SingleTon::GarBo  SingleTon::gc;//类外的初始化。

    这样就得到更加完美的单例类。


    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    一个很香的python练习网站
    关于接口测试用例设计的一些思考
    pytest、tox、Jenkins实现python接口自动化持续集成
    django实战商城项目注册业务实现
    面试测试开发被问到数据库索引不知道怎么办?这篇文章告诉你
    python框架Django实战商城项目之用户模块创建
    python框架Django实战商城项目之工程搭建
    golang在gitlab中的工作流
    kubernetes extension point
    kubernetes controller 实现
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4822167.html
Copyright © 2011-2022 走看看