本帖最后由 baizy77 于 2019-8-30 14:55 编辑
作者: 女儿叫老白 转载请注明出处! ---------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------
引言 ---------------------------------------------------------------- 在很多人共同开发一个软件项目时,大家会分别负责不同的模块开发,最后把这些模块拼接成一个完整的程序。很多情况下,这些模块之间需要共享一些配置数据。这时,可能有人首先想到了全局变量。全局变量的确也能达到目的,但是我们有一个更好的选择,就是采用设计模式中的单体模式。本节,我们为朋友们介绍一下单体模式实现全局配置的方法。
正文 ---------------------------------------------------------------- 单体模式(Singleton),顾名思义,指的是只有一个实体。那么怎样做才能让配置只有一个实体呢? 在本节示例代码中,我们的保存配置信息的类为CConfig。为了实现单体模式,我们需要把CConfig做一下改造:把构造函数、析构函数、拷贝构造函数声明为私有成员: 代码清单04-19-01 config.h - class KS04_19_CONFIG_Export CConfig {
- // ……
- private:
- /**
- * @brief 构造函数,定义为私有的目的是防止他人使用该类构造对象。
- * @return 无
- */
- CConfig() { }
- /**
- * @brief 拷贝构造函数,定义为私有的目的是防止编译器调用默认的拷贝构造
- * 函数隐式构造该类的对象。
- * @return 无
- */
- CConfig(const CConfig&);
- /**
- * @brief 析构造函数,定义为私有的目的是防止他人用delete语句删除单体对象。
- * @return 无
- */
- ~CConfig(){}
- };
复制代码代码清单04-19-01中: 在第3~8行,为了保证该类对象只有一个实体存在,我们将构造函数声明为私有的,目的是防止他人使用该类构造对象(如果将类的构造函数声明为私有,则new CConfig这种代码将会被编译器报错,因为编译器无法调用私有的构造函数来构造对象,只能调用public的构造函数)。 我们将析构函数声明为私有,目的是防止他人用delete语句删除我们构造的单体对象。 另外,我们将拷贝构造函数也声明为私有,目的是防止编译器调用默认的拷贝构造函数隐式构造该类的对象。 好了,把所有能够构造对象的入口封住之后,我们来创建自己的接口来构造单体对象,方法如下,为CConfig添加一个私有成员: 代码清单04-19-02 config.h - class KS04_19_CONFIG_Export CConfig {
- // ......
- public:
- static CConfig& instance();
- private:
- static CConfig s_config; /// 配置对象实例
- // .....
- };
复制代码代码清单04-19-02中: 在第6行,定义了一个私有的static成员对象。朋友们看到了吗?这个私有成员的类型就是CConfig。请注意,此行代码并不能构造该s_config对象,我们需要单独对其进行构造: 代码清单04-19-03 config.cpp: - CConfig CConfig::s_config;
- CCfonfig::CConfig(){
- //......
- }
复制代码代码清单04-19-03中: 第1行的代码表示构造该s_config对象。
回到代码清单04-19-02: 在第4行,提供一个static接口用来访问该静态对象。 该接口实现如下: 代码清单04-19-04 config.cpp - CConfig& CConfig::instance() {
- return s_config;
- }
复制代码代码清单04-19-04中: 该接口的实现比较简单,直接返回之前定义的static对象即可。
到此为止,单体类定义好了。那么该怎么使用单体类呢?其实很简单。方法就是使用static接口的调用语法,如下代码将得到该单体对象的引用: 比如,在本节示例代码中,我们在dll中调用该单体对象的接口设置参数: 代码清单04-19-05 model.cpp
- bool CModel::initialize() {
- CConfig::instance().setSelectRadius(3.f);
- return true;
- }
复制代码代码清单04-19-05中; 第2行,通过CConfig::instance()静态接口得到单体对象的引用,然后调用其setSelectRadius()接口。 然后,我们在exe中调用该单体对象的接口获取刚刚设置的参数: 代码清单04-19-06 mian.cpp
- int main(int argc, char * argv[]) {
- CModel model;
- model.initialize();
- qreal r = CConfig::instance().getSelectRadius();
- cout << "r = " << r << endl;
- return 0;
- }
复制代码
结语 ---------------------------------------------------------------- 在本节中,我们介绍了通过单体模式实现全局配置的方法。在设计单体类时,需要注意的是下面几点: 1). 将构造函数、析构函数、拷贝构造函数声明为私有成员。拷贝构造函数可以只定义不实现。 2). 为单体类添加一个static成员变量,类型为该单体类。在cpp中需要用以下语句进行定义:
- CConfig CConfig::m_config;
复制代码 3). 为单体类添加一个static成员接口,比如instance(),该接口无参数,返回类型为类的引用或类指针,该接口内部返回static成员变量的引用或指针。 4). 如果在静态接口instance()内部构造一个static对象并返回该对象的引用,那么建议使用全局锁保护该static对象。如果作为类的成员变量,则不需要用锁保护(如果是指针类型的成员变量,则需要用锁进行保护)。 5). 该单体对象的使用方法是通过类的static接口instance(): 好了,朋友们可以练习一下编写自己的单体类啦。
|