singleton pattern,又称单件模式,或者单例模式。singleton要求类有且仅有一个实例,并给其他对象提供这一实例。

控制类实例仅有一个,办法有两个:
1.私有化构造函数与copy构造函数,使用一个函数静态变量
1 #include <iostream> 2class People{ 3private: 4 People(std::string name,int age); 5 People( const People&); 6public: 7 friend People& MadePeople( ); 8public: 9void show( );10private:11 std::string name;12int age;13};1415void People::show( )16{17 std::cout<<"The people's name is "<<name<<std::endl;18 std::cout<<"The people's age is "<<age<<std::endl;19}2021 People& MadePeople( )22{23static People onlyPeople("tom",16);24return onlyPeople; 25}2627int main( int argc,char **argv)28{29 MadePeople( ).show( );30return0;31 }
结果为:

1 #include <stdexcept> 2 #include <iostream> 3class TooManyPeople:public std::exception 4{ 5public: 6 TooManyPeople(std::string e) 7 :errorMsg(e) 8 {} 9 ~TooManyPeople( ) throw( ) {}10constchar * what( ) constthrow( );11private:12 std::string errorMsg;13};14constchar* TooManyPeople::what( ) constthrow( )15{16return errorMsg.c_str( );17}18class People{19private:20static std::size_t numPeople;21 People(const People&);22public:23 People(std::string name,int age);24 ~People( );25private:26 std::string name;27int age;28 };29 size_t People::numPeople = 0;30 People::People(std::string n,int a:w )31{32if(numPeople > = 1)33 {34throw TooManyPeople("Error:Too Many People");35 }36 name=n;37 age=a;38 ++numPeople;39}4041 People::~People( )42{43 --numPeople;44}4546int main(int argc,char **argv)47{48try49 {50 People p1("tom",17);51 People p2("sam",15); 52 }53catch(std::exception &e)54 {55 std::cerr<<e.what( )<<std::endl;56 }57return0;58 }
运行结果为

