我读<代码整洁之道>--读书笔记整理

简介: 第一章 整洁代码  "我可以列出我留意到的整洁代码的所有特点,但其中有一条是根本性的,整洁的代码总是看起来像是某位特别在意他的人写的.几乎没有改进的余地,代码作者设么都想到了,如果你企图改进它,总会回到原点,赞叹某人留给你的代码" ---Michael Feathers   "整洁的代码只做好一...

第一章 整洁代码

  "我可以列出我留意到的整洁代码的所有特点,但其中有一条是根本性的,整洁的代码总是看起来像是某位特别在意他的人写的.几乎没有改进的余地,代码作者设么都想到了,如果你企图改进它,总会回到原点,赞叹某人留给你的代码" ---Michael Feathers 

  "整洁的代码只做好一件事" ---Bjarne Stroustrup 

第二章 有意义的命名

  1 变量名要名副其实

  即顾名思义,变量.函数或者类的名称应该能告诉你,它为什么会存在,他做什么事,应该怎么用,名称应该尽量不需要注释补充亦能表示其含义.

  类名和对象应该是名词或者名词短语,方法名应该是动词或者动词短语.

  2 避免误导

//不好的命名
public boolean stateMachine(int smStatus) {
//...
}
public boolean doAction() {
//...
}
//好的命名
public boolean moveStateMachineToStatus(int smStatus) {
//...
}
public boolean doNextStepInProviderTechnique() {
//...
}

  3 做有意义的区分

    4 使用能读得出来的名称

  名字中不要有冗余,定义一个List类型变量,xxxList不如xxx的复数形式简洁,List字眼就属于冗余字段.

   5 命名布尔变量

   使用常见的布尔含义的命名: 如done;error;found;success;

   可以添加前缀is,has来转换布尔,但是isSuccess不如success可读性好

   避免使用负向变量命名:如notFound,设想if(!notFound)是不是觉得别扭.负向条件比正向条件更加难于理解,应该尽量避免.

第三章    函数  

  1 短小

  这里是指一个函数的代码量,不是指函数名称要短小.函数应该是在做一件从语义上无法再次拆解的事情.

  2 一个函数只做一件事

  函数应该做一件事,做好这一件事,而且只做这一件事.

写多长的函数比较合适?

  约定:不超过一屏幕,长度并不是问题,关键在于函数名称和函数体之前的语义距离,函数应该很短,也可以较长.只要保证函数只做这一件事.

拆分函数的技巧?

  寻找注释,如果函数中某部分代码前面有一行注释,一般可以把这段代码替换成一个函数.此外,当感觉需要注释来说明一些什么的时候,就要考虑把要说明的这些东西封装成一个独立的函数.

  3 每个函数一个抽象层级

  这一点需要多一些说明,要确保函数只做一件事,函数的语句要在同一个抽象层级上.

public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String fileId = request.getParameter("FILEID"); 
    if (fileId == null) {
        throw new ServletException("Invalid FileId"); }
    String partNum = request.getParameter("PART"); int part = 1;
    if (partNum != null) {
        part = Integer.valueOf(partNum).intValue(); }
        boolean isLast = "Y".equals(request.getParameter("LAST"));
        boolean getName="Y".equals(request.getParameter("GETNAME"));
        String fileName = 
        MitoDownloadCache.INSTANCE.getFileName(fileId, part); 
   if (fileName== null) {
        throw new ServletException("Invalid FileName"); }
    MitoConfig mitoCfg = new MitoConfig();
    File file = new File(mitoCfg.getPrintClientDataPath()+"/"+fileName); 
   if (!file.exists()) {
        throw new ServletException("File " + file.getAbsolutePath() + " not found");
}
    if (getName) {
        doDownloadFilename(request, response, file.getName());
} else {
    if (isLast) {
        MitoDownloadCache.INSTANCE.removeFileList(fileId); }
        doDownload(request, response, file); file.delete();
   }

  上面这个方法是我copy来的,不用研究这个函数的内容,只看一下结构,这个函数中既有比较高抽象层次的函数doDownloadFilename,doDownload,还有getFileName这种位于中间抽象层次的函数,更有很多像equals等较低抽象层次的概念.混杂了不同抽象层次,读起来就比较吃力,现在来改造一下:

