《代码大全》第6~19章语句摘选

来源:互联网 发布:python爬虫和java爬虫 编辑:程序博客网 时间:2024/06/06 19:54

第6章 可以工作的类

p125:

成为高效程序员的一个关键就在于,当你开发程序任一部分的代码时,都能安全地忽视程序中尽可能多的其余部分。

p142:

每当你发现自己是通过查看类的内部实现来得知该如何使用这个类的时候,你就不是在针对接口编程了,而是在透过接口针对内部实现编程了。

如果仅仅根据类的接口文档还是无法得知何如使用一个类的话,正确的做法不是拉出这个类的源代码,从中查看其内部实现。(高手和牛人一般都喜欢diy,看实现只是为了了解如何实现,调自己代码的错误时跟到底部查看原因根本时观看,而这里的看接口文档只是在使用的时候,只是说明针对接口编程~当作黑盒子便可以放心使用的意思~下面作者是说找写这段代码的人去让他修改,如果这个人是自己,那么请好好考虑下这个类的抽象,如果抽象的目的不明确,那么就重新设计,如果抽象的目标很明确,就考虑下函数名等细节,因为该书的作者反复提到的也有代码即文档,而且是不会过时的文档这一观念)

p144:

Andy Hunt和Dave Thomas把LSP总结为:“派生类必须能通过基类的接口而被使用,且使用者无须了解两者之间的差异。”(Andy and Thomas 2000)。

p149:

下面来总结一下何时可以使用继承,何时又该使用包含:

-如果多个类共享数据而非行为,应该创建这些类可以包含的共用对象。

-如果多个类共享行为而非数据,应该让它们从共同的基类继承而来,并在基类里定义共用的子程序。

-如果多个类既共享数据也共享行为,应该让它们从一个共同的基类继承而来,并在基类里定义共用的数据和子程序。

-当你想由基类控制接口时,使用继承;当你想自己控制接口时,使用包含。

 

第7章 高质量的子程序

p171:

描述子程序所做的所有事情 子程序的名字应当描述其所有的输出结果以及副作用(side effects)。

p171:

如果你写的是有一些副作用的子程序,那就会起出很多又长又笨的名字。解决的方法不是使用某个描述性较弱的子程序名,而应该换一种方式编写程序,直截了当地解决问题而不产生副作用。(名字虽代表不了内部的实现,但是是内部实现的外表,外部调用者最直接快捷的了解,外表露出病态,内部就十之八九出了问题,正如目前的通货膨胀和高房价,政体不改,什么政策都只是使用某个描述性较弱的子程序名来掩饰其内部程序的设计不合理,正如刘哥所说:“偷懒迟早要还”的一样~)

 

第8章 防御式编程

p191:

用错误处理代码来处理预期会发生的状况,用断言来处理绝不应该发生的状况

p197:

正确性(correctness)意味着永不返回不准确的结果,哪怕不返回结果也比返回不准确的结果好。然而,健壮性(robustness)则意味着要不断尝试采取某些措施,以保证软件可以持续地运转下去,哪怕有时做出一些不够准确的结果。(健壮性的英文音译就是鲁棒性。。。)

p198:

异常是把代码中的错误或异常事件传递给调用方代码的一种特殊手段。

p199:

只在真正例外的情况下才抛出异常

p199:

异常的应用情形跟断言相似-都是用来处理那些不仅罕见甚至永远不该发生的情况。

p199:

不能用异常来推卸责任 如果某种的错误情况可以在局部处理,那就应该在局部处理掉它。不要把本来可以在局部处理掉的错误当成一个未被捕获的异常抛出去。

p199:

避免在构造函数和析构函数中抛出异常,除非你在同一地方把它们不会 当从构造函数和析构函数里抛出异常时,处理异常的规则马上就会变得非常复杂。比如说在C++里,只有在对象已完全构造之后才可能调用析构函数,也就是说,如果在构造函数的代码中抛出异常,就不会调用析构函数,从而造成潜在的资源泄漏(Meyers 1996, Stroustrup 1997)。在析构函数中抛出异常也有类似复杂的规则。

p199:

在恰当的抽象层次抛出异常

p200:

当你决定把一个异常传给调用方时,请确保异常的抽象层次与子程序接口的抽象层次是一致的。(原文这段话下面的举例很形象)

 

第9章 伪代码编程过程

p230:

理解每一行代码所起的作用,理解为什么需要这行代码。没有什么东西会仅仅因为它看上去可行就是正确的。如果你不知道它为什么可以工作,那么它很可能就是不能工作的——只是你还不知道罢了。

