论坛登陆 用户名:  密 码:
设为首页  加入收藏
08年北京名校秋季招生
名牌院校免试入学宽进严出,突破考分限制,名校与你零距离,以下院校按报名先后顺序录取,24小时网上报名覆盖全国
  您现在的位置: 中国教育招生在线 >> IT >> JAVA认证 >> IT正文
网友评论:软件的最大追求到底是什么?
 作者:佚名     2007-3-14 16:54:08        来源:不详  浏览次数:

 

 

 

 

 

 

 

 

前段时间读了《软件的最大追求是什么》,击节叫好,深以为然,虽然该文章很多地方显得有点极端。
        
    如今的软件系统越来越复杂,如果软件的结构不好会影响软件的可维护性,重构代码是一件极其痛苦的事情。
        
    关于软件的复杂性问题,我做了一些思考:
        
    1)    Cyclomatic Complexity (圈复杂性 = number of decision points +1
      其中number of decision points是指一个if else之类的条件判断语句
           (引自《软件的最大追求是什么》)

         if else 语句可以被行为模式/策略模式代替,不妨看下列的例子:
            
        假设我们要根据条件判断来完成不同的行为,用if else 是这样写的:
            
        main(){
           if(case A){
                //do with strategy A
          }else(case B){
                //do with strategy B
          }else(case C){
                //do with strategy C
          }
        }
            
            
       用策略模式则如下:
    class runner{
         do();
    }
            
    class A extends runner{
           do(){
                //do with strategy A
           }
    }
            
    class B extends runner{
            do(){
                //do with strategy B
            }
    }
            
         class A extends runner{
            do(){
                //do with strategy C
            }
         }
            
    main(){
        runner.do();
    }
    用了策略模式后main()中的语句的确简单多了,再也看不到该死的if else了^_^酷~~~
                
    可实际上是这样简单吗???仔细研究一下上面的代码就能看出问题出来,首先这两段代码中的A、B、C的实际意义是不一样的:第一段代码中ABC代表的是某一个逻辑条件的值而第二段中的ABC则是具体的类;第二段得到如此简化的前提是它得到的逻辑条件就是一个类;如果得到的仍然只是一个逻辑条件,那么为了达到代码简化的效果,必须由另一个类(或方法)完成这种逻辑条件到具体类的转换,会出现类似下列的代码
    class RunnerFactory{
        runner getInstante(case){
              if (case A) return new A();
              else if (case B) return new B();
              else if (case C) return new C();
        }
    }
    从测试的角度来说,两者的测试分支都是3,复杂度相同,而第二种方法在很多的时候貌似还要测试借口的有效性。用策略模式还有一个缺点就是会使系统中的类的数量大大的增加,如上的例子,采用if else类的数量为1,而采用策略模式的类个数为5个或6个(主要取决于逻辑映射是否用单独的类)。
                
    如果逻辑判断的条件有三个,每个逻辑条件有三种可能的话,用策略模式系统至少会增加10个新类;如果条件更多的话类的个数也会更多
                
    这么看来GOF的策略模式还要它干嘛??
                
    当然不是,策略模式在很多情况下是一种非常好的解决方案。
                
    这还要从if else 语句造成程序复杂以至难以维护的真正原因说起。就我个人的感觉真正造成if else语句难以维护的原因是每一个逻辑分支中的处理语句过长。比如我现在工作中维护的代码,常常一个条件下面的业务处理语句有两三千行,每次我光确定某个逻辑分支的结束位置就要找半天,头晕-_-!。如果是多层条件的话情况就更糟了。一个分支就一千多行,几个分支上万行自然很难维护。
                
    if else 语句本质上是程序的流程控制语句,而分支中N长的代码通常是业务处理语句。行为模式/策略模式就是把流程判断和业务处理进行了一次解耦,将业务逻辑封装成一个个单独的类。换句话说,行为模式/策略模式并不是不需要if else 语句(事实上该判断的还是要判断),只不过的换了地方或者是别的代码帮你做了。另一方面,进行逻辑判断的语句被集中起来而不是分散在程序的各个角落,有利于逻辑本身的维护。策略模式/行为模式还有一个明显的好处就是如果新增加了一种状态,我们只需要新增加一个策略类(同上的ABC)就可以了,避免了在程序中改动那些大段大段让人厌烦的if else 语句。
                
    所以对于你的程序来说到底是使用设计模式还是简单的使用if else 关键在于你的程序是否复杂,有没有必要将控制逻辑和业务逻辑进行解耦。当然如果你可以用别的方式实现解耦也是非常好的。
                
    2)    Response for Class(RFC)
    当一个类和很多其他类存在依赖时,它就变得复杂甚至难以修改和维护,这样,RFC值越大,表示你的系统味道越坏。(引自《软件的最大追求是什么》)
                
    复杂性是由类与类之间的依赖关系(dependency)造成的。具体如下所示:
                
    interface  Runner;
                
    class A implement runner{
            do(){};
        }
                
    一个大型的系统中很多地方用到了runner接口,于是在很多地方出现了如下的相同代码:
                
    {
           Runner r = new A();
           r.do();
    }
    如果因为某种原因runner接口的实现类改为B,则在所有用到runner接口的地方代码都要统统改为:
    {
        //Runner r = new A();
        Runner r = new B();
        r.do();
    }
    这些遍布系统各个角落的改动是繁琐且容易出错的。于是出现了各种框架和模式,其中最著名的当然是IOC(Inversion of Control)反转控制或者称之为依赖型注射(Dependency Injection)
    那些讨厌的代码变成了如下:
    {
            ApplicationContext ctx = new FileSystemXmlApplicationContext("spring.xml");
       Runner r = (Runner)ctx.getBean("Runner");
      r.do();
    }
    这样我们就不需要对各个角落的代码进行维护了,容器会自动的为我们选择合适的类。
                
    我到觉得维护的工作还是我们的,为了让容器注射入合适的类,我们必须要维护一个叫spring.xml的配置文件,或者如果你不喜欢配置文件这个东东的话(比如偶)就得自己写一个注册类,将依赖关系一一注册进去。你还要为使用该接口的类定义一个以该接口为参数的构造函数或者该接口的setter方法,好让容器可以将实现类顺利的注射进来。
                
    该做的还是要做,只不过换了一个地方做而已。但就是换了个地方,实现了对依赖关系的集中维护(又是集中),大大的改善了系统的结构,明确了不同职责单位之间的分工。呵呵,有时自己也极端的觉得设计的工作说到底就是解决代码结构的问题^_^
                
    IOC一直是和轻量级框架联系在一起的。所谓的重量级框架EJB也有实现相同功能的解决方案:Service Locator
                
    Service Locator就是一个定位器,它维护了一个数据结构(比如一个表),通过这个定位器你可以准确的定位到你的接口想要的实现类,Service Locator同样使你免去了改变接口实现类后的维护恶梦:
    {
        Runner r = (Runner)ServiceLocator.lookup("Runner");
        r.do();
    }
                
    无论是IOC还是Service Locator都帮助你维护了类之间的依赖关系。那么是否我们在编程中一定要用呢,这又是个权衡的问题,IOC带来了很多的好处,不过我个人认为它的代码是让人费解的(你根本不知道它做了什么),并且为了用它,一方面你要借助于容器,另一方面你要编写配置文件,要为依赖型注射提供合适的途径。

    如果你的系统类之间的依赖型错综复杂,需求的变化常常导致实现类的变化,同时你又希望采用测试驱动的快速开发模式,IOC毫无疑问是一个完美的解决方案;如果你的系统不存在上述的问题,为什么不简简单单的在程序中写死呢,何苦去维护一堆配置文件(我所在的开发部门貌似都比较痛恨配置文件这个东东)。Service Locator也有很多缺点,被骂的最多的就是没法快速测试。
                
    反转控制,即转换控制权。依赖关系控制权的转换是对代码结构的一次重构,重构的目标还是解耦,让不同的职责代码集中放到不同的地方,于是程序员可以更加专注的解决特定的问题,比如业务逻辑。
                
    程序设计的发展就是对代码结构的不断调整,不断解耦,让特定的代码解决特定的问题而不是什么都混在一起。从面向过程到面向对象难道不是这样吗,封装的本质也是解耦。
                
    在实际问题的解决当中,最重要的信条就是合适,要记住任何结构的改进都会付出代价,你的改进是否值得你为此付出的代价。比如当你做一个嵌入式程序的时候你首要考虑的自然是效率问题;而如果你做的是一个ERP产品,在系统设计的时候,光系统的可维护性问题就让你不得不绞尽脑汁考虑一下代码的结构。
    
    一句话,只做最对的。
                
    程序设计的最大追求就是在合适的地方做正确的事。



