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