9 防御式编程

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

防御式编程DefensiveProgramming任课老师:黄武下午5时53分522下午5时53分提纲保护程序免遭非法输入数据的破坏断言错误处理技术异常隔离程序辅助调试代码下午5时53分523下午5时53分1.保护程序免遭非法输入数据破坏如何做到防御式驾驶?下午5时53分524下午5时53分1.1主动防御的思想防御式编程的主要思想是:子程序不因传入错误数据而被破坏,哪怕是由其它子程序产生的错误数据其核心是承认程序都会有问题,都需要被修改,这是保护的基础防御式编程是针对程序外部的保护问题你如何保护你的程序免遭外部数据的影响?525下午5时53分下午5时53分526下午5时53分1.2如何处理非法数据通常有三种方法来处理非法数据1.检查所有来源于外部数据的值2.检查子程序所有输入参数的值3.决定如何处理错误的输入数据下午5时53分527下午5时53分1.2.1检查所有来源于外部的数据•外部数据来源于文件,用户输入,网络或其它外部接口,应检查这些值是否在合法的范围之内外部数据源下午5时53分528下午5时53分1.2.2检查子程序所有输入参数子程序参数可能是错误的,需要检查例如voidGet_Process_Type(shortshNo){if((0=shNo)&&(shNoMAX_CHA_NUM)){return(Win2[shNo].shType);}}问题你如何检查程序的动态错误?529下午5时53分下午5时53分52102.断言断言是在开发期间使用的、让程序在运行时自检的代码断言为真,则表明程序运行正常,断言为假,则说明程序发生错误,如assert(!strOrigFileName.empty());断言对于大型复杂程序或可靠性要求极高的程序而言非常有效,程序员可以通过断言快速定位程序中的关键错误下午5时53分下午5时53分5211下午5时53分2.1断言能够检查到的错误1.输入参数或输出参数取值处于预期范围内2.子程序开始(或结束)时文件或流是处于打开(或关闭)状态3.子程序开始(或结束)时文件或流的读写位置位于开头(或结尾)处4.文件或流已用只读、只写或读写方式打开5.仅用于输入的变量的值没有被子程序所修改6.指针非空7.传入子程序的数组或其他容器至少能容纳X个数据元素8.表已经初始化,存储着真实的数据下午5时53分5212下午5时53分2.2断言的表达断言通常含有两个参数:布尔表达式和消息,比如assert(denominator!=0,“denominatorisunexpectedlyequalto0”);有些语言不直接支持断言语句,可以自己构建断言机制,下面是一个c++的断言:#defineASSERT(condition,message){\if(!(condition)){\LogError(“Assertionfailed:”,#condition,message);exit(EXIT_FAILURE);}}下午5时53分52132.3什么时候使用断言断言主要用于开发和维护阶段断言只在开发阶段被编译到目标代码中,而在生成产品代码时不编译到产品代码中下午5时53分下午5时53分5214下午5时53分2.3.1断言和错误处理的使用状况断言(assertion)用来检查永远不应该发生的状况,断言用于检查代码中的bug,因此断言通常采用强制退出程序的方式错误处理(error-handlingcode)用来检查程序的非正常状况,这些情况能在写代码时就预料到,比如从文件读取的汽车速度数据,应该在0-300Km/h范围内,超出了这个范围被认为数据出错下午5时53分5215下午5时53分2.3.2避免把执行代码放到断言中如果把代码放到断言中,则在产品发布时关闭断言后这些代码将不被执行,例如,下面的方式不可取Debug.Assert(PerformAction())上面的代码可以做如下修改:actionPerformed=PerformAction()Debug.Assert(actionPerformed)下午5时53分52162.3.3前条件和后条件使用断言保护前条件和后条件前条件(Precondition)——子程序或类的调用方法在调用其子程序或实例化对象之前要确保为真的属性前条件是调用方代码对其所调用代码的承诺后条件(Postcondition)——子程序或类方法在执行结束后要确保为真的属性后条件是子程序或类方法对调用方代码的承诺下午5时53分下午5时53分52172.3.3.1前条件和后条件举例下午5时53分VisualBasic示例:使用断言来记述前条件和后条件PrivateFunctionVelocity(-ByVallatitudeAsCoordinate,-ByVallongitudeAsCoordinate,-ByValelevationAsCoordinate-)Assingle‘PreconditionsDebug.Assert(-90=latitudeAndlatitude=90)Debug.Assert(0=longitudeAndlongitude360)Debug.Assert(-500=elevationAndelevation=75000)…‘PostconditionsDebug.Assert(0=returnVelocityAndreturnVelocity=600)‘returnvalueVelocity=returnVelocityEndFunction下午5时53分5218下午5时53分2.3.4先使用断言再使用错误处理通常而言,要么使用断言,要么使用错误处理,但有时也同时使用VisualBasic示例:使用断言来说明前条件和后条件PrivateFunctionVelocity(-ByVallatitudeAsCoordinate,-ByVallongitudeAsCoordinate,-ByValelevationAsCoordinate-)Assingle‘PreconditionsDebug.Assert(-90=latitudeAndlatitude=90)Debug.Assert(0=longitudeAndlongitude360)Debug.Assert(-500=elevationAndelevation=75000)…‘Sanitizeinputdata.ValuesshouldbewithintherangesassertedaboveIf(latitude-90)Thenlatitude=-90ElseIf(latitude90)Thenlatitude=90EndIf…这里是断言代码这里是在运行时处理错误输入数据的代码下午5时53分5219下午5时53分3.错误处理技术错误处理技术(Error-HandlingTechniques)用于处理那些能够预测的数据出错,常见的处理方法包括:1.返回中立值2.换用下一个正确的数据(实时系统)3.返回与前次相同的数据(数据处理)4.换用最接近的合法数据(预先设置)下午5时53分5220下午5时53分3.1其他错误处理技术5.把警告信息记录到日志文件中6.返回一个错误码(设置状态变量)7.调用集中的错误处理子程序或对象8.当错误发生时显示出错消息9.最妥当的方式是在局部处理错误10.关闭程序下午5时53分5221下午5时53分3.1.1错误处理技术举例if((shChannel_No0)||(shChannel_NoMAX_CHANNEL_NUMBER){shChannel_No=0;///返回中立值}if(iHeart_RateMAX_HEART_RATE){iHeart_Rate=iLast_Heart_Rate;///返回上一次的值}if((iVelocityMAX_VELOCITY){iVelocity=DEF_VELOCITY;///返回默认值}下午5时53分5222下午5时53分3.1.2集中的错误处理子程序构建一个集中的错误处理程序,所有错误处理都由其完成优点:调试简单缺点:整个程序都和这个集中错误处理点发生耦合下午5时53分5223下午5时53分3.2正确性和健壮性正确性(Correctness)是指永不返回不准确的结果,即遇到不准确的结果时不返回,比如医疗检查人身安全攸关软件往往更倾向于正确性健壮性(Robustness)是指不断尝试采取某种措施,以保证软件可以持续地运转下去,那怕是做出一些不准确的结果,比如视频播放消费类软件更注重健壮性下午5时53分5224下午5时53分3.3高层设计对错误处理方式影响应该在整个程序里采用一致的方式处理非法参数,通用的错误处理决策,涉及到软件构架的设计决策对于高可靠性的系统,在软件构架中可以设计不同层次的错误处理,比如异常的处理,可以设置通用的错误处理方式,比如日志记录,返回值检查等,这些问题只有在构架层次上设计才能够达到统一下午5时53分5225下午5时53分4异常异常(Exceptions)是把代码中的错误或异常事件传递给调用方代码的一种特殊手段异常的基本结构是:子程序使用throw抛出一个异常对象,再被调用链上层其他子程序的try-catch语句捕获下午5时53分5226下午5时53分4.1不同语言对异常的支持跟异常相关的特性C++JavaVB支持try-catch语句支持支持支持支持try-catch-finally语句不支持支持支持能抛出什么Std::exception对象或它派生类的对象;对象指针、引用;string或int等数据类型Exception对象或它派生类的对象Exception对象或它派生类的对象未捕获的异常所造成的影响调用std::unexpected()函数,该函数默认调用std::terminate(),该函数默认调用abort如果时一个受检异常,则终止执行;如果时运行时异常则不产生任何影响终止程序执行必须在类的接口中定义可能会抛出的异常否是否必须在类的接口中定义可能会捕获的异常否是否表8-1支持几种流行的编程语言的表达式下午5时53分52274.2使用异常的建议1.用异常通知程序的其它部分,发生了不可忽略的错误2.只在真正例外的情况下抛出异常3.不能用异常来推卸责任4.避免在构造函数或析构函数中抛出异常5.在恰当的抽象层次抛出异常6.在异常消息中加入关于异常发生的全部信息7.避免使用空的catch语句8.考虑创建一个集中的异常报告机制9.考虑异常的替换方案下午5时53分5228下午5时53分4.2.1在恰当的层次抛出异常子程序应该在其接口中展现一致的抽象,抛出的异常也是程序接口的一部分Java示例:一个在一致的抽象层次上抛出异常的类classEmployee{…publicTaxIDGetTaxID()throwsEmployeeDataNotAvailable{…}…}这里声明的异常则位于一致的抽象层次此处声明的异常位于不一致的抽象层次Java反例:抛出抽象层次不一致的异常的类classEmployee{…publicTaxIDGetTaxID()throwsEOFException{…}…}下午5时53分5229下午5时53分4.2.2避免使用空的Catch语句空的Catch语句意味着程序存在问题Java示例:忽略异常的错误做法try{…//Lotsofcode…}catch(AnExceptionexception){}Java示例:忽略异常的正确做法try{…//Lotsofcode…}catch(AnExceptionexception){LogError(“Unexpectedexception“);}下午5时53分5230下午5时53分4.2.3考虑创建集中的异常报告机制VisualBasic示例:集中的异常报告机制(第一部分)SubReportException(_By

1 / 52
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功