“面向过程”时,我们常常在想“干什么”、“做什么”、“处理什么”……,“基于对象”时,我们开始想:“它是什么”,INI文件的对象,这家伙是什么?
从实体上看,先把list <string> 放进来:
class INI
{
private:
list <string> _lines;
};
“_lines”的内容从何处来?何时来?一是构造时可以指定文件名,从而在构造过程中读入,二是先空构造,后面再使用类似两段式构造的方法,提供一个Load方法,顺便,我们把此INI的文件名也保存下来:
class INI
{
public:
INI() = default;
INI(string const& filename);
bool Load(string const& filename);
private:
list <string> _lines;
string _filename;
};
_lines和_filename都支持“傻白甜”方式的复制,因此INI类的拷贝,复制等都可以延用默认的行为。
正确读入文件,则_lines就有该文件的内容,而_filename记录文件名称;无法正确读入文件,则_lines应为空,但文件名应保留。这就是INI类当前的不变式。能读还能要写,再新增一个函数用于保存INI文件:
class INI
{
public:
INI() = default;
INI(string const& filename);
bool Load(string const& filename);
bool Save(string const& filename);
private:
list <string> _lines;
string _filename;
};
等一下!INI已经保留原来的文件名,所以“保存(Save)”函数应该不再需要传入“filename”才对呀,需要提供新文件名的那个版本,应该叫“另存为(SaveAs)”才对:
class INI
{
public:
INI() = default;
INI(string const& filename);
bool Load(string const& filename);
bool Save()
{
assert(!this->_filename.empty());
SaveAs(this->_filename);
}
bool SaveAs(string const& filename);
private:
list <string> _lines;
string _filename;
};
因为要关心并记录处理过程中存在的隐患,再为该类增加几个成员:
class INI
{
public:
INI() = default;
INI(string const& filename);
bool Load(string const& filename);
bool Save()
{
assert(!this->_filename.empty());
SaveAs(this->_filename);
}
bool SaveAs(string const& filename);
list <string> const& GetWarningList() const
{
return _warning_list;
}
private:
list <string> _lines;
string _filename;
list <string> _warning_list;
};
哇,INI类看起来功能已经远超“面向过程”版本的两个函数了,既有警告和出错信息,还可以有另存功能!太强悍了!“面向过程”听着乐了:“不吹牛会死吗?你们还没干正事呢,规定动作“读”和“写”一个都没实现啊!”
【危险】:小心得“对象十全大补综合症”!
“基于对象”或“面向对象”程序设计时,一定要谨记:“简单而完整!”坚决避免:一,脱离实际使用需求,完全按现实中对象的功能设计类型;二,沉迷于“功能适用性”、“功能灵活配置”等乱加的功能。