zoukankan      html  css  js  c++  java
  • 做好代码复用不简单

    前面我们用了那么多示例讨论了代码复用。毫无疑问,几乎所有人都明白代码复用的重要意义,知道要写好代码必须要合理地复用代码。然而,曾经有一份真挚的感情放在你面前你却没有珍惜,那就是你应该复用代码了。等你失去的时候我才后悔莫及,有木有?为什么每当我们应当复用代码的关键时刻,我们却往往选择复制粘贴呢?因为道理非常清楚但实际操作起来却困难重重,因为要实现复用必须要调整原有程序。要调整原有程序,这就不好玩了,我们就不知道该怎样应对了,还是复制粘贴来得简单快捷。

    有一次,我参与了一个财务系统的研发。我在开发一个功能的时候,发现有个数值型参数,有时候在前端传过来的时候数据位数或精度会非常大,造成转型成Number类型的时候会出错,必须转型成BigDecimal。同时,前端传送过来的数据有可能是String类型,也可能是char[]类型。为此我进行了如下的修改:

     1 ……
     2 Number amount
     3 Object value = req.getParameter(“amount”);
     4 try{
     5     if (value ==null){
     6         amount = null;
     7     } else if (value instanceof Number){
     8         amount = (Number)value;
     9     } else if (value instanceof String){
    10         amount = new BigDecimal((String)value).setScale(9, RoundingMode.HALF_UP);
    11     } else if (value instanceof char[]){
    12         amount = new BigDecimal((char[])value).setScale(9, RoundingMode.HALF_UP);
    13     } else {
    14         throw new MsgException("数据不是数字!”);
    15 } 16 }catch(NumberFormatException nfe){ 17 throw new MsgException("数据不是数字格式!”); 18 } 19 ……

    经过测试,该问题得到了修复。但在随后的开发中,我发现系统中许许多多从前端获取数字的程序都需要这段程序。如果当我们每次需要这个功能时都将这段代码拷贝过去,实现现有的功能当然没有问题,但却会为日后的维护埋下隐患。假如有一天这段程序需要调整,难道我们要到整个系统的数百份拷贝中去修改吗?道理大家都明白,关键是这样的问题却在无数软件系统中反复出现。

    在这里问题的关键在于,要让这段程序为其它的程序所复用,不修改它自身是根本没有办法做到的。我们必须从现有程序中将这段程序提取出来形成一个公用函数,为其它程序所复用,然后将该程序修改成对这个公用程序的引用才行。为此我做出了如下修改:

    首先运用“抽取方法”,将这段代码从其它程序中提取出来,放到工具类中形成一个静态调用函数:

     

     1 /**
     2 * @param value
     3 * @return 根据不同的数据格式返回数字类型的数据
     4 */
     5 public static Number getNumber(Object value){
     6     if(value==null){return null;}
     7     if(value instanceof Number){
     8         return (Number)value;
     9     }
    10     try{
    11         if(value instanceof String){
    12         return new BigDecimal((String)value).setScale(PRECISION,ROUNDMODE);
    13         }
    14         if(value instanceof char[]){
    15         return new BigDecimal((char[])value).setScale(PRECISION,ROUNDMODE);
    16         }
    17     }catch(NumberFormatException nfe){
    18         throw new MsgException("数据不是数字格式!”);
    19     }
    20     throw new MsgException("数据不是数字!”);
    21 }

    然后将原程序改为:

    1 ……
    2 Number amount = XxxUtil.getNumber(req.getParameter(“amount”));
    3 ……

    这里,我们运用了重构中“两顶帽子”的设计方式,先在不增加新功能的情况下,调整原程序内部结构,即抽取出工具类,以此来适应新功能的需要。经过这样的调整,在实现新功能时就可以大胆复用原有代码了,复用变得不再那么困难。

    然而,我们说,做好代码复用简约而不简单,它考验的是IT攻城狮的设计水平与开发能力。怎么说呢?有时候我们意识到应该复用了,但真正要写好复用真的需要下很多功夫。而每一个复用都是一个分析、设计、重构的过程。

    没有经过重构的、原生态的代码是没有办法复用的,但当我们发现代码需要复用时,切忌不要使用过去那种简单粗暴的复制粘贴。合理运用重构方法,加之以仔细、认真、及时的测试,可以保证既有代码的正确,而使整个系统合理地复用起来,以提高系统的可维护性,关键是你有没有这样的意识。所以,重构是一种习惯。

    然而,复用不是银弹,它不能搞定一切问题。被复用以后,如果公用的代码出现变更,甚至出现一部分客户使用旧程序,一部分客户使用新程序,应当怎么办呢?呵呵,这下好,老革命遇到了新问题。这常常让人十分头疼,而要解决这个问题,我们就进入了一个新的话题,老程序的功能扩展……(续)

    相关文档:

    遗留系统:IT攻城狮永远的痛
    需求变更是罪恶之源吗?
    系统重构是个什么玩意儿
    我们应当改变我们的设计习惯
    小步快跑是这样玩的(上)
    小步快跑是这样玩的(下)
    代码复用应该这样做(1)
    代码复用应该这样做(2)
    代码复用应该这样做(3)
    做好代码复用不简单

    特别说明:希望网友们在转载本文时,应当注明作者或出处,以示对作者的尊重,谢谢!

  • 相关阅读:
    roportional Rate Reduction (PRR)
    【C++11新特性】 nullptr关键字
    C++ 智能指针
    std::thread
    C++11 的 std::ref 用法
    for auto
    C++11右值引用与移动构造函数
    leetcode刷题笔记一百零六题 从中序与后序遍历序列构造二叉树
    leetcode刷题笔记一百零五题 从前序与中序遍历序列构造二叉树
    leetcode刷题笔记一百零四题 二叉树的最大深度
  • 原文地址:https://www.cnblogs.com/mooodo/p/codeReusedIsNotEasy.html
Copyright © 2011-2022 走看看