这里开放了一个方法来实例化该对象,我们在该方法中加入了逻辑判断,并在类中有一个静态变量来指示该类的实例化数量是多少?当该指示变量大于等于1的时候,我们就封锁该方法,禁止实例化更多的对象,小于的时候就进行实例化,并修改指示变量。所以这里完成了限制实例化个数为1的要求。(这里提示下,如果在多线程下面,指示变量是一个互斥资源)
扩展
现在假设我们规定,环境里只有一个男人和一个女人
class Man:public People{ ... };class Women:Public People{ ... };Man m;Women w;
这里按我们本意是行的通的,控制每一个类只有一个对象,但是实际上,这里建立Women对象是行不通的。因为构造Man会调用基类构造函数People( ),在构造Women的时候调用构造函数People( ),就会报错。当然当其他类包含People对象时候,会发生同样的问题。
1class Robot2{3private:4 ...5 People p; //有类似人的能力6 ...7}8Robot h1;9 Robot h2; //错误
这里被嵌入更大的对象,作为它派生类的基类,这些混淆了存在对象的数目,编程(www.cppentry.com)的本意与编译器不一致。通常我们仅仅对对象本身存在的情况做限制,而不是其他对象。如果采用第一种方式实现单例模式方法,就很容进行这种限制,而且不会影响到其他对象。因为People构造函数是private,带有private构造函数的类不能作为基类使用,也不能嵌入到其他对象中。那么下面一种给我们提供了解决上面因被继承或者嵌入其他对象中造成了混淆的问题思路,如下:
1class T{ 2public: 3static T * makeT( ); 4static T * makeT( const T& rhs); 5 ... 6private: 7 T( ); 8 T(const T& rhs); 9 ...10};11 T * T::makeT( )12{ 13returnnew T( );14}1516 T* T::makeT( const T& rhs)17{ 18returnnew T(rhs);19 }
那么摆脱上述两种现象问题,在此前代码基础上改正可以得到以下代码:
1 #include <stdexctpt> 2 #include <iostream> 3 #include <memory> 4class tooManyPeople:public std::exception 5{ 6public: 7 TooManyPeople(std::string e) 8 :errorMsg(e) 9 {}10 ~TooManyPeople( ) throw( ) {}11constchar * what( ) constthrow( );12private:13 std::string errorMsg;14};15constchar* TooManyPeople::what( ) constthrow( )16{17return errorMsg.c_str( );18}19class People{20private:21static std::size_t numPeople;22 People(const People&);23 People(std::string name,int age);24public:25static People* MakePeople(std::stirng n,int a);26 ~People( );27private:28 std::string name;29int age;30 };31 size_t People::numPeople = 0;32 People::People(std::string n,int a:w )33{34if(numPeople > = 1)35 {36throw TooManyPeople("Error:Too Many People");37 }38 name=n;39 age=a;40 ++numPeople;41}4243 People* People::MakePeople(std::string n,int a)44{45returnnew People(n,a);46}4748 People::~People( )49{50 --numPeople;51}5253int main(int argc,char **argv)54{55try56 {57 std::auto_ptr<People> p1(People::MakePeople("tom",19));58 std::auto_ptr<People> p2(People::MakePeople("tom",20));59 }60catch(std::exception &e)61 {62 std::cerr<<e.what( )<<std::endl;63 }64return0;65 }
运行结果与上面一致。这里我们控制的实例个数为1个,其实可以稍稍改动一下代码,就可以实现将控制的实例个数为N个了。
1class People{ 2public: 3class TooManyPeople{ }; 4static People * makePeople( ); 5static People * makePeople( const People& rhs); 6 ... 7private: 8static size_t numPeople; 9staticconstint maxPeople ;10 People( );11 People(const People & rhs);12}13 size_t numPeople = 0;14constint maxPeople=5;15 People* People::makePeople( )16{17returnnew People( );18}19 People* People::makePeople(const People rhs)20{21returnnew People(rhs)22}23People::People( )24{25if(numPeople>=maxPeople)26 {27throw TooManyPeople;28 }29 ...30 ++numPeople;31}32 People::People(const People& rhs)33{34if(numPeople>=maxPeople)35 {36throw TooManyPeople;37 }38 ....39 ++numPeople;40}41 People::~People( )42{43 --numPeople;44 }
那么上面一段代码就可以很好完成控制类的实例化数目了。但是我们还可以进一步扩展,如果代码要求有大量类需要控制类的实例化数目,那么我们需要一遍又一遍的编写上面类似的代码,这样我们不累吗 其实我们可以写一个控制类实例化的模版基类,需要控制实例化的类继承该模版基类即可。
View Code 1 #include <iostream> 2 #include <stdexcept> 3 #include <memory> 4 template <typename T> 5class tooManyPeople:public std::exception 6{ 7public: 8 TooManyPeople(std::string e) 9 :errorMsg(e) 10 {} 11 ~TooManyPeople( ) throw( ) {} 12constchar * what( ) constthrow( ); 13private: 14 std::string errorMsg; 15}; 16 17constchar* TooManyPeople::what( ) constthrow( ) 18{ 19return errorMsg.c_str( ); 20} 21 22 tempalte <typename T> 23class counted 24{ 25public: 26staticint objectCount( ) { return numObject; } 27protected: 28 counted( ); 29 counted(const Counted& rhs); 30 ~Counted( ) { --numObject; } 31private: 32staticconst std::size_t maxObject; 33staticint numObject 34void init( ); 35}; 36 37 template<typename T> int count<T>::numObject=0; 38 39 template<typename T> const std::size_t counted<T>::maxObject=2; 40 41 template<typename T> counted<T>::counted( ) 42{ 43 init( ); 44} 45 46 template<typename T> counted<T>::counted( const counted& rhs) 47{ 48 init( ); 49} 50 51 template<typename T> void counted<T>::init( ) 52{ 53if(numObject >=maxObject) 54 { 55throw tooManyObject("Error: Too Many Object!!"); 56 } 57 ++numObject; 58} 59 60class People:private Counted<People> 61{ 62public: 63static People * makePeople( ); 64static People * makePeople( const std::string n,constint a); 65static People * makePeople(const People& rhs); 66 ~People( ); 67using Counted<People>::objectCount; 68private: 69 People( ) 70 :name(""),age(0) 71 {} 72 People(const std::string n,constint a) 73 :name(n),age(a) 74 {} 75 People( const People & rhs); 76private: 77 std::string name; 78int age; 79} 80 81 People::People(const People & rhs) 82{ 83 name=rhs.name; 84 age=rhs.age; 85} 86 87 People* People::makePeople( ) 88{ 89returnnew People( ); 90} 91 92 People* People::makePeople( const std::string n,constint a) 93{ 94returnnew People(n,a); 95} 96 97 People* People::makePeople(const People & rhs) 98{ 99returnnew People(rhs);100}101102int main( int argc,char ** argv)103{104try105 {106 std::auto_ptr<People> p1(People::makePeople("tom",16));107 std::cout<<"The number of object is"<<People::counted<People>::objectCount( )<<std::endl;108 std::auto_ptr<People> p2(People::makePeople( ));109 std::cout<<"The number of object is"<<People::counted<People>::objectCount( )<<std::endl;110 std::auto_ptr<People p3(People::makePeople("sim",15));111 }112catch(std::exception &e)113 {114 std::cerr<<e.what( )<<std::endl;115 }116return0;117 }
运行结果为:

这里说明一下为什么是私有继承,因为这里使用着是不需要关心这个Counted这个计数基类,所以这里采用私有继承是最好的方式。