责任编辑:lss
  相关新闻
06年9月23日计算机二级Access答案汇总(网友提供)
2006年9月23日计算机三级PC答案汇总(网友提供)
张钰首张EP结束网上海选 80%来自网友原创
网友心声:新生代JAVA程序员的思想
【网友投稿】如何打造完美软件系统
网友评论:软件的最大追求到底是什么?
网友原创:建立分析模型和设计模型
【网友投稿】如何打造完美软件系统
【网友投稿】针对事务型数据库设计小结
【网友投稿】我来忽悠一下 AJAX
06年9月23日计算机二级Access答案汇总(网友提供)
2006年9月23日计算机三级PC答案汇总(网友提供)
张钰首张EP结束网上海选 80%来自网友原创
【网友投稿】针对事务型数据库设计小结
【网友投稿】我来忽悠一下 AJAX
网友心声:新生代JAVA程序员的思想
【网友投稿】如何打造完美软件系统
网友原创:建立分析模型和设计模型
网友评论:软件的最大追求到底是什么?
【网友投稿】如何打造完美软件系统
  评论
现在有100人对本文发表评论
查看所有评论
 
推  荐
 
100本成功必读热销书
热门招生
  北京文理研修学院   前进大学
  北京明园大学   北京建设大学
  北京邮电大学世纪学院   北方工商管理学院
  联想软件定向委培班   香港数码动画学院
  青年企业管理研修学院   北京华夏管理学院
热门培训
网络化办公专家培训认证 电子科技大学软件学院
软件测试工程师培训认证 北大青鸟十大授权培训
IT硬件工程师培训认证班 北京环球雅思荷兰预科
JAVA开发工程师培训 潜能时代IT服务管理培训
网络信息化工程师培训 清华大学继续教育学院
论坛精选
 
有些细节是男人也该注意的风度!最容易读错的字
某强人手机里保存的30条短信 中国十大高薪职业
最感人的十大韩剧经典台词 嫁给工程师的N个理由
爆强!只有一句话的鬼故事 转贴教你如何做妖精
 女人一定要記住的話 女人最好别嫁给最爱的男人
城市联盟
 大连 上海 天津 广州 西安 深圳  天津  青岛  大连  福州  沈阳  青海  连云港  南京  吉林  厦门  威海  辽宁  呼和浩特
Copyright © 2006   www.edu999.com   All rights reserved. 中国教育招生在线  版权所有
北京市通信管理局[2004]字第552号函    京ICP证040442号