32.面向未来编程

前言

 
唯一不变的就是变化本身。


软件的变化性

 
好的软件能够适应变化。软件的灵活性、健壮性、可靠性是程序员们在满足当前需求并关注将来的可能后设计和实现出来的。优秀的软件是那些时刻关注未来的人们编写的。
什么会发生变化呢?继承体系会变,现在的派生类将会是以后的基类;运行平台会变;程序的维护人员会更替,因此程序应该被设计得易于被别人理解、维护和扩充 。


如何表达设计条件的约束

 
我们应该习惯于使用C++语言自身来约束程序的性质,而不是依赖注释或文档
如果一个类不可继承,那么应该按照More Effective C++ 26中的方法阻止。
如果一个类的实例必须创建于heap中,应该用More Effective C++ 27中的方法来强迫完成。
如果一个类的拷贝构造或赋值无意义,则应该将它们设置为private。
当我们定义成员函数时,应该判明其意义,以及派生类中的它是否有意义。如果它在派生类中依然存在意义,则令它为虚函数,即使当前并不需要override。如果不存在任何意义,声明为非虚函数。确保更改是为了整个类的运行环境和类所表示的抽象,而非仅仅满足某个需求。(Effetive C++ 35)
处理每个类的赋值和拷贝构造函数,以防止有人误调编译器提供的默认版本而产生意料之外的结果。(Effective C++ 07)
当我们建立一个类时,努力保证其操作和语法自然且直观,自定义数据类型的行为尽量与内置类型保持一致。(Effective C++ 19)
要确信用户必然会犯错,因此你的类必须设计得可以预防、检测、及修正这些错误。(Effective C++ 18)
努力去写可移植的代码。只有在性能极其重要时采用不可移植的结构才是可取的。
尽可能地封装,将实现细节申明为私有。(Effective C++ 23、29)
尽可能使用无名命名空间和文件内的静态对象或函数。(More Effective C++ 31)
避免导致虚基类的设计,因为这种类需要每个派生类都直接初始化它--即使是间接派生类。(Effective C++ 41)
避免需要RTTI的设计,因为它需要多重的if-else逻辑判断,每当继承层次改变,都需要更新原有的逻辑。(More Effective C++ 31)
面向未来编程认为:在设计一个类时,不要去关注现在该如何使用该类,而是关注该类被设计为如何使用。如果一个类被设计为作一个基类使用(即使现在还没有被这么使用),它就应该有一个虚析构函数。这样的类在现在和将来都行为正确,并且当新类从它们派生时并不影响其它库用户。


活在当下与面向未来

 
当然,我们依旧活在当下,首先要做的应该是确保完成当下的任务,但未来时态仅仅只是增加了一些额外的约束:

  1. 尽可能提供完备的类, 确保当产生新需求时不用去更改它们。
  2. 将你的接口设计得直观且高效,使class不易被错误使用。
  3. 尽量通用化代码。例如,如果在写树的遍历算法,考虑将其通用化至可以处理任何有向无环图。

总结

 
面向未来编程增加了代码的可重用性、可维护性、健壮性,并且保证了在运行环境发生改变时易于修改。但面向未来编程的前提是完成当前问题已经得到有效解决。