《C++代码整洁之道:C++17 可持续软件开发模式实践》 —3.5 信息隐藏原则
3.5 信息隐藏原则
信息隐藏原则是软件开发中一个众所周知的基本原则,它首先记录在开创性论文“On the Criteria to Be Used in Decomposing Systems Into Modules”[Parnas72]中,由David L. Parnas于1972年撰写。
该原则指出,一段代码调用了另外一段代码,那么,调用者不应该知道被调用者的内部实现。否则,调用者就有可能通过修改被调用者的内部实现而完成某个功能,而不是强制性地要求调用者修改自己的代码。
David L. Parnas认为信息隐藏是把系统分解为模块的基本原则,Parnas同样认为系统模块化是为了隐藏困难的设计决策或可能改变的设计决策,应该涉及隐藏困难的设计决策或可能改变的设计决策,软件单元(例如,类或组件)暴露于其环境的内部构件越少,该单元的实现与其客户端之间的耦合就越低。因此,软件单元内部实现的更改将不会被其使用者所察觉。
信息隐藏有很多优点:
限制了模块变更的范围。
如果需要修复缺陷,对其他模块的影响最小。
显著提高了模块的可复用性。
模块具有更好的可测试性。
信息隐藏通常与封装混淆,但其实它们不一样,这两个术语在许多著名的书籍中是同义词,但我并不这么认为。信息隐藏是帮助开发人员找到好的设计模块的原则,该原则适用于多个抽象层次并能展现其正面效果,特别是在大型系统中。
封装通常是依赖于编程语言的技术,用于限制对模块内部的访问。例如,在C++中,你可以在private关键字后定义一些类成员,以确保类外部无法访问它们,但我们仅用这种防护方式进行访问控制,离自动隐藏信息还远着呢,封装有助于但不能保证信息隐藏。
以下代码示例展示了隐藏信息较差的封装类:
代码3-1 一个自动转向门的类(摘录)
这不是信息隐藏,因为类内部的实现部分暴露给了外部环境,尽管该类看起来封装得很好。注意getState返回值的类型,客户端用到的枚举类State用到了这个类,如下示例所示:
代码3-2 必须使用AutomaticDoor查询门的当前状态的示例
枚举类(结构体)[C++11]
在C++11中,枚举类型也有了创新。为了向下兼容早期的C++标准,现在仍存在众所周知的枚举类型及其关键字enum。从C++11开始,我们还引入了枚举类和枚举结构体。
旧的C++枚举类型有一个坏处是,它们将枚举成员引入周围的命名空间,导致了名称冲突,如下示例所示:
此外,旧的C++ enum会隐式转换为int,当我们不预期或不需要这样的转换时会导致难以察觉的错误:
当使用枚举类(也称为“新枚举”或“强枚举”)时,这些问题将不再存在,它们的枚举成员对枚举来说是局部的,并且它们的值不会隐式转换为其他类型(比如另一个枚举或int类型)。
对于现代C++程序,强烈建议使用枚举类而非普通的旧的枚举类型,因为它使代码更安全,并且因为枚举类也是类,所以它们可以前向声明。
如果必须更改AutomaticDoor的内部实现并从类中删除枚举类State,那么会发生什么呢?很容易看出它会对客户端的代码产生重大影响,它将导致使用成员函数AutomaticDoor::getState()的所有地方都要进行更改。
以下是具有良好的信息隐藏性的封装的AutomaticDoor类:
代码3-3 一个更好的自动门转向设计类
代码3-4 类AutomaticDoor被修改后的简洁例子
现在,修改AutomaticDoor类的内部要容易实现得多。客户端代码不再依赖于类的内部实现。现在你可以在不引起该类任何用户注意的情况下,删除State枚举并将其替换为另一种实现。
- 点赞
- 收藏
- 关注作者
评论(0)