《随笔二十四》—— “ 【代码整洁之道 Clean Code】 提炼总结 一 ”

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34536551/article/details/86476418

目录

第一章《整洁代码 》

第二章《 有意义的命名》

第三章 函数

短小

只做一件事

命名合适且具有描述性

函数参数尽量少

标识参数

参数对象

接受可变参数的函数


第一章《整洁代码 》


●  这章先是给我们传递一个观点:整洁代码是十分有必要的。然后就列举了几位java大师级人物对整洁代码的定义和看法。

    真正有用的就是这些大师人物的观点,都是经过几十年的编程经验总结而成的,下面我再将这些观点进行总结,得到以下几个“真理”:

  •   尽量减少依赖关系,便于维护
  •   简单直接,充满了干净利落的抽象和直截了当的控制语句。
  •  能够全部运行通过,并配有单元测试和验收测试
  •  没有重复的代码(提取公共方法和公共类)
  • 写的代码能够完全提现我们的设计理念(类、方法、属性的命名)

第二章《 有意义的命名》


●    在给 标识符 命名的时候应该选择能够体现本意的名称,最好能体现该名称是干嘛的,有什么作用,做什么事情,如何使用等等。 这样可以让人更容易理解和修改代码。注意:  在阅读或修改过程中,如果发现有更好的名称, 就要换掉旧的。

举个栗子:以下的这句代码里的d就不算是个好命名。名称d 什么都没说,它没引起我们对时间消逝的感觉,更别说单位是天了:

int d; // elapsed time in days || 经过了几天时间

我们应该选择这样的指明了计量对象和计量单位的名称:

int elapsedTimeInDays;
int daysSinceCreation;
int daysSinceModification;
int fileAgeInDays;

●  我们应该避免留下隐藏代码本意的错误线索,也应该避免使用与本意相悖的词。例如,别用accountList来指一组账号,除非它真的是List类型,用accountGroup、bunchOfAccounts,或者直接用accounts,都是更好的选择。

尽量提防长得太像的名称。想区分XYZControllerForEfficientHandlingOfStrings和XYZControllerForEfficientStorageOfStrings,会花费我们太多的时间。因为这两个词,实在太相似了。
 

注意:  不要用 小写字母 “ l ” 和 " O"  做变量名,特别是组合使用的时候。


● 尽量避免使用数字系列命名(a1、a2…….aN)。这样的名称纯属误导,因为很多时候完全没有提供正确的信息,没有提供导向作者意图的线索。

废话是另一种没有意义的区分。如果我们有一个Product类,还有一个ProductInfo或ProductData类,那么他们的名称虽然不同,但意思却无区别。这里的Info、Data就像a、an和the一样,是意义含混的废话。


注意,只要体现出有意义的区分,使用a、the这样的前缀就没错。例如,将a用在域内变量,把the用于函数参数。


● 我们要使用读得出来的名称。如果名称读不出来,讨论的时候就会不方便且很尴尬,甚至让旁人觉得很蠢。

例如,变量名称是beeceearrthreecee,讨论的时候读起来简直像没吃药。


单字母和数字常量有个问题,就是很难再一大篇文字中找出来。

找MAX_CLASSED_PER_STUDENT很容易,但想找数字7,就很麻烦。

同样,字母e也不是个便于搜索的好变量名。因为作为英文中最常用的字母,在每个程序、每段代码中都有可能出现。

单字母的名称可以用在很小的函数中作为局部变量。 名称长短应与其作用域大小相对应,若变量或常量可能在代码中多处使用,应赋予其以便于搜索的名称。
 

下面举个例子:

for (int j=0; j<34; j++)
 {
s += (t[j]*4)/5;
}

VS

int realDaysPerIdealDay = 4;
const int WORK_DAYS_PER_WEEK = 5;
int sum = 0;

for (int j=0; j < NUMBER_OF_TASKS; j++) 
{
int realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
int realTaskWeeks = (realdays / WORK_DAYS_PER_WEEK);
sum += realTaskWeeks;
}

按整洁代码的要求来评判,第一段代码会让读者不知所云,第二段代码比第一段好太多。第二段代码中,sum并非特别有用的名称,但至少他搜索得到。采用能表达意图的名称,貌似拉长了函数代码,但要想想看,WORK_DAYS_PER_WEEK要比数字5好找得多,而列表中也只剩下了体现我们意图的名称。
 


