http://www.ityran.com/archives/2105

本文由子龙山人原创,泰然授权转载,转载请注明出处并通知子龙山人!

声明:防御式编程是提高程序代码质量的一种手段,它不能算是真正意义上的模式。但是,这里,我还是要给它冠之以“模式”二字。

原因有2:
1.cocos2d-x的框架源代码大量采用了防御式编程技术,用来确保框架的代码质量和稳定性。

2.标题党,引起大家对于防御式编程的重视。特别是当大家给cocos2d-x贡献源代码的时候,更应该要注意保证代码质量。因为,王哲大大在review很多人给cocos2d-x贡献代码时发现,这种防御式编程代码并不多,需要引起我们的注意。

1.应用场景
首先,第一个大量使用的是CCLayer的init函数:

  1. bool CCLayer::init()
  2. {
  3. bool bRet = false;
  4. do
  5. {
  6. CCDirector * pDirector;
  7. CC_BREAK_IF(!(pDirector = CCDirector::sharedDirector()));
  8. this->setContentSize(pDirector->getWinSize());
  9. m_bIsTouchEnabled = false;
  10. m_bIsAccelerometerEnabled = false;
  11. // success
  12. bRet = true;
  13. } while(0);
  14. return bRet;
  15. }

这里使用了do…while(0);惯用法,同时配合CC_BREAK_IF宏来做错误处理。关于为什么要使用do…while(0)惯用法,可以参考这篇文章

另一个地方就是一些内存管理的宏,这些宏可以帮助我们编写更健壮的内存管理代码:

  1. #define CC_SAFE_DELETE(p) do { if(p) { delete (p); (p) = 0; } } while(0)
  2. #define CC_SAFE_DELETE_ARRAY(p) do { if(p) { delete[] (p); (p) = 0; } } while(0)
  3. #define CC_SAFE_FREE(p) do { if(p) { free(p); (p) = 0; } } while(0)
  4. #define CC_SAFE_RELEASE(p) do { if(p) { (p)->release(); } } while(0)
  5. #define CC_SAFE_RELEASE_NULL(p) do { if(p) { (p)->release(); (p) = 0; } } while(0)
  6. #define CC_SAFE_RETAIN(p) do { if(p) { (p)->retain(); } } while(0)

最后一个地方,就是在函数的入口处,或者需要保证某些“不变量”的时候,使用assert断言来确保参数和返回结果的有效性。这个在cocos2d-x的源代码中也到处是可以看到的。

2.使用此模式的优缺点

优点:
提高代码质量,使得代码的健壮性和稳定性都有保障。可以防止子程序由于接收到了非法数据而遭受破坏。

缺点:

过度的防御式编程也会引来问题,如果你在每一个能想到的地方用每一种能想到的方法检查从参数传入的数据,那么你的程序将会变得臃肿而缓慢。更糟糕的是,防御式编程引入的额外代码增加了软件的复杂度。所以运用是需谨慎。

3.此模式的定义及一般实现

子程序应该不因传入错误数据而被破坏,哪怕是由其他子程序产生的错误数据。

我们一般可以采用以下手段来进行防御式编程:

1)检查每个子程序的入口参数,记住“垃圾进、垃圾出”这个隐喻。必要的时候可以使用断言来确保函数的先验条件是符合假定的。因为很多时候,我们编写代码都是隐藏了一系列的假定的,只是你自己没有感觉到,有时候,这些假定没有关系,出了bug也容易找出来。但是,有时候,就不是那么幸运了。

2)不要直接使用文字常量,比如3、“Hero.png”这种常量。尽可能地定义const定义常量或者使用宏定义。

3)尽可能让函数返回一些东西,这样如果当函数运行出现问题时,可以根据返回值做一些处理。如果全部设计成void类型的函数,那么出现异常要么就是try—catch,要么就是直接让程序崩溃了。由于c++的异常机制并不是那么完善,所以,也一直为人们所诟病,cocos2d-x里面几乎没有使用c++的异常处理机制。最后,必要的时候要检查函数里面调用其它子程序时的返回值。

4.实际开发中如何采用此模式

在实际开发中,我个人觉得必要的防御式编程的态度和做法还是要有的。特别是函数的输入输出,因为函数的逻辑部分是我们关注地最多的,虽然它是最复杂的,但是,往往这部分出错的概率不高。

相反,是函数的一些边界条件和异常情况导致程序bug的滋生。有些时候除了验证函数参数的数据值范围有效性以外,更加要注意的是验证数据的业务条件是否满足。这一点恰恰最容易被忽视。

在做内存管理的时候,尽可能地使用cocos2d-x里面定义的一些宏来清理资源,比如CC_SAFE_DELETE等。当实现自定义的CCLayer对象的时候,也尽可能地采用do…while(0)的写法,如果里面出现问题,可以用CC_BREAK_IF来判断并退出。

5.此模式与其它模式的关系