public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    File file = fileToDownLoad(request); 
    if (downloadByName(request)) {
        doDownloadFilename(request, response, file.getName()); 
    }  else {
        removeFromCacheIfLast(request);
        doDownload(request, response, fileToDownLoad(request)); 
        file.delete();
} }

  将功能拆分成红能更小更细的函数,封装成私有方法,起一个见名知义的函数名,使整个方法能够位于同一个抽象层次,然后在每个函数内部都跟着下一级抽象层次的函数,这样能给阅读带来极大的便利.(上面函数中私有方法这里不再展示)

  4 使用描述性名称

   函数越小,功能越集中,就越容易取一个合适的名字.另外不要害怕长名称,描述性很好的长名称比含糊不清的短名称要好.不要害怕花时间给函数起名字,起一个合适的名字本身就是编程的一部分.

  5 函数输入参数

  最理想的函数参数是0个(无参函数),其次是一个,二个,应该尽量避免三个以上的参数.

      尽量避免标示参数,即用一个boolean类型作为入参,比如下面这个函数,eat(true);这样读起来就有些摸不着头脑,可能读者需要去查看eat方法eat(boolean isHuntry)才能比较理解这个函数.

      如果函数必须要三个或三个以上的参数,就说明其中一些参数需要封装成类,如果很难封装成类,就说明这个函数的设计有问题.

  6 函数输出参数

  面向对象语言的方法应该尽量避免使用输出参数,当然那些util类型的工具类除外.this也有输出函数的意味,如果函数必须要修改某种状态,就修改所属对象的状态吧.

  7 抽离try/catch代码块

   try/catch代码块比较丑陋,搞乱了代码结构,最好把try/catch代码块的主体部分抽离出来,另外形成函数.

函数应该只做一件事,错误处理就是一件事,因此,如果处理错误(带try/catch)的函数应该只处理错误,该函数只有try/catch不应该再包含其他内容.

  8 使用更少的代码

//实例1:不好的代码格式
public int size() {
  if (root == null) {
    return 0;
  }else {
    return root.numSiblings(); 
  }
}
//实例1:好的代码风格
public int size() {
  return root != null ?root.numSiblings() : 0; 
}
//实例2 不好的代码
   List<Integer> list = Arrays.asList(1, 2, 3));
   list = Collections.unmodifieableList(list); 
   return list;
//实例2 好的代码
   import static java.util.Arrays.*;
   import static java.util.Collections.*;
   ...

   return unmodifiableList(asList(1, 2, 3))

实例2中给出的例子有些函数式编程的味道,这里只是提供一种思路,但大多数情况我们一般写出来的都是上面的格式.

第四章 注释

  不写无意义的注释,什么是无意义的注释,如下:

  //当我写这段代码的时候,只有老天和我自己知道我在做什么

     //现在,只剩老天知道了

       ...

    //我不对以下代码负责

   //使他们逼我写的,是违背我意愿的  

  注释尽量做到简洁

  最好不写注释

  代码结合命名应该良好的描述功能,写注释说明表达意图的失败以及对代码功能的不自信,糟糕的代码是注释存在的动机之一.

  什么是必须要写的注释

    警告他人 版权协议 公共API 

第五章 格式 

  1 格式的目的

  代码格式很重要,代码格式关乎沟通,而沟通是开发者的头等大事.

  2 垂直格式

    阅读代码都是从上往下,从左往右读的.在一个类中,在封包声明,导入声明,和每个函数之前都应该使用一个空白行来隔开.这可以给阅读带来愉悦的感受.

  空白行隔开了概念,每个空白行都是一条线索,标示出一个新的独立的概念,阅读代码的时候,我们的目光总是容易停留在空白行的前一行或后一行.

    变量声明 :变量声明应该尽量靠近其使用位置.类变量应该声明在类的顶部,

    相关函数:某函数A调用了函数B,应该尽量把他们放到一起,让A位于B的上方.

    概念相关:概念相关的代码应该放到一起,相关性越强,他们之间的距离就应该越短.

    避免过度缩进(代码梯子):