避免思维映射


我们取名的时候要避免思维映射,不应当让读者在脑中把你的名称翻译为他们熟知的名称,也就是说取名不要绕弯子,而是要直白,直截了当。

 在多数情况下,单字母不是个好的命名选择,除非是在作用域小、没有名称冲突的地方,比如循环。循环计数器自然有可能被命名为i,j或k(最好别用字母l),这是因为传统上我们惯用单字母名称做循环计数器。
 


类名尽量用名词


类名尽量用名词或名词短语,比如Customer, WikiPage,Account, 或 AddressParser。

类名最好不要是动词。


方法名尽量用动词或动词短语。比如postPayment, deletePage, 或者save。

属性访问器、修改器 mutator 和 断言应该根据其value来命名,并根据标准加上get、set和is前缀。

举个栗子,这里的getName、setName等命名都是可以的:

string name = employee.getName();
customer.setName("mike");
if (paycheck.isPosted())...

我们需要为一个抽象概念挑选一个词,并坚持下去。

例如,使用fetch、retrieve和get来给在多个类中的同种方法命名,你怎么记得住哪个类中是哪个方法呢?

不要把函数中的参数名的名称跟某一个函数声明的名称一样。  函数名应该是独一无二的,而且还要保持一致。

同样,在同一堆代码中混用controller、manager,driver,就会令人困惑。DeviceManager和Protocol-Controller之间有何根本区别?为什么不全用controller或者manager?他们都是Driver吗?这就会让读者以为这两个对象是不同的类型,也分属不同的类。

所以,对于那些会用到你代码的程序员,一以贯之的命名法简直就是天降福音。
 


记住,只有程序员才会读你写的代码。所以,尽管去用那些计算机科学领域的专业术语、算法名、模式名、数学术语。

对于熟悉访问者(Visitor)模式的程序来说,名称AccountVisitor富有意义。给技术性的事物取个恰如其分的技术性名称,通常就是最靠谱的做法。
 

如果不能用程序员熟悉的术语来给手头的工作命名, 就采用从所涉问题领域而来的名称吧。


很少有名称是可以自我说明的。所以,我们需要用有良好命名的类,函数或名称空间来放置名称,给读者提供语境。若没能提供放置的地方,还可以给名称添加前缀。

例如: 假如我们有名为firstName、lastName、street、houseNumber、city、state和zipcode的变量。当他们搁一块儿的时候,的确是构成了一个地址。不过,假如只是在某个方法中看到一个孤零零的state呢?我们会推断这个变量是地址的一部分吗?

我们可以添加前缀addrFirstName、addrLastName、addrState等,以此提供语境。至少,读者可以知道这些变量是某个更大变量的一部分。当然,更好的方案是创建名为Address的类。这样,即便是编译器也会知道这些变量是隶属于某个更大的概念了。

另外,只要短名称足够好,对含义的表达足够清除,就要比长名称更合适。添加有意义的语境甚好,别给名称添加不必要的语境。
 


最后总结


其实,取一个好名字最难的地方在于需要良好的描述技巧和共有的文化背景。与其说这是一种技术、商业或管理问题,还不如说这是一种教学问题。

不妨试试上面列出的这十二条规则与要点,看看你的代码可读性是否有所提升。而如果你是在维护别人的代码,或者是在重构,效果应该会是立竿见影的。