暂不讨论

cocos2d-x设计模式发掘之五:防御式编程模式的更多相关文章

  1. MVVM设计模式加RAC响应式编程

    一:为什么要用MVVM? 为什么要用MVVM?只是因为它不会让我时常懵逼. 每次做完项目过后,都会被自己庞大的ViewController代码吓坏,不管是什么网络请求.networking data ...

  2. 《Code Complete》ch.8 防御式编程

    WHAT? 主要思想:子程序不应因传入参数错误而被破坏 WHY? 保护程序免遭非法输入的破坏 HOW? 断言 assert denominator != 0 : "denominator s ...

  3. 软件工程 - 防御式编程EAFP vs LBYL

    概念 EAFP:easier to ask forgiveness than permission LBYL:look before you leap 代码 # LBYL def getUserInf ...

  4. python2学习------基础语法3(类、类的继承、类成员函数、防御式编程)

    1.类的定义以及实例化 # 类定义 class p: """ this is a basic class """ basicInfo={&q ...

  5. 【SQLSERVER学习笔记】进攻式编程

    一般的编程语言建议是进行防御式编程,在开始处理之前先检查所有参数的合法性.但实际上,对数据库编程而言,尽量同时做几件事情的进攻式编程有切实的优势.*/ --我们SP中常见的防御式编程示例:--场景一: ...

  6. JS 响应式编程

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <script ...

  7. PHP 面向对象编程和设计模式 (1/5) - 抽象类、对象接口、instanceof 和契约式编程

    PHP高级程序设计 学习笔记 2014.06.09 什么是面向对象编程 面向对象编程(Object Oriented Programming,OOP)是一种计算机编程架构.OOP 的一条基本原则是计算 ...

  8. iOS架构:MVVM设计模式+RAC响应式编程

    https://cloud.tencent.com/developer/article/1117009 一:为什么要用MVVM? 为什么要用MVVM?只是因为它不会让我时常懵逼. 每次做完项目过后,都 ...

  9. cocos2d-x设计模式发掘之一:单例模式

       作者: firedragonpzy  原地址:http://www.firedragonpzy.com.cn/index.php/archives/1781 本系列文章我将和大家一起来发掘coc ...

随机推荐

  1. OpenSSH for Windows,CopSSH

    https://www.oschina.net/p/openssh+for+windows https://www.oschina.net/p/copssh

  2. 学习笔记-[Maven实战]-第三章:Maven使用入门(2)

    使用maven执行编译和测试 1.maven执行编译 (1).在pom.xml上点右键,选择Maven build... (2).在Goals里输入clean complie,执行编译 执行结果: [ ...

  3. C#中的@符号

      C# 中的 @ 符号 C# 中的 @ 符号其实有很多的用法,我们来看看 @ 有什么神奇之处. 1. 限定字符串 用 @ 符号加在字符串前面表示其中的转义字符 “ 不 ” 被处理. 如果我们写一个文 ...

  4. 【转】Xcode常用快捷键与技巧分享

    原文网址:http://www.jianshu.com/p/039954b0cbe0 工欲善其事必先利其器. 虽然Xcode编写objective-c or swift很完美, 但了解其工具的常用快捷 ...

  5. CDN原理

    要了解CDN的实现原理,首先让我们来回顾一下网站传统的访问过程,以便理解其与CDN访问方式之间的差别: 由上图可见,传统的网站访问过程为:1. 用户在浏览器中输入要访问的域名:2. 浏览器向域名解析服 ...

  6. epub3 in action: epub3文件格式简介

    epub3文件就是一个符合epub3标准,以epub为扩展名的zip压缩文件.epub3标准则是基于html5.css3.svg等web标准以及mathML等来展示内容.下图就是一个简单epub3文件 ...

  7. 【原】Spark Rpc通信源码分析

    Spark 1.6+推出了以RPCEnv.RPCEndpoint.RPCEndpointRef为核心的新型架构下的RPC通信方式.其具体实现有Akka和Netty两种方式,Akka是基于Scala的A ...

  8. VS2013 MVC Web项目使用内置的IISExpress支持局域网内部机器(手机、PC)访问、调试

    VS2013内置了IISExpress.做asp.net MVC的web项目开发时,Ctrl+F5和F5启动项目运行(后者是调试模式)的同时都会打开IISExpress,事实上本机对该web项目走的就 ...

  9. leetcode之Palindrome Partitioning

    方法一:DFS递归,判断每一个是否为回文数 1,首先要有一个判断字符串是否是回文的函数.容易实现,字符串从两边同时往中间走,看字符是否相同; 2,深度优先搜索思想对字符串进行遍历.得到结果.例如,s ...

  10. Esper系列(十一)NamedWindow语法Merge、Queries、Indexing、Dropping

    On-Merge With Named Windows 功能:对window中的insert.update.delete操作进行组合运用. 格式: 1  "; 14      15  Sys ...