我有一段代码源文件怎么保存,但我不知道该怎么些,所以把它存起来?


#include<stdio.h>#defineN5voidsort(intA[N])//用以对输入数据进行排序的函数{inti,j,value;for(i=0;i<=N...
#include<stdio.h>#define N 5void sort(int A[N])//用以对输入数据进行排序的函数{int i,j,value;for(i=0;i<=N;i++){for(j=0;j<=N-i-1;j++){if(A[j]<=A[j+1]){value=A[j];A[j]=A[j+1];A[j+1]=value;}}}}void main(){int Array01[N],i;char c;printf("请输入一组数据:");for(i=0;i<N;i++)
{scanf("%d",&Array01[i]);
}
printf("你刚才一共输入了 %d 个数据\n",i+1);printf("请问是否进行排序?(Y/N)\n");fflush(stdin);while((c=getchar())=='y'
(c=getchar())=='Y'){sort(Array01);printf("排序后的数据为:");for(i=0;i<N;i++){printf("%d ",Array01[i]);}printf("\n");break;}}报错:--------------------Configuration: exersice - Win32 Debug--------------------Linking...01.obj : error LNK2005: _main already defined in exersice.objDebug/exersice.exe : fatal error LNK1169: one or more multiply defined symbols found执行 link.exe 时出错.exersice.exe - 1 error(s), 0 warning(s)注:希望能帮我分析一下问题出在哪里并给我一段正确的代码!谢谢!先谢过楼下两位但小弟刚试试过,两种方法都不行
展开
选择擅长的领域继续答题?
{@each tagList as item}
${item.tagName}
{@/each}
手机回答更方便,互动更有趣,下载APP
提交成功是否继续回答问题?
手机回答更方便,互动更有趣,下载APP
把fflish(stdin)去掉吧。fflush(stdin)刷新标准输入缓冲区,把输入缓冲区里的东西丢弃在试试看吧sort函数循环条件为for(i=0;i<N;i++)
一、整洁代码A.混乱的代价1.有些团队在项目初期进展迅速,但有那么一两年的时间却慢去蜗行。对代码的每次修改都影响到其他两三处代码2.花时间保持代码整洁不但有关效率,还有关生存3.程序员遵从不了解混乱风险经理的意愿,也是不专业的做法4.Bjarne Stroustrup,C++发明者:我喜欢优雅和高效的代码。代码逻辑应该直接了当,叫缺陷难以隐藏;尽量减少依赖关系,使之便于维护;依据某种分层战略完善错误处理代码;性能调至最优,省得引诱别人做没规矩的优化,搞出一堆混乱来。整洁的代码只做好一件事。5.Grady Booch,《面向分析与设计》:整洁的代码简单直接。整洁的代码如同优美的散文。整洁的代码从不隐藏设计者的意图,充满了干净利落的抽象和直接了当的控制语句。6.Dave Thomas,OTI公司创始人:整洁的代码应可由作者之外的开发者阅读和增补。它应有单元测试和验收测试。它使用有意义的命名。它只提供一种而非多种做一件事的途径。它只有尽量少的依赖关系,而且要明确地定义和提供清晰、尽量少的API。代码应通过其字面表达含义,因为不同的语言导致并非所有必须信息均可通过代码自身清晰表达。7.Michael Feathers,《修改代码的艺术》:我可以列出我留意到的整洁代码的所有特点,但其中有一条是根本性的。整洁的代码总是看起来像是某位特别在意它的人写的。几乎没有改进的余地。代码作者什么都想到了,如果你企图改进它,总会回到原点,赞叹某人留给你的代码——全心投入的某人留下的代码。8.Ron Jeffries,《极限编程实施》:简单代码,依其重要顺序:能通过所有测试;没有重复代码;体现系统中的全部设计理念;包括尽量少的实体,比如类、方法、函数等9.Ward Cunningham,Wiki发明者:如果每个例程都让你感到深合已意,那就是整洁代码。如果代码让编程语言看起来像是专为解决那个问题而存在,就可以称之为漂亮的代码。B.思想流派1.读与写花费时间的比例起过10:1C.童子军军规1.“让营地比你来时更干净”2.如果每次签入时,代码都比签出时干净,那么代码就不会腐坏二、有意义的命名A.名副其实1.变量、函数或类的名称应该已经答复了所有的大问题,如果名称需要注释来补充,那就不算名副其实2.代码的模糊度:即上下文在代码中未被明确体现的程度B.避免误导1.程序员必须避免留下掩藏代码本意的错误线索。应当避免使用与本意相悖的词2.以同样的方式拼写出同样的概念才是信息,拼写前后不一致就是误导3.要注意使用小写字母i和大写字母O作为变量名,看起来像“壹”和“零”C.做有意义的区分1.同一作用范围内两样不同的东西不能重名,如果名称必须相异,那其意思也应该不同才对2.废话是另一种没意义的区分。假设你有一个Product类,如果还有一个ProductInfo或ProductData类,那它们的名称虽然不同,意思却无区别3.只要体现出有意义的区分,使用a和the这样的前缀就没错4.废话都是冗余。Variable一词记录不应当出现在变量名中,Table一词永远不应当出现在表名中D.使用读得出来的名称E.使用可搜索的名称1.单字母名称和数字常量有个问题,就是很难在一大篇文字中找出来F.避免使用编码1.把类型或作用域编进名称里面,徒然增加了解码的负担2.也不必用m_前缀来标明成员变量,应当把类和函数做得足够小,消除对成员前缀的需要3.不加修饰的接口,不要用前导字母IG.避免思维映射1.不应当让读者在脑中把你的名称翻译为他们熟知的名称,单字母变量名就是个问题2.专业程序员了解,明确是王道H.类名1.类名和对象名应该是名词或名词短语,类名不应当是动词I.方法名1.方法名应该是动词或动词短语。属性访问器、修改器和断言应该根据其值命名,并依Javabean标准加上get、set和is前缀2.可以考虑将相应构造器设置为private,强制使用这种命名手段J.别扮可爱1.言到意到,意到言到K.别用双关语1.避免将同一单词用于不同目的2.应尽力写出易于理解的代码,把代码写得让别人能一目尽览而不必殚精竭虑地研究L.使用解决方案领域名称1.尽管用那些计算机科学术语、算法名、模式名、数学术语M.使用源自所涉问题领域的名称1.如果不能用程序员熟悉的术语来给手头的工作命名,就采用从所涉问题领域而来的名称2.优秀的程序员和设计师,其工作之一就是分离解决方案领域和问题领域的概念N.添加有意义的语境1.你需要用有良好命名的类、函数或名称空间来放置名称,给读者提供语境2.如果没这么做,给名称添加前缀就是最后一招了O.不要添加没用的语境1.只要短名称足够清楚,就要比长名称好P.最后的话1.取好名字最难的地方在于需要良好的描述技巧和共有文化背景三、函数A.短小1.函数的第一规则是要短小,第二条规则是还要更短小2.if语句、else语句、while语句等,其中的代码块应该只有一行,该行大抵是一个函数调用语句3.函数不应该大到足以容纳嵌套结构,所以,函数的缩进层级不该多于一层或两层B.只做一件事1.函数应该做一件事。做好这件事,只做这一件事2.要判断函数是否不止做了一件事,就是看看是否能再拆出一个函数,该函数不仅只是单纯地重新诠释其实现3.只做一件事的函数无法被合理地切分为多个区段C.每个函数一个抽象层级1.要确保函数只做一件事,函数中的语句都要在同一抽象层级上2.自顶向下读代码:向下规则,让代码拥有自顶向下的阅读顺序,让每个函数后面都跟着下一抽象层级的函数D.switch语句1.写出短小的switch语句很维,写出只做一件事的switch语句也很难,Switch天生要做N件事2.将switch语句埋到抽象工厂底下,不让任何人看到3.如果只出现一次,用于创建多态对象,而且隐藏在某个继承关系中,在系统其他部分看不到,就还能容忍E.使用描述性的名称1.沃德原则:“如果每个例程都让你感到深合已意,那就是整洁代码”2.函数越短小,功能越集中,就越便于取个好名字3.别害怕长名称,长而具有描述性的名称,要比短而令人费解的名称好4.命名方式要保持一致。使用与模块名一脉相承的短语、名词和动词给函数命名F.函数参数1.最理想的参数数量是零,有足够的理由才能用三个以上参数2.事件:在这种形式中,有输入参数而无输出参数,程序将函数看作一个事件,使用该参数修改系统状态3.对于转换,使用输出参数而非返回值令人迷惑,如果函数要对输入参数进行转换操作,转换结果就该体现为返回值4.向函数传入布尔值会使方法签名立刻变得复杂起来,大声宣布函数不止做一件事5.如果函数看来需要两个、三个或三个以上参数,就说明其中一些参数应该封装为类了6.有可变参数的函数可能是一元、二元甚至三元,超过这个数量就可能要犯错了7.对于一元函数,函数和参数应当形成一种非常良好的动词/名词对形式G.无副作用1.函数承诺只做一件事,但还是会做其他被藏起来的事,会导致古怪的时序性耦合及顺序依赖2.参数多数会被自然而希地看作是函数的输入H.分隔指令与询问1.函数要么做什么事,要么回答什么事,但二者不可得兼I.使用异步替代返回错误码1.从指令式函数返回错误码轻微违反了指令与询问分隔的规则。它鼓励了在if语句判断中把指令当作表达式使用2.try/catch代码块把错误处理与正常流程混为一谈,最好把try和catch代码块的主体部分抽离出来,另外形成函数3.错误处理就是一件事,处理错误的函数不该做其他事4.依赖磁铁(dependency magnet):其他许多类都得导入和使用它J.别重复自己1.重复可能是软件中一切邪恶的根源,许多原则与实践规则都是为控制与消除重复而创建K.结构化编程1.每个函数、函数中的每个代码块都应该有一个入口、一个出口。遵循这些规则,意味着在每个函数中只该有一个return语句,循环中不能有break或者continue语句,而且永永远远不能有任何的goto语句2.只有在大函数中这些规则才会有明显好处,因为,只要函数保持短小,偶尔出现的return、break或continue语句没有坏处,goto语句尽量避免L.如何写出这样的函数1.打磨代码,分解函数、修改名称、消除重复2.缩短和重新安置方法、拆散类、保持测试通过四、注释1.若编程语言足够有表达力,就不需要注释2.注释的恰当用法是弥补我们在用代码表达意图时遭遇的失败。注释总是一种失败3.程序员应当负责将注释保持在可维护、有关联、精确的高度,更应该把力气用在写清楚代码上,直接保证无须编写注释4.不准确的注释要比没注释坏得多A.注释不能美化糟糕的代码1.带有少量注释的整洁而有表达力的代码,要比带有大量注释的零碎而复杂的代码像样得多2.与其花时间编写解释你搞出的糟糕的代码的注释,不如花时间清洁那堆糟糕的代码B.用代码来阐述1.用代码解释你大部分的意图,很多时候,简单到只需要创建一个描述与注释所言同一事物的函数即可C.好注释1.法律信息2.提供信息的注释3.对意图的解释:提供某个决定后面的意图4.阐释:注释把某些晦涩难懂的参数或返回值的意义翻译为某种可读形式5.警示6.TODO注释:注意要清理7.放大:放大某种看来不合理之物的重要性8.公共API中的JavadocD.坏注释1.喃喃自语2.多余的注释3.误导性注释4.循规式注释5.日志式注释6.废话注释7.可怕的废话8.能用函数或变量时就别用注释9.位置标记:如果标记栏不多,就会显而易见,所以,尽量少用标记栏,只在特别有价值的时候用10.括号后面的注释11.归属与署名12.注释掉的代码13.HTML注释14.非本地信息15.信息过多16.不明显的联系17.函数头18.非公共代码中的Javadoc19.范例五、格式A.格式的目的1.代码格式关乎沟通,而沟通是专业开发者的头等大事B.垂直格式1.短文件通常比长文件易于理解2.源文件也要像报纸文章那样 ,名称应当简单且一目了然,最顶部应该给出高层次概念和算法,细节应该往下渐次展开3.几乎所有的代码都是从上往下读,从左往右读。每行展现一个表达式或一个子句,每代码行展示一条完整的思路。这些思路用空白行区隔开来。4.如果说空白行隔开了概念,靠近的代码行则暗示了它们之间的紧密关系5.除非有很好的理由,否则就不要把关系密切的概念放到不同的文件中,实际上,这也是避免使用protected变量的理由之一,应避免迫使读者在源文件和类中跳来跳去6.变量声明应尽可能靠近其使用位置,在函数顶部出现,循环的控制变量总是在循环语句中声明7.实体变量在类的顶部声明8.相关函数,若某个函数调用了另外一个,就应该把它们放到一起,而且调用者应该尽可能放在被调用者上面9.概念相关的代码应该放到一起,相关性越强,彼此之间的距离就该越短10.我们想自上向下展示函数调用依赖顺序,被调用的函数应该放在执行调用的函数下面,这就建立了一种自顶向下贯穿源代码模块的良好信息流C.横向格式1.尽力保持代码行短小,遵循无需拖动滚动条到右边的原则,最好不超过120个2.我们使用空格字符将彼此紧密相关的事物连接到一起,也用空格字符把相关性较弱的事物分隔开3.对齐,像是在强调不重要的东西,把目光从真正的意义上拉开4.如果有较长的列表需要做对齐处理,那问题就是在列表的长度上而不是对齐上5.程序员相当依赖缩进模式6.有时,while或for语句的语句体为空,如果无法避免,就确保空范围体的缩进,用括号包围起来D.团队规则1.一组开发者应当认同一种模式风格,每个成员都应该采用那种风格2.好的软件系统是由一系列读起来不错的代码文件组成的,需要拥有一致和顺畅的风格六、对象和数据结构A.数据抽象1.隐藏实现关乎抽象,类并不简单地用取值器和赋值器将其变量推向外部,而是曝露抽象接口,以便用户无需了解数据的实现就能操作数据本体B.数据、对象的反对称性1.对象把数据隐藏于抽象之后,曝露操作数据的函数。数据结构曝露其数据,并没有提供有意义的函数2.对象与数据结构之间的二分原理:* 过程式代码(使用数据结构的代码)便于在不改动既有数据结构的前提下添加新函数。面向对象代码便于在不改动既有函数的前提下添加新类* 过程式代码难以添加新数据结构,因为必须修改所有函数。面向对象代码难以添加新函数,因为必须修改所有类C.得墨忒耳律1.得墨忒耳律(The Law of Demeter):模块不应了解它所操作对象的内部情形,意味着对象不应通过存取器曝露其内部结构,因为这样更像是曝露而非隐藏其内部结构2.混合结构,一半是对象,一半是数据结构,应避免这种结构D.数据传送对象1.最为精练的数据结构,是一个只有公共变量、没有函数的类,这种被称为数据传送对象,或DTO(Data Transfer Objects)。在与数据库通信、或解析套接字传递的消息之类场景中2.JavaBean或Active Record3.不要塞进业务规则方法,把Active Record当做数据结构,并创建包含业务规则、隐藏内部数据(可能就是Active Record的实体)的独立对象七、错误处理1.错误处理很重要,但如果它搞乱了代码逻辑,就是错误的做法A.使用异常而非返回码1.遇到错误时,最好抛出一个异常。调用代码很整洁,其逻辑不会被错误处理搞乱B.先写Try-Catch-Finally语句1.异常的妙处之一是,它们在程序中定义了一个范围。执行try-catch-finally语句中try部分的代码时,你是在表明可随时取消执行,并在catch语句中接续2.在某种意义上,try代码块就像是事务,catch代码块将程序维持在一种持续状态3.在编写可能抛出异常的代码时,最好先写try-catch-finally语句,能帮你定义代码的用户应该期待什么,无论try代码块中执行的代码出什么错都一样C.使用不可控异常1.可控异常的代价就是违反开放/闭合原则,得在catch语句和抛出异常处之间的每个方法签名中声明该异常2.可控异常意味着对软件中较低层级的修改,都将波及较高层级的签名D.给出异常发生的环境说明1.抛出的每个异常,都应当提供足够的环境说明,以便判断错误的来源和处所2.应创建信息充分的错误消息,并和异常一起传递出去E.依调用者需要定义异常类1.最重要的考虑是它们如何被捕获2.将第三方API打包是个良好的实践手段,降低了对每个第三方的依赖,也有助于模拟第三方调用F.定义常规流程1.特例模式(SPECIAL CASE PATTERN,[Fowler]),创建一个类或配置一个对象,用来处理特例,异常行为被封装到特例对象中G.别返回null值1.返回null值,基本是在给自己增加工作量,也是在给调用者添乱,只要有一处没检查null值,应用程序就会失控H.别传递null值1.将null值传递给其他方法更糟糕,除非API要求你向它传递null值,否则就要尽可能避免传递null值八、边界A.使用第三方代码1.第三方程序包和框架提供者追求普适性,这样就能在多个环境中工作,吸引广泛的用户2.我们建议不要将Map(或在边界上的其他接口)在系统中传递,把它保留在类或近亲类中,避免从API中返回边界接口,或将接口作为参数传递给公共APIB.浏览和学习边界C.学习性测试的好处不只是免费1.学习性测试毫无成本,编写测试是获得这些知识(要使用的API)的容易而不会影响其他工作的途径2.学习性测试确保第三方程序包按照我们想要的方式工作D.使用尚不存在的代码1.编写我们想得到的接口,好处之一是它在我们控制之下,有助于保持客户代码更可读,且集中于它该完成的工作E.整洁的边界1.边界上的改动,有良好的软件设计,无需巨大投入和重写即可进行修改2.边界上的代码需要清晰的分割和定义了期望的测试。依靠你能控制的东西,好过依靠你控制不了的东西,免得日后受它控制3.可以使用ADAPTER模式将我们的接口转换为第三方提供的接口九、单元测试A.TDD三定律1.在编写能通过的单元测试前,不可编写生产代码2.只可编写刚好无法通过的单元测试,不能编译也算不通过3.只可编写刚好足以通过当前失败测试的生产代码B.保持测试整洁1.脏测试等同于没测试,测试必须随生产代码的演进而修改,测试越脏,就越难修改2.测试代码和生产代码一样重要,它需要被思考、被设计和被照料,它该像生产代码一般保持整洁3.如果测试不能保持整洁,你就会失去它们,没有了测试,你就会失去保证生产代码可扩展的一切要素C.整洁的测试1.三个要素:可读性、可读性和可读性,明确、简洁还有足够的表达力2.构造-操作-检验(BUILD-OPERATE-CHECK)模式,第一个环节构造测试数据,第二个环节操作测试数据,第三个部分检验操作是否得到期望的结果3.守规矩的开发者也将他们的测试代码重构为更简洁和具有表达力的形式D.每个测试一个断言1.JUnit中每个测试函数都应该有且只有一个断言语句2.最好的说法是单个测试中的断言数量应该最小化3.更好一些的规则或许是每个测试函数中只测试一个概念4.最佳规则是应该尽可能减少每个概念的断言数量,每个测试函数只测试一个概念E.F.I.R.S.T1.快速(Fast)测试应该够快2.独立(Independent)测试应该相互独立3.可重复(Repeatable)测试应当可在任何环境中重复通过4.自足验证(Self-Validating)测试应该有布尔值输出5.及时(Timely)测试应及时编写十、类A.类的组织1.类应该从一级变量列表开始,如果有公共静态变量,应该先出现,然后是私有静态变量,以及实体变量,很少会有公共变量2.公共函数应该跟在变量列表之后3.保持变量和工具函数的私有性,但并不执着于此B.类应该短小1.第一规则是类应该短小,第二规则是还要更短小2.衡量方法,计算权责(responsibility)3.类的名称应当描述其权责,如果无法为某个类命以精确的名称,这个类大概就太长了,类名越含混,该类越有可能拥有过多权责4.单一权责原则(SRP)认为,类或模块应有且只有一条加以修改的理由5.系统应该由许多短小的类而不是少量巨大的类组成,每个小类封装一个权责,只有一个修改的原因,并与少数其他类一起协同达成期望的系统行为6.方法操作的变量越多,就越黏聚到类上,如果一个类的每个变量都被每个方法所使用,则该类具有最大的内聚性7.保持函数和参数列表短小的策略,有时会导致为一组子集方法所用的实体变量数量增加。出现这种情况时,往往意味着至少有一个类要从大类中挣扎出来。你应当尝试将这些变量和方法分拆到两个或多个类中,让新的类更为内聚8.将大函数拆为许多小函数,往往也是将类拆分为多个小类的时机C.为了修改而组织1.在整洁的系统中,我们对类加以组织,以降低修改的风险2.开放-闭合原则(OCP):类应当对扩展开放,对修改封闭3.在理想系统中,我们通过扩展系统而非修改现有代码来添加新特性4.依赖倒置原则(Dependency Inversion Principle,DIP),类应该依赖于抽象而不是依赖于具体细节十一、系统A.如何建造一个城市1.每个城市都有一组人管理不同的部分,有人负责全局,其他人负责细节2.深化出恰当的抽象等级和模块,好让个人和他们所管理的“组件”即便在不了解全局时也能有效地运转B.将系统的构造与使用分开1.构造与使用是非常不一样的过程2.软件系统应将启始过程和启始过程之后的运行时逻辑分离开,在启始过程中构建应用对象,也会存在互相缠结的依赖关系3.将构造与使用分开的方法之一是将全部构造过程搬迁到main或被称为main的模块中,设计系统的其余部分时,假设所有对象都已正确构造和设置4.可以使用抽象工厂模式让应用自行控制何时创建对象,但构造的细节却隔离于应用程序代码之外5.控制反转将第二权责从对象中拿出来,转移到另一个专注于此的对象中,从而遵循了单一权责原则。在依赖管理情景中,对象不应负责实体化对自身的依赖,反之,它应当将这份权责移交给其他“有权力”的机制,从而实现控制的反转C.扩容1.“一开始就做对系统”纯属神话,反之,我们应该只去实现今天的用户故事,然后重构,明天再扩展系统、实现新的用户故事,这就是迭代和增量敏捷的精髓所在。测试驱动开发、重构以及它们打造出的整洁代码,在代码层面保证了这个过程的实现2.软件系统与物理系统可以类比。它们的架构都可以递增式的增长,只要我们持续将关注面恰当地切分3.持久化之类关注面倾向于横贯某个领域的天然对象边界D.Java代理1.适用于简单情况,例如在单独的对象或类中包装方法调用2.旧式的Java对象(Plain-Old Java Object, POJO)E.纯Java AOP框架F.AspectJ的方面G.测试驱动系统架构1.通过方面式(AOP)的手段切分关注面的威力不可低估。假使你能用POJO编写应用程序的领域逻辑,在代码层面与架构关注面分离开,就有可能真正地用测试来驱动架构2.没必要先做大设计(Big Design Up Front,BDUF),BDUF甚至是有害的,它阻碍改进,因为心理上会抵制丢弃即成之事,也因为架构上的方案选择影响到后续的设计思路3.我们可以从“简单自然”但切分良好的架构开始做软件项目,快速交付可工作的用户故事,随着规模的增长添加更多基础架构4.最佳的系统架构由模块化的关注面领域组成,每个关注面均用纯Java(或其他语言)对象实现,不同的领域之间用最不具有侵害性的方面或类方面工具整合起来,这种架构能测试驱动,就像代码一样H.优化决策1.模块化和关注面切分成就了分散化管理和决策2.延迟决策至最后一刻也是好手段,它让我们能够基于最有可能的信息做出选择3.拥有模块化关注面的POJO系统提供的敏捷能力,允许我们基于最新的知识做出优化的、时机刚好的决策,决策的复杂性也降低了I.明智使用添加了可论证价值的标准1.有了标准,就更易复用想法和组件、雇用拥有相关经验的人才、封装好点子,以及将组件连接起来。不过,创立标准的过程有时却漫长到行业等不及的程度,有些标准没能与它要服务的采用者的真实需求相结合J.系统需要领域特定语言1.领域特定语言(Domain-Specific Language, DSL)是一种单独的小型脚本语言或以标准语言写就的API,领域专家可以用它编写读像是组织严谨的散文一般的代码2.领域特定语言允许所有抽象层级和应用程序中的所有领域,从高级策略到底层细节,使用POJO来表达十二、迭进A.通过迭进设计达到整洁目的1.“简单规则”:* 运行所有测试* 不可重复* 表达了程序员的意图* 尽可能减少类和方法的数量* 以上规则按其重要程序排列B.简单设计原则1:运行所有测试1.设计必须制造出如预期一般工作的系统,这是首要因素2.全面测试并持续通过所有测试的系统,就是可测试的系统,不可验证的系统,绝不应部署3.只要系统可测试,就会导向保持类短小且目的单一的设计方案4.紧耦合的代码难以编写测试5.遵循有关编写测试并持续运行测试的简单、明确的规则,系统就会更贴近OO低耦合度、高内聚度的目标,编写测试引致更好的设计C.简单设计原则2-4:重构1.有了测试,就能保持代码和类的整洁,方法就是递增式地重构代码2.测试消除了对清理代码就会破坏代码的恐惧D.不可重复1.重复是拥有良好设计系统的大敌2.极其雷同的代码行当然是重复,还有实现上的重复等其他一些形态3.“小规模复用”可大量降低系统复杂性,要想实现大规模复用,必须理解如何实现小规模复用4.模板方法模式是一种移除高层级重复的通用技巧E.表达力1.软件项目的主要成本在于长期维护,代码应当清晰地表达其作者的意图2.可以通过选用好名称来表达3.可以通过保持函数和类尺寸短小来表达4.可以通过采用标准命名法来表达5.编写良好的单元测试也具有表达性6.做到有表达力的最重要方式是尝试F.尽可能少的类和方法1.类和方法的数量太多,有时是由毫无意义的教条主义导致的,应该采用更实用的手段2.目标是在保持函数和类短小的同时,保持整个系统短小精悍十三、并发编程A.为什么要并发1.并发是一种解耦策略,它帮助我们把做什么(目的)和何时(时机)做分解开2.解耦目的与时机能明显地改进应用程序的吞吐量和结构3.单线程程序许多时间花在等待web套接字I/O结束上面,通过采用同时访问多个站点的多线程算法,就能改进性能4.常见的迷思和误解* 并发总能改进性能:只在多个线程或处理器之间能分享大量等待时间的时候管用* 编写并发程序无需修改设计:可能与单线程系统的设计极不相同* 在采用web或ejb容器时,理解并发问题并不重要5.有关编写并发软件的中肯的说法:* 并发会在性能和编写额外代码上增加一些开销* 正确的并发是复杂的,即使对于简单的问题也是如此* 并发缺陷并非总能重现,所以常被看做偶发事件而忽略,未被当做真的缺陷看待* 并发常常需要对设计策略的根本性修改B.挑战1.线程在执行代码时有许多可能路径可行,有些路径会产生错误的结果C.并发防御原则1.单一权责原则(SRP):方法/类/组件应当只有一个修改的理由* 并发相关代码有自己的开发、修改和调优生命周期* 开发相关代码有自己要对付的挑战,和非并发相关代码不同* 即使没有周边应用程序增加的负担,写得不好的并发代码可能的出错方式数量也已经足具有挑战性* 建议:分离并发相关代码与其他代码2.推论:限制数据作用域* 采用synchronized关键字在代码中保护一块使用共享对象的临界区(critical section)* 建议:谨记数据封闭;严格限制对可能被共享的数据的访问3.推论:使用数据复本* 一开始就避免共享数据,复制对象并以只读方式对待,或复制对象,从多个线程收集所有复本的结果,并在单个线程中合并这些结果4.推论:线程应尽可能地独立* 让每个线程在自己的世界中存在,不与其他线程共享数据* 建议:尝试将数据分解到可被独立线程(可能在不同处理器上)操作的独立子集D.了解Java库 1.要注意:* 使用类库提供的线程安全群集* 使用executor框架(executor framework)执行无关任务* 尽可能使用非锁定解决方案* 有几个类并不是线程安全的E.了解执行模型1.一些基础定义* 限定资源:并发环境中有着固定尺寸或数量的资源* 互斥:每一时刻仅有一个线程能访问共享数据或共享资源* 线程饥饿:一个或一组线程在很长时间内或永久被禁止* 死锁:两个或多个线程互相等待执行结束。每个线程都拥有其他线程需要的资源,行不到其他线程拥有的资源,就无法终止* 活锁:执行次序一致的线程,每个都想要起步,但发现其他线程已经“在路上”。由于竞步的原因,线程会持续尝试起步,但在很长时间内却无法如愿,甚至永远无法启动2.生产者-消费者模型:一个或多个生产者线程创建某些工作,并置于缓存或队列中。一个或多个消费者线程从队列中获取并完成这些工作。生产者消费者之间的队列是一种限定资源3.读者-作者模型:协调读者线程,不去读作者线程正在更新的信息(反之亦然),这是一种辛苦的平衡工作,作者线程倾向于长期锁定许多读者纯种,从而导致吞吐量问题4.宴席哲学家5.建议学习这些基础算法,理解其解决方案F.警惕同步方法之间的依赖1.同步方法之间的依赖会导致并发代码中的狡猾缺陷,建议避免使用一个共享对象的多个方法2.基于客户端的锁定:客户端代码在调用第一个方法前锁定服务端,确保锁的范围覆盖了调用最后一个方法的代码3.基于服务端的锁定:在服务端内创建锁定服务端的方法,调用所有方法,然后解锁。让客户端代码调用新方法4.适配服务端:创建执行锁定的中间层。这是一种基于服务端的锁定的例子,但不修改原始服务端代码G.保持同步区域微小1.同一个锁维护的所有代码区域在任一时刻保证只有一个线程执行,因为它们带来了延迟和额外开销,临界区应该被保护起来,应该尽可能少地设计临界区H.很维编写正确的关闭代码1.平静关闭很难做到,常见问题与死锁有关,线程一直等待永远不会到来的信号2.建议:尽早考虑关闭问题,尽早令其工作正常I.测试线程代码1.建议:编写有潜力曝露问题的测试,在不同的编程配置、系统配置和负载条件下频繁运行。如果测试失败,跟踪错误。别因为后来测试通过了后来的运行就忽略失败2.将伪失败看作可能的线程问题:线程代码导致“不可能失败的”失败,不要将系统错误归咎于偶发事件3.先使非线程代码可工作:不要同时追踪非线程缺陷和线程缺陷,确保代码在线程之外可工作4.编写可插拔的线程代码,能在不同的配置环境下运行5.编写可调整的线程代码:允许线程依据吞吐量和系统使用率自我调整6.运行多于处理器数量的线程:任务交换越频繁,越有可能找到错过临界区域导致死锁的代码7.在不同平台上运行:尽早并经常地在所有目标平台上运行线程代码8.装置试错代码:增加对Object.wait()、Object.sleep()、Object.yield()、Object.priority()等方法的调用,改变代码执行顺序,硬编码或自动化十四、逐步改进1.要编写清洁代码,必须先写肮脏代码,然后再清理它2.毁坏程序的最好方法之一就是以改进之名大动其结构十五、JUnit内幕十六、重构SerialDate十七、味道与启发A.注释1.不恰当的信息:注释只应该描述有关代码和设计的技术性信息2.废弃的注释3.冗余的注释4.糟糕的注释:别闲扯,别画蛇添足,保持简洁5.注释掉的代码:删除它B.环境 1.需要多步才能实现的构建:构建系统应该是单步的小操作2.需要多步才能做到的测试:应当能够发出单个指令就可以运行全部单元测试C.函数1.过多的参数:参数量应该少,三个以上的参数非常值得质疑2.输出参数:输出参数违反直觉,直接修改它所有对象的状态3.标识参数:布尔值参数大声宣告函数做了不止一件事,应该消灭掉4.死函数:永不被调用的方法应该丢弃D.一般性问题:1.一个源文件中存在多种语言:尽力减少源文件中额外语言的数量和范围2.明显的行为未被实现:遵循“最小惊异原则”(The principle of Least Surprise),函数或类应该实现其他程序员有理由期待的行为 3.不正确的边界行为:别依赖直觉,追索每种边界条件,并编写测试4.忽视安全5.重复:看到重复代码,都代表遗漏了抽象6.在错误的抽象层级上的代码:创建分离较高层级一般性概念(抽象类)与较低层级细节概念(派生类)的抽象模型7.基类依赖于派生类:基类对派生类应该一无所知8.信息过多:设计良好的模块有着非常小的接口,限制类或模块中暴露的接口数量,类中的方法越少越好,隐藏你的数据,隐藏你的工具函数,隐藏常量和临时变量9.死代码:删除掉10.垂直分隔:变量和函数应该在靠近被使用的地方定义,垂直距离要短11.前后不一致:从一而终,可以追溯到最小惊异原则,让代码更加易于阅读和修改12.混淆视听:保持源文件整洁,良好地组织,不被搞乱13.人为耦合:不互相依赖的东西不该耦合14.特性依恋:类的方法只应对其所属类中的变量和函数感兴趣,不该垂青其他类中的变量和函数15.选择算子参数:使用多个函数,通常优于向单个函数传递某些代码来选择函数行为 16.晦涩的意图:代码要尽可能具有表达力17.位置错误的权责:代码应该放在读者自然而然期待它所有的地方18.不恰当的静态方法:如果的确需要静态函数,确保没机会打算让它有多态行为19.使用解释性变量:让程序可读的最有力方法之一就是将计算过程打散成用有意义的单词命名的变量中放置的中间值20.函数名称应该表达其行为21.理解算法:在你认为自己完成某个函数之前,确认自己理解了它是怎么工作的,你必须知道解决方案是正确的22.把逻辑依赖改为物理依赖:依赖模块不应对被依赖者模块有假定,它应当明确地询问后者全部信息23.用多态替代if/Else或Switch/Case,“单个switch”规则:对于给定的选择类型,不应有多于一个switch语句24.遵循标准约定,遵循基于通用行业规范的一套编码标准25.用命名常量替代魔术数,在代码中出现原始形态数字通常来说是坏现象,有些常量与非常具有自我解释能力的代码协同工作时,就不必总是需要命名常量来隐藏了。“魔术数”泛指任何不能自我描述的符号26.准确,在代码中做决定时,确认自己足够准确,明确自己为何要这么做,如果遇到异常情况如何处理27.结构甚于约定28.封装条件,如果没有if或while语句的上下文,布尔逻辑就难以理解,应该把解释了条件意图的函数抽离出来29.避免否定性条件,尽可能将条件表示为肯定形式30.函数只该做一件事31.掩蔽时序耦合,排列函数参数,好让它们被调用的次序显而易见32.别随意,构建代码需要理由,而且理由应与代码结构相契合33.封装边界条件,把处理边界条件的代码集中到一处,不要散落于代码中34.函数应该只在一个抽象层级上,函数中的语句应该在同一抽象层级上,该层级应该是函数名所示操作的下一层35.在较高层级放置可配置数据,如果你有个已知并该在较高抽象层级的默认常量或配置值,不要将它埋藏到较低层级的函数中36.避免传递浏览,让直接协作者提供所需的全部服务,不必逛遍系统的对象全图,搜寻我们要调用的方法E.Java1.通过使用通配符避免过长的导入清单2.不要继承常量,应该直接导入常量类3.常量 vs. 枚举,放心使用枚举F.名称1.采用描述性名称,事物的意义随着软件的演化而变化,要经常性地重新估量名称是否恰当2.名称应与抽象层级相符,不要取沟通实现的名称;取反映类或函数抽象层级的名称3.尽可能使用标准命名法4.无歧义的名称,选用不会混淆函数或变量意义的名称5.为较大作用范围选用较长名称6.避免编码,不要用匈牙利命名法污染你的名称7.名称应该说明副作用G.测试1.测试不足,一套测试应该测到所有可能失败的东西2.使用覆盖率工具,能汇报你测试策略中的缺口3.别略过小测试4.被忽略的测试就是对不确定事物的疑问5.测试边界条件6.全面测试相近的缺陷7.测试失败的模式有启发性,完整的测试用例,按合理的顺序排列,能暴露出模式8.测试覆盖率的模式有启发性9.测试应该快速

我要回帖

更多关于 代码源文件怎么保存 的文章