//不好的代码风格
public void startCharging() {
   if (customer.hasFunds()) {
      if (!station.isCharging()) {
         if (!station.currentlyBooked()) { 
            reallyStartCharging();
            return; 
         }
      }
   }
   throw new UnableToStartException(); 
}
//好的代码风格
public void startCharging() {
   if (!customer.hasFunds()) throw new UnableToStartException
   if (station.isCharging()) throw new UnableToStartException
   if (station.currentlyBooked()) throw newUnableToStartException
    reallyStartCharging(); 
}

  3 横向格式

  一行代码应该多宽?

  应当遵循无需拖动滚动条到右边的原则,每行代码控制在100个字符以内是良好的风格.

第六章 对象和数据结构

  数据抽象

  当我们构建一个实体类时,会为变量设置为private,再为变量提供set/get方法,想一想为什么要这么做?实际上,即使变量都是私有,我们通过变量的set/get方法操作变量时,实现仍然被曝光了,那为何不直接将变量设置为public,然后直接操作变量呢?

  隐藏实现并非只是在变量之间放上一个函数层那么简单,更大的意义在于抽象,类并不是简单的用set/get方法将变量推向外间,而是暴露抽象接口,使得用户无需了解数据的实现就能够操作数据本体.  

  德墨忒尔定律(The Law of Demeter)

  得墨特定律认为,模块不应该了解它所操作的对象的内部情况.对象隐藏数据,曝光操作.

  类C的方法f只应该调用以下对象的方法

  1. C
  2. 由f创建的对象
  3. 作为参数传递给f的对象 
  4. 由C的实体变量持有的对象

  方法不应该调用任何由任何函数返回的对象的方法,一个很经典的比喻就是:不要和陌生人说话,只和朋友说话,还有一个比喻就是,人可以命令狗走路,但人不能直接命令狗的腿去走路,而应该由狗来控制自己的腿去走路.

  如果代码中充斥着"."构成的链式编程风格的代码.意味着该定律被被违反了.当然如果调用者是数据结构,没有行为只有数据,就可以忽略.

 

 

 ...未完

相关文章
|
5月前
|
开发者
从代码中汲取智慧——我的编程之旅与技术感悟
【9月更文挑战第24天】在数字世界的迷宫中,代码是指引我们前行的罗盘。它不仅仅是冷冰冰的指令集合,更是一扇窗,透过它,我们可以看到逻辑的严谨、问题的解决以及创新的火花。本文将分享我在编程旅途中的一些深刻体会,从最初的困惑与挫败,到逐渐掌握编程语言的乐趣,再到通过代码解决问题的成就感。我将探讨如何通过编程提升思维能力,以及编程对个人成长和职业发展的重要性。无论你是编程新手还是资深开发者,这段旅程都将启发你去思考和探索技术的深层次意义。
48 1
|
设计模式 数据采集 程序员
代码整洁之道--告别码农,做一个有思想的程序员
代码整洁是软件长期稳定和可扩展的基础,本文作者从现实中的代码、重构、设计模式谈论代码整洁之道,总结出如何做一个有思想的程序员。
131449 58
|
Java 程序员
话题讨论 | 程序员表白,不光需要“技术”,更需要勇气!
回忆起我们的点点滴滴,我们也有美好回忆。程序员应该如何表白呢 ?很大一部分是不够自信,怕穷,怕拒绝,其实更多的你可能需要的是一份勇气,爱,要大声说出来!恰逢官方正文,在此总结一下我们的点点滴滴,平凡而又伟大。
240 0
|
人工智能 图形学
9年3D建模师的感悟—写给还在迷茫中的朋友
不知不觉,从事3d行业已经9年了。今天想把这么久以来积攒的3D建模的学习经验彻底讲一下,希望能对你有所帮助 。
319 0
|
程序员 C++ 开发者
《代码整洁之道》-开篇
《代码整洁之道》-开篇
|
程序员
【抛砖引玉】“技术顾问” —— 老程序员的一个出路。
     以前总可以看到一些讨论,程序员30岁以后怎么办?35岁以后怎么办?当然有一些人,不管大多的年龄,都可以继续编程。但是对于大多数人年龄大了,各方面的压力也就更大了。年龄大了就面临上有老下有小的处境,简单地说父母、爷爷奶奶病了要去照顾;孩子病了也要照顾;老婆病了也要照顾;自己病了还得自己照顾自己。
1339 0