4.6 singleton
singleton即单件模式,实现这种模式的类在程序生命周期里只能有一个且仅有一个实例。单件模式是一个很有用的创建型模式,有许多实际的应用,并被广泛且深入地研究。如果读者还不熟悉这个模式,最好先阅读附录A推荐书目[1],它提供了对singleton模式完整深刻的表述。
虽然单件模式非常重要,但很遗憾目前Boost中并没有专门的单件库,而仅是在其他库中有并不十分完善的实现。虽然不够完善(但比普通实现还是要好很多),但总比没有强。
4.6.1 boost.pool的单件实现
在之前介绍pool库的时候,里面有一个组件名字是singleton_pool,它包含了一个泛型的单件类singleton_default。
singleton_default位于名字空间boost::details::pool,为了使用singleton_ default,需要包含头文件<boost/pool/detail/singleton.hpp>,即:
- #include <boost/pool/detail/singleton.hpp>
- using boost::details::pool::singleton_default;
类摘要
singleton_default的简要声明如下:
- template <typename T>
- struct singleton_default
- {
- public:
- typedef T object_type;
- static object_type & instance();
- };
singleton_default把模板参数T实现为一个单件类,唯一实例只能通过静态成员函数instance()访问。它运用了很巧妙的技术,可以在main()运行之前就创建单件。对类型T的要求是有缺省(无参)构造函数,而且在构造和析构时不能抛出异常,因为单件在main()前后构造和析构,如果发生异常会无法捕获。
用法
在4.5节(第113页)我们定义了一个三维点point,它具有缺省构造函数,因此可以应用于singleton_default,实现一个唯一的原点实例。为了演示singleton_default<>的创建与销毁,下面的代码增加了构造函数与析构函数:
- #include <boost/pool/detail/singleton.hpp>
- using boost::details::pool::singleton_default; //单件名字空间
- class point
- {public:
- point(int a=0, int b=0, int c=0):x(a),y(b),z(c) //构造函数
- {cout << "point ctor" << endl;}
- ~point() //析构函数
- {cout << "point dtor" << endl;}
- ...
- };
-
- int main()
- {
- cout << "main() start" << endl;
- typedef singleton_default<point> origin; //定义单件类
-
- origin::instance().print(); //使用instance()获得单件对象
- cout << "main() finish" << endl;
- }
程序运行结果如下:- point ctor
- main() start
- 0,0,0
- main() finish
- point dtor
这段代码示范了如何使用singleton_default,用法非常简单,只需要把想成为单件的类作为它的模板参数就可以了,接下来的工作由singleton_default自动完成。可能唯一的一点不方便之处是过长的类型名,但可以用typedef来简化。
point的例子可能过于简单,下面再用一个比较接近实际的例子。假设我们要实现一个数据库访问类,它负责程序中所有涉及数据库的操作。很自然,这样的类在程序中只能有一个实例存在,它可以实现为单件。
- class SqlDB_t
- {
- public:
- void connect()
- {cout << "connect db" << endl; }
- void exec(const char *sqlstr)
- {cout << "exec insert/update/delete :" << sqlstr << endl;}
- void query(const char *sqlstr)
- {cout << "exec select " << sqlstr << endl;}
- };
- typedef singleton_default<SqlDB_t> SqlDB;
-
- int main()
- {
- cout << "main() start" << endl;
-
- SqlDB::instance().connect();
- SqlDB::instance().exec("create table goods(int id, varchar name(20)");
- SqlDB::instance().exec("insert into goods values(101, 'wii')");
- SqlDB::instance().query("select * from goods");
-
- cout << "main() finish" << endl;
- }
程序运行结果如下:- main() start
- connect db
- exec insert/update/delete :create table goods(int id, varchar name(20)
- exec insert/update/delete :insert into goods values(101, 'wii')
- exec select select * from goods
- main() finish