本文涉及知识点提炼整理


  • 要点一:要名副其实。一个好的变量、函数或类的名称应该已经答复了所有的大问题。一个好名称可以大概告诉你这个名称所代表的内容,为什么会存在,做了什么事情,应该如何用等。
  • 要点二:要避免误导。我们应该避免留下隐藏代码本意的错误线索,也应该避免使用与本意相悖的词。
  • 要点三:尽量做有意义的区分。尽量避免使用数字系列命名(a1、a2…….aN)和没有意义的区分。
  • 要点四:尽量使用读得出来的名称。如名称读不出来,讨论的时候会不方便且很尴尬。
  • 要点五:尽量使用可搜索的名称。名称长短应与其作用域大小相对应,若变量或常量可能在代码中多处使用,应赋予其以便于搜索的名称。
  • 要点六:取名不要绕弯子。取名要直白,要直截了当,明确就是王道。
  • 要点七:类名尽量用名词。类名尽量用名词或名词短语,最好不要是动词。
  • 要点八:方法名尽量用动词。方法名尽量用动词或动词短语。
  • 要点九:每个概念对应一词,并一以贯之。对于那些会用到你代码的程序员,一以贯之的命名法简直就是天降福音。
  • 要点十:通俗易懂。应尽力写出易于理解的变量名,要把代码写得让别人能一目了然,而不必让人去非常费力地去揣摩其含义。
  • 要点十一:尽情使用解决方案领域专业术语。尽管去用那些计算机科学领域的专业术语、算法名、模式名、数学术语。
  • 要点十二:要添加有意义的语境。需要用有良好命名的类,函数或名称空间来放置名称,给读者提供语境。若没能提供放置的地方,还可以给名称添加前缀。

第三章 函数



短小

《代码整洁之道》作者Bob大叔写道 “ 函数的第一规则是要短小。第二规则还是要更短小。 ” 一般20行封顶最佳。

还建议我们函数不应该大到足以容纳嵌套结构。所以, 函数的缩进层级不该多于一层或两层。这样就好的阅读与理解。


只做一件事

函数应该只做一件事情。只做一件事,做好这件事。

有哪些方法可以判断该函数只是做了一件事:

  • 如果该函数只是做了该函数名下同一抽象层上的步骤, 则该函数还是只做了一件事。
  • 要判断函数是否不止做了一件事, 还有一个方法,,如果你可以从该函数中提取另外一个函数,该函数不仅只是单纯地重新诠释其实现[G34]。

命名合适且具有描述性

“如果每个例程都让你感到深合己意,那就是整洁的代码。”要遵循这一原则,大半工作都在于为只做一件事的小函数取个好名字。函数越短小,功能越集中,就越容易选择描述性名称。

我们为函数取个描述性的名称,不要害怕取了长名称。长而具有描述性的名称,比短而令人费解的名称好。而且长而具有描述性的名称,比描述性的长注释要好。而且选择描述性的名称能理清你关于模块的设计思路,以后好并帮你改进之,而且一个名字是否好寻找可以对代码进行有利的重构。

不要害怕花时间选择一个名字,可以尝试使用几个不同的名称,并阅读每个名称对应的代码。然后使用IDE尝试使用不同的名称,直到找到一个尽可能具有描述性的名称。

还要记住的是:给函数 命名方式要一致,并且坚持下去。


函数参数尽量少

最理想的函数参数个数是零参数,其次是单参数,再次是双参数,应尽量避免三参数及以上参数的函数,有足够的理由才能用三个以上参数(多参数函数)。

输出参数比输入参数更难理解。当我们读取一个函数时,我们习惯于通过参数将信息输入到函数中,然后通过返回值将信息输出。我们不太期望信息通过参数输出。

当我们编写二元参数的时候,看看能不能利用某些方法将其转换成一元函数


标识参数

尽量避免将布尔值传递给一个函数, 因为这样相当于告诉我们这个函数不止做一件事,如果传递true ,它做这一件事; 如果传递false ,它做另一件事。


参数对象

当一个函数似乎需要两个或 三个、 以及三个以上参数时,很可能这些参数中的一些应该被封装为类。例如,考虑以下两个声明之间的差异

Circle makeCircle(double x, double y, double radius);
Circle makeCircle(Point center, double radius);

通过从参数中创建对象来减少参数的数量可能看起来像是作弊,但事实并非如此。当一组变量一起传递时,就像上例中的x和y一样,它们很可能是一个概念的一部分,应该有一个自己的名称。


接受可变参数的函数

具有可变参数的函数可以接受单参数、双参数甚至三参数。但是超过这个数量可能要犯错。


一个函数要么做某件事,要么回答某件事,但不能两者兼而有之。如果一个函数需要修改对象的状态,或者返回关于该对象的一些信息。同时做这两件事往往会导致混淆。

猜你喜欢

转载自blog.csdn.net/qq_34536551/article/details/86476418