之前花过一段时间学习设计模式,现在对于很多模式只留下一些感性的认识了。最常用的设计模式是策略模式 、工厂模式;最有用的设计原则是封装、组合>继承。
以前的项目中大家为了简化往往忽视了设计模式的存在,这往往造成了项目维护的困难。现在又要进行新的代码编写了,希望能在设计之初考虑到这些问题,也方便以后代码维护的人。
今天我记录一个简单的模式:单件模式。单件,毫无疑问就是独一无二的对象,其实在程序中这种对象有很多,例如存储系统配置信息的对象、接受和发送socket或是其他消息的对象、存储一些全局信息的对象,这些对象在系统中都是唯一的,它们建立好之后将不会销毁,直到程序终止(当然独一无二不意味着不销毁)。
下面还是用代码说话把,下面代码位于三个文件中,分别为:configurator.h(Configurator类的定义头文件)、configurator.cpp(Configurator类的方法实现文件)、test_singleton.cpp(测试文件)。在C++中文件的划分是很重要的,这在大型程序中尤其如此,关于头文件的定义大家可以参考C++ Prime,上面讲的还是挺好的。(曾经又一次错误的在头文件中写下了using namespace std;结果导致各种莫名奇妙的编译错误,汗啊~)
FileName: configurator.h
#ifndef _CONFIGURATOR_H_
#define _CONFIGURATOR_H_
//this class has only one instance.
class Configurator{
public:
static Configurator* only();
void setFlag(int newFlag);
int getFlag();
//NOT IMPLEMENTED ,AVOID MISUSE.
Configurator(const Configurator&);
Configurator& operator=(Configurator);
private:
//if it has child class, the Constructor should be protected.
Configurator();
static Configurator* instance;
int flag;
};
#endif
FileName: configurator.cpp
#include <iostream>
#include "configurator.h"
using namespace std;
Configurator* Configurator::instance=NULL;
Configurator::Configurator():flag(2){
cout<<"I have been builded."<<endl;
}
Configurator* Configurator::only(){
//if you want destory the class after use,you can do define instance here
//static Confiugrator * instance=NULL;
if(instance==NULL){
instance= new Configurator;
}
return instance;
}
void Configurator::setFlag(int newFlag){
flag = newFlag;
}
int Configurator::getFlag(){
return flag;
}
FileName: test_singleton.cpp
#include <iostream>
#include "configurator.h"
using namespace std;
int main(){
cout<<"start building Configurator."<<endl;
Configurator* first = Configurator::only();
cout<<"first: flag is:"<<first->getFlag()<<endl;
first->setFlag(7);
cout<<"first: flag is:"<<first->getFlag()<<endl;
//the other block.
{
Configurator* second=Configurator::only();
cout<<"second: flag is:"<<second->getFlag()<<endl;
second->setFlag(9);
cout<<"second: flag is:"<<second->getFlag()<<endl;
}
cout<<"now first: flag is:"<<first->getFlag()<<endl;
}
编译并运行:
# g++ configurator.cpp test_singleton.cpp # ./a.out
代码的运行结果如下:
start building Configurator. I have been builded. first: flag is:2 first: flag is:7 second: flag is:7 second: flag is:9 now first: flag is:9
从Configurator类的定义中可以看出它和普通类的定义所不同的有以下几点:
1 、构造函数被定义为private,(如果有子类可以定义为protected),即对于外界不能通过构造函数来得到实例类型。如果你试图定义一个Configurator myCfg;编译时就会报错;获得实例变量的唯一办法就是调用only类方法,这也就保证了类的唯一性。
[题外话]调用类的默认构造方法时应该写成Configurator myCfg; 而不是 Configurator myCfg();因为后者编译器会认为是方法的定义。
2、为了进一步保证类的唯一性,在定义中把“构造拷贝函数”、“赋值函数”只进行声明而没有定义,这样可以防止某些人拷贝此单件类。如果试图拷贝的话可以通过编译,但链接时会报错(因为找不到对应的方法)。
3、单件类包含有一个private的指向自己类型的指针,并且此指针定义成static类型,即全局的指针,可以用于指向此单件对象,并保证此对象的唯一性。
众所周知,C++是支持全局变量的(当然也可以是全局的类变量),但是全局变量的出现使得程序文件中充斥了extern等字样,很多人提倡取消全局变量,它有很多缺点,其中包括降低代码的可读性,增加代码的维护难度,但全局方法有一个很大的优点:简单。不过我们还是应该尽量不用全局变量,相比而言,单件模式就是一个很好的解决方案,它可以让代码更易与维护并且避免一些不必要的错误。
[题外话]很多事情存在都有它存在的理由,在实际中我们需要进行权衡,我们选择的不一定是最好的,但一定应该是最适合自己的。
Recent Comments