之所以说这个,是因为之前的一篇文章
http://www.cppblog.com/darkdestiny/archive/2006/05/31/7986.htmlArcrest给我一些留言,我特别在意的是他说到的第五条,
使用文件这种方法很局限,缺点太多,最重要的等于是给这个类强加了一个读取文件的依赖。如果参数太长,应该考虑重构,用类来替代,至于类实例的初始化,从文件读取还是从网络读取,那是新的类的职责了.
类的初始化,我一直坚持在构造函数中完全进行,而不是放到类似于init函数中等待显式的调用.基于这样的逻辑:一个实例,他诞生是因为需要他,那么他就应该在诞生之时完全做好准备,此时构造和init是连续执行的,那么就应该把init纳入构造函数中.一种反对的意见是构造函数可能会抛出异常,使得类的构造是不完整的,所以把初始化推到init,会是一个完整的
空类.对于这种反对意见我总是有点窒息,因为我缺少关于不完整构造的知识,好像在《有效C++》里面提到过,不过我没有找到.
在我所做的一些工作中,每个类的初始化是依赖一个ini文件,向构造函数传递一个文件名,然后读取key-value对,所以一直写有一个ConfigFile的类处理这种事情,不知道是不是Arcrest所说的文件依赖,毕竟我的水平还不是太能理解过于简练和抽象的表达.
如果参数太长,应该考虑重构,用类来替代,至于类实例的初始化,从文件读取还是从网络读取,那是新的类的职责了.我不太理解"用类来代替"的意思,不过后面提到的职责使我想到了一个接口.
1
// 接口,从某种数据源中读取指定字段的值
2
class StreamReader
3![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
4
public:
5
virtual ~StreamReader();
6
virtual const string& GetType() const;
7
virtual void Open(const string &src);
8
virtual void Close();
9
virtual void GetValue(const string &key, int &value) const;
10
virtual void GetValue(const string &key, float &value) const;
11
virtual void GetValue(const string &key, string &value) const;
12
}; 那么根据可能的不同的数据源,比如ini文件,或者xml文件,或者二进制文件,又或者网络,都可以写出相应的子类.然后由需要初始化的类创建StreamReader实例,从传入构造函数的字符串打开相应的源,进行读取.
那么应该创建哪种源的StreamReader的实例呢?需要初始化的类不应该负责判断这些东西吧?是的,不需要,所以需要包装一个负责判断这些区别的类.
1
// 负责注册,管理,判断,打开
2
// 单件模式
3
class StreamReaderManager
4![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
5
public:
6
static StreamReaderManager& GetSingleton();
7
void Register(StreamReader &sr);
8
// 这个就是负责判断源类型并创建适当StreamReader的地方
9
StreamReader* Open(const string &src);
10
}; 利用这个manager,在需要初始化的类里面就可以比较好看的初始化你那海量的成员变量了.
^_^,感谢Arcrest
posted on 2006-07-02 13:12
LOGOS 阅读(899)
评论(7) 编辑 收藏 引用