这里的底线是:只是能写出一个可以工作的子程序是不够的。如果你不知道它为什么可以工作,那就去研究它,讨论它,用其他的设计方案作实验,直到你弄明白为止。、

 

第10章 使用变量的一般事项

p255:

每个变量只用于单一用途(可以看下原文下面的例子,便于理解)

p256:

避免让代码具有隐含含义(可以看下原文下面的例子,便于理解)

 

第11章 变量名的力量

p260:

为变量命名时最重要的考虑事项时,该名字要完全、准确地描述出该变量所代表的事物。获得好名字的一种实用技巧就是用文字表达变量所代表的是什么。通常,对变量的描述就是最佳的变量名。

p261:

一个好记的名字反映的通常都是问题,而不是解决方案。一个好名字通常表达的是“什么”(what),而不是“如何”(how)。一般而言,如果一个名字反映了计算的某些方面而不是问题本身,那么它反映的就是“how”而非“what”了。请避免选取这样的名字,而应该在名字中反映出问题本身。(原文下面的例子很好~便于理解~)

p263:

很多程序都有表示计算结果的变量:总额、平均值、最大值,等等。如果你要用类似于Total、Sum、Average、Max、Min、Record、String、Pointer这样的限定词来修改(应该是修饰吧?)某个名字,那么请记住把限定词加到名字的最后。

这种方法具有很多优点。首先,变量名中最重要的那部分,即为这一变量赋予主要含义的部分应当位于最前面,这样,这一部分就可以显得最为突出,并会被首先阅读到。其次,采纳了这一规则,你将避免由于同时在程序中使用totalRevenue和revenueTotal而产生歧义。

把计算的量放在名字最后的这条规则也有例外,那就是Num限定词的位置已经是约定俗成的。Num放在变量名的开始位置代表一个总数:numCustomers表示的是员工的总数。Num放在变量名的结束位置代表一个下表:customerNum表示的是当前员工的序号。通过numCustomers最后代表复数的s也能够看出这两种应用之间的区别。然而,由于这样使用Num常常会带来麻烦,因此可能最好的办法是避开这些问题,用Count或者Total来代表员工的总数,用Index来指代某个特定的员工。这样,customerCount就代表员工的总数,customerIndex代表某个特定的员工。

p268:

为了取得更好的效果,应该把status替换为类似于error或者statusOK这样的名字,同时把sourceFile替换为sourceFileAvailable、sourceFileFound,或者其他能体现该变量所代表含义的名字。

有些程序员喜欢在他们写的布尔变量名前加上Is。这样,变量名就变成了一个问题:isdone?isError?isFound?isProcessingComplete?用true或false回答问题也就为该变量给出了取值。这种方法的优点之一是它不能用于那些模糊不清的名字:isStatus?这毫无意义。它的缺点之一是降低了简单逻辑表达式的可读性:if(isFound)的可读性要略差于if(ffound)。

p269:

使用肯定的布尔变量名 否定的名字如notFound、notdone以及notSuccessful等较难阅读,特别是如果它们被求反:if not notFound

 

第12章 基本数据类型

p299:

把C-style字符串的长度声明为CONSTANT+1(理由可以看看原文的详细解释。。。)

p301:

要把逻辑变量或者布尔变量用错是非常困难的,而更仔细地运用它会让你的程序变得更清晰。

用布尔变量对程序加以文档说明(其实就是用布尔变量名进行了代码层面的文档说明效果,直接上书中的例子了啊~)

--------------------------------------------------------------------------------------------------------------------------------------------------------

Java示例:目的不明确的布尔判断

if( ( elementIndex < 0 ) || ( MAX_ELEMENTS < elementIndex ) || ( elementIndex == lastElementIndex ) )

{

...

}

--------------------------------------------------------------------------------------------------------------------------------------------------------

Java示例:目的明确的布尔判断

finished = ( ( elementIndex < 0 ) || ( MAX_ELEMENTS < elementIndex )  );

repeatedEntry = ( elementIndex == lastElementIndex );

if( finished || repeatedEntry )

{

...

}

--------------------------------------------------------------------------------------------------------------------------------------------------------

p315:

给所创建的类型取功能导向的名字

避免使用预定义的类

(上面两条是小标题了,隶属于“创建自定义数据类型的指导原则”,原文中有详细的解释,这里的“自定义数据类型”指的应该是c++中的typedef,而非class,仅看小标题估计不是很清楚,希望翻看原文回顾下~)

 

第13章 不常见的数据类型、

p320:

