随笔 - 119  文章 - 290  trackbacks - 0

博客搬家了哦,请移步
叫我abc

常用链接

留言簿(12)

随笔分类

我的博客

搜索

  •  

积分与排名

  • 积分 - 302263
  • 排名 - 84

最新评论

阅读排行榜

之所以说这个,是因为之前的一篇文章http://www.cppblog.com/darkdestiny/archive/2006/05/31/7986.html
Arcrest给我一些留言,我特别在意的是他说到的第五条,使用文件这种方法很局限,缺点太多,最重要的等于是给这个类强加了一个读取文件的依赖。如果参数太长,应该考虑重构,用类来替代,至于类实例的初始化,从文件读取还是从网络读取,那是新的类的职责了.
类的初始化,我一直坚持在构造函数中完全进行,而不是放到类似于init函数中等待显式的调用.基于这样的逻辑:一个实例,他诞生是因为需要他,那么他就应该在诞生之时完全做好准备,此时构造和init是连续执行的,那么就应该把init纳入构造函数中.一种反对的意见是构造函数可能会抛出异常,使得类的构造是不完整的,所以把初始化推到init,会是一个完整的类.对于这种反对意见我总是有点窒息,因为我缺少关于不完整构造的知识,好像在《有效C++》里面提到过,不过我没有找到.
在我所做的一些工作中,每个类的初始化是依赖一个ini文件,向构造函数传递一个文件名,然后读取key-value对,所以一直写有一个ConfigFile的类处理这种事情,不知道是不是Arcrest所说的文件依赖,毕竟我的水平还不是太能理解过于简练和抽象的表达.
如果参数太长,应该考虑重构,用类来替代,至于类实例的初始化,从文件读取还是从网络读取,那是新的类的职责了.我不太理解"用类来代替"的意思,不过后面提到的职责使我想到了一个接口.
 1// 接口,从某种数据源中读取指定字段的值
 2class  StreamReader
 3{
 4public:
 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// 单件模式
 3class  StreamReaderManager
 4{
 5public:
 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 阅读(902) 评论(7)  编辑 收藏 引用

FeedBack:
# re: 谈类的初始化 2006-07-03 17:57 pandaxiaoxi
你好,我刚开始写blog,发代码格式很不好看,你的代码怎么那么好看哪?能教教我怎么做的吗?  回复  更多评论
  
# re: 谈类的初始化 2006-07-03 18:16 LOGOS
@pandaxiaoxi
在编辑文章的时候,网站的编辑工具中有一个"代码"的按钮,点击那个你就明白了  回复  更多评论
  
# re: 谈类的初始化 2006-07-04 10:37 天爬者
看到你处理用文件初始化类的代码

我们工程中也大量遇到!原来我们也曾采用过类似你代码里面的方案

但是现在我们采用的是boost序列化的方案来解决

基本上用序列化对比你的方法3个差别

1.一般来说既然有loadfromfile的过程 就还需要写savetofile,boost 把读写的操作统一了。

2.使用键值存取变量导致每个变量都需要有一个 全局唯一字符串的名称,并且使用时候必须知道型别

3.boost封装了标准容器的序列化,而普通方法遇到的时候则必须自己书写迭代读写  回复  更多评论
  
# re: 谈类的初始化 2006-07-04 22:11 笑笑生
boost序列化很方便  回复  更多评论
  
# re: 谈类的初始化 2006-07-05 10:23 LOGOS
谢谢两位.我搜索了一些boost序列化的文章,的确是挺简洁的.  回复  更多评论
  
# re: 谈类的初始化 2006-07-12 15:41 Arcrest
那个参数太长,意思可以考虑把之间有相互关系的参数合并到一个类中作为成员变量,然后传入类的实例

针对接口编程确实才是真正的OOP
用StreamReader/Writer,使得操作配置文件的都针对这个接口来操作,而不关心数据从哪儿来,当然个人觉得,GetValue/SetValue的接口应该和Open/Save分开,打开数据和保存数据的操作一般是开始和结束的,而使用GetValue/SetValue则可能到处都使用,不过还是看你应用了,抽象和分离职责是OOP设计中的最难的。

设计个好的比较通用的配置库确实不容易,以前参考过apache的jakarta commons的Configuration的项目,但是终觉得对C++不适合,缺少的东西太多,人家Java毕竟不只是语言,而更是一个平台。 也看过eMule等开源软件的配置设计,感觉五花八门,什么都有,得出的结论是针对具体的项目写,通用的太难。

以上大侠提到的boost的serialization还没看过,是在io的库中吗?不过boost的都是好东东的说,:)
  回复  更多评论
  
# re: 谈类的初始化 2006-07-13 18:49 LOGOS
嗯.我已经下了boost练习了一下.
发现它不能适合类的初始化,因为初始化的数据是手工编辑的.
boost/serialization的数据格式有3,binary,txt,xml.
binary的基本上不指望能手工编辑.
txt的话基本上看不明白它的结构是如何安排的,也不能手工编辑.
xml的话,虽然有key-value对,但是boost/serialization并不关心配对情形,它参照的只是先后顺序,也就是说:
<key1>5</key1> 和 <key2>5</key2>
<key2>6</key2> <key1>6</key1>
是完全一样的....
顺序过于严格,而key的数量又太多的话,由于编辑数据产生的奇异状况估计没那么容易捕获.

不过对于序列化(非初始化),的确是一个相当棒的方案.  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理