C# 4.0中的契约式编程

一切从质量谈起

许多人在考虑软件开发的新方法和新工具时,都是把提高生产率或产量 (productivity)作为主要的期望目标。但是产量不仅直接受益于新的方法途径,也受益于对质量的重视。

软件质量的一个主要部分是可靠性(reliability):系统要能够完成所规定的任务( 正确性 -- correctness),也要能够妥善处理异常情况(稳固性 -- robustness)。

一言蔽之,可靠性就是系统没有错误故障。软件开发不管用什么方法,一般都对可靠性有很高的要求。尤其在OO方法中,可靠性更为重要,这是因为OO方法中复用性(reusability)扮演着特殊的角色:复用的软件部件的正确性必须高于一般的软件,否则复用就是空谈。

已知的一些提高软件质量的方法:

  • Static typing(静态类型)能够帮助及早抓住源码中那些不一致的部分,从而避免使其成为故障之源。
  • Garbage collection(垃圾收集),可以减少进行内存管理时容易犯的错误。
  • 复用:通过复用由信誉良好的机构开发或者反复验证的软件部件,从而提高软件的质量。


但还有更多事情需要我们自己处理,比如说错误。错误处理一直是软件开发者所面临的最大困难之一。Bjarne Stroustrup在谈到其原因时说道,能够探察错误的一方不知道如何处理错误,知道如何处理错误的一方没有能力探察错误,而直接采用防御性代码来解决,会使得程序的正常结构被打乱,从而带来更多的错误。

C++、Java、C#等其他语言对错误处理问题的途径是异常机制。这种机制在正常的程序执行流之外开辟了专门的信道,专门用来在不同程序模块之间报告错误,解决上述错误探察与处理策略分散的矛盾。

然而,有了异常处理机制后,开发者开始有一种倾向,就是使用异常来处理所有的错误。结果是有相当多的人,都认为异常是错误处理的通用解决方案。《The Pragmatic Programmer》在讲到错误处理时,有一句箴言:
  
    “只在真正异常的状况下使用异常。”

    书中举了一个例子,如果你需要当前目录下的一个名叫“app.dat”的文件,而这个文件不存在,这不叫异常状况,这是你应该预料得到的、并且显式处理的情况。而如果你要到Windows目录下寻找user.dat文件,却没找到,那才叫做异常状况——因为每一个正常运行的Windows系统都应该有这个文件。

    究竟应该如何看待错误?怎样才能最好地错误处理?

    在这两个问题上,我们所见到的大部分语言都没有给出很好的回答。C秉承一贯风格,把所有的东西推给开发者考虑;Ada发明了异常,但是又为异常所累(知道阿里亚纳5火箭的处女航为什么失败吗?);C++企图将Ada的异常机制融合进自己的体系中,结果异常成了C++中最难以处理的东西;Java和4.0之前的C#显然都没有耐心重新考虑错误处理这桩事,而只是简单的将C++的异常机制完善化了事。

权利与义务

一般的观点,在软件体系中,程序库和组件库被类比为server,而使用程序库、组件库的程序被视为client。我们往往对库程序和组件的质量提出很严苛的要求,强迫它们承担本不应该由它们来承担的责任,而过分纵容client一方,甚至要求库程序去处理明显由于client错误造成的困境。



在《面向对象软件构造》一书中讲到:“对于一个大型系统来说,光保证它的各组成部分的质量是不够的。而最有价值的是确保在任何两个组成部分的交接处设计明晰的彼此义务和权利规范,即所谓契约。”

这不是说仅仅定义各组成部分的接口、参数顺序等等就可以了,还必须准确定义各组成部分的相互通讯方式,以及通讯需要的条件。这就是契约式设计技术所包含的内容了。


你可能感兴趣的:(编程,C++,c,C#,OO)