用结构体来明确数据关系 结构体把相关联的一组数据项聚集在一起。有时了解一个程序最为困难的部分就在于理清哪些数据之间互相有联系。这就像来到一座小镇上问谁认识谁一样。你会发现每个人似乎都与其他人有关,但又并不尽然,这样你永远不会得到一个好的答案。

如果数据的组织结构非常清晰,那么弄清楚哪些数据与哪些相关联就会容易多了。

(这个是原文中解释使用结构体的理由中的第一条,其实结构体一般也用过,但是教科书上一般的解释都是和class差不多,除了默认访问级别class为private而struct为public,一般没有像本书解释使用结构体的理由,所以值得一看。原文中而后的一些论点感觉和第一条差不多,可以看下,例子也都很好~)

p322:

用结构体来简化参数列表

(这个也是原文中解释使用结构体的理由中的其中一条,好像前面说函数参数的时候说过,如果一个函数需要同一个对象中的几个成员变量,那是直接传对象好还是拆开传这几个变量那?好像说的是看函数抽象成是需要这个对象那还是这几个参数。。。哦~找到了p179,“子程序的接口要表达何种抽象?”,但是p322中好像说的是另一种解释吧,所以应该翻到那也看看。。。)

p325:

把指针操作限制在子程序或者类里面

(这是使用指针的一般技巧的其中一个小标题,其中的内容值得看看~)

p327:

用额外的指针变量来提高代码清晰度

(看下例子,可以明白这句话的含义,也可以看出作者的重要观点,代码清晰度,代码即文档~)

p336:

与全局数据有关的奇异的和令人激动的别名问题

(这个好像就属于无意间修改了全局数据把~看下原文中的例子吧~有点意思~)

p337:

与全局数据有关的非确定的初始化顺序事宜 有些语言,特别是C++,没有定义不同“转译单元”(文件)里的数据初始化的顺序。如果在初始化一个文件中的全局变量的时候使用了在另一个不同文件中初始化的全局变量,那么除非你用明确的手段来确保这两个变量能按照正确的顺序初始化,否则请不要对第二个变量的取值下任何赌注。

(底层了一点,不过很值得看看~这边解释还不是很懂~Google下吧~)

p341:

在你的访问器子程序里构建一个抽象层

(接着就讲了一些访问器子程序的使用条件和优势,可以看看如何和全局变量搭配使用,说的都很棒~原文此话下面的表格很直观很好~)

把这些信息隐藏在抽象访问子程序后面,将会使得代码的作用不言自明,同时使得代码在问题域的层面上就能被理解,而不是在实现细节层上去理解他。

(和上面的话隔了几行~连起来看~不错~)

p342:

使得对一项数据的所有访问都发生在同一个抽象层上

(不懂可以看下原文下的小段,解释的很好~还有和上页一样经典的表格。。。)

 

第15章 使用条件语句

p355

在写if语句的时候请遵循下述指导原则

首先写正常代码路径;再处理不常见情况

(跳过了一个,这边只是抽取几点,详情见原文)

把正常情况的处理放在if后面而不要放在else后面

 

第16章 控制循环

p369:

带退出循环通常是在这样的场合下使用:如果把循环条件检测放在循环开始或结束处,那就需要写出一个半循环(loop-and-a-half)的代码。

(这个问题遇到过,然后就很郁闷,原文中这句话紧跟一个例子,而这话只说了会出现半循环的场合下使用带退出循环,但是没说出现半循环有什么不好,原文例子下给了解释,如下)

p370:

例子中的前两行代码又在while循环中的后两行中重复出现了。在修改的时候,你很容易忘记让这两组代码保持一致。如果别的程序员来修改这段代码,很可能不会注意到这两组代码应该同步地修改。不管怎样,其结构都是由于没有完全地修改而导致出错。你可以按照下面的样子来重写这些代码,以使之更清晰:

(如上所说,看原文中的例子吧。。。还有其他一些琐碎的知识点,比如:

“在适当的情况下多使用for循环”;

“在while循环更适用的时候,不要使用for循环”;

“把循环内务操作要么放在循环的开始,要么放在循环的末尾 循环内务操作(housekeeping)是指像i = i + 1或者j++这样的表达式,他们的主要目的不是完成循环工作,而是控制循环。”;

“一个循环只做一件事”;

“不要为了终止循环而胡乱改动for循环的下标”;

“避免出现一览于循环下标最终取值的代码”;

还有本章末尾的轻松创建循环-由内而外。。。我偷懒了。。因为下班了。。好饿。。看不懂只能翻书了。。。)

 

第17章 不常见的控制结构

第18章 表驱动法

原创粉丝点击