This commit is contained in:
louzefeng
2024-07-11 05:50:32 +00:00
parent bf99793fd0
commit d3828a7aee
6071 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
<audio id="audio" title="01 | 为什么说每个程序员都要尽早地学习并掌握设计模式相关知识?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/02/b9/02a11c60b160fc48a0363f65ff4f3cb9.mp3"></audio>
我相信很多程序员都已经意识到基础知识的重要性觉得要夯实基础才能走得更远但同时对于如何将基础知识转化成开发“生产力”仍然有些疑惑。所以你可能看了很多基础的书籍比如操作系统、组成原理、编译原理等但还是觉得很迷茫觉得在开发中用不上起码在平时的CRUD业务开发中用不上。实际上这些基础的知识确实很难直接转化成开发“生产力”。但是它能潜移默化地、间接地提高你对技术的理解。
不过,我觉得,设计模式和操作系统、组成原理、编译原理等这些基础学科是不一样的。它虽然也算是一门基础知识,但是它和数据结构、算法更像是一道儿的,相比那些更加基础的学科,设计模式能更直接地提高你的开发能力。我在开篇词里也说了,如果说数据结构和算法是教你如何写出高效代码,那设计模式讲的是如何写出可扩展、可读、可维护的高质量代码,所以,它们跟平时的编码会有直接的关系,也会直接影响到你的开发能力。
不过,你可能还是会觉得设计模式是把屠龙刀,看起来很厉害,但平时的开发根本用不上。基于这种观点,接下来,我们就具体地聊一聊,我们为什么要学习设计模式?
## 1. 应对面试中的设计模式相关问题
学习设计模式和算法一样,最功利、最直接的目的,可能就是应对面试了。
不管你是前端工程师、后端工程师还是全栈工程师在求职面试中设计模式问题是被问得频率比较高的一类问题。特别是一些像BAT、TMD这样的大公司比较重视候选人的基本功经常会拿算法、设计模式之类的问题来考察候选人。
所以,我在求职面试的时候,都会提前准备、温习一遍设计模式。尽管并不是每次面试都会被问到,但一旦被问到,如果回答得不好,就是一个败笔,这场面试基本上也就凉凉了。所以,为了保证万无一失,摆脱一旦被问到答不出来的窘境,对于设计模式这种大概率被问到的问题,我都会未雨绸缪,提前准备一下。
当然,我并不是临时抱佛脚。我平时就比较重视设计模式相关知识的积累,所以底子比较好,只需要在每次面试前花很短的时间,重新温习一下,便可以自信满满地去面试,而不是心里老是担心被问到,影响正常的面试发挥。
所以,如果你也不想让设计模式相关问题成为你面试中的短板,那跟着我把专栏中的知识点都搞清楚,以后面试再遇到设计模式相关的问题,就不会惧怕了,甚至还会成为你面试中的亮点。
## 2. 告别写被人吐槽的烂代码
我们经常说“Talk is cheapshow me the code。”实际上代码能力是一个程序员最基础的能力是基本功是展示一个程序员基础素养的最直接的衡量标准。你写的代码实际上就是你名片。
尽管我已经工作近十年但我一直没有脱离编码一线现在每天也都在坚持写代码、review指导同事写代码、重构遗留系统的烂代码。这些年的工作经历中我见过太多的烂代码比如命名不规范、类设计不合理、分层不清晰、没有模块化概念、代码结构混乱、高度耦合等等。这样的代码维护起来非常费劲添加或者修改一个功能常常会牵一发而动全身让你无从下手恨不得将全部的代码删掉重写
当然,在这些年的工作经历中,我也看到过很多让我眼前一亮的代码。每当我看到这样的好代码,都会立刻对作者产生无比的好感和认可。且不管这个人处在公司的何种级别,从代码就能看出,他是一个基础扎实的高潜员工,值得培养,前途无量!因此,代码写得好,能让你在团队中脱颖而出。
所以,我的专栏,不仅仅只是讲解设计模式,更加重要的是,我会通过实战例子,手把手教你如何避免刚刚提到的代码问题,告别被人诟病的烂代码,写出令人称道的好代码,成为团队中的代码标杆!而且,写出一份漂亮的代码,你自己也会很有成就感。
## 3. 提高复杂代码的设计和开发能力
大部分工程师比较熟悉的都是编程语言、工具、框架这些东西,因为每天的工作就是在框架里根据业务需求,填充代码。实际上,我刚工作的时候,也是做这类事情。相对来说,这样的工作并不需要你具备很强的代码设计能力,只要单纯地能理解业务,翻译成代码就可以了。
但是有一天我的leader让我开发一个跟业务无关的比较通用的功能模块面对这样稍微复杂的代码设计和开发我就发现我有点力不从心不知从何下手了。因为我知道只是完成功能、代码能用可能并不复杂但是要想写出易扩展、易用、易维护的代码并不容易。
如何分层、分模块应该怎么划分类每个类应该具有哪些属性、方法怎么设计类之间的交互该用继承还是组合该使用接口还是抽象类怎样做到解耦、高内聚低耦合该用单例模式还是静态方法用工厂模式创建对象还是直接new出来如何避免引入设计模式提高扩展性的同时带来的降低可读性问题……各种问题一下子挤到了我面前。
而我当时并没有对设计模式相关的知识(包括设计模式、设计原则、面向对象设计思想等)有太多的了解和积累,所以一时间搞得我手足无措。好在因此我意识到了这方面知识的重要性,所以在之后很多年的开发中,我都一直刻意锻炼、积累这方面的能力。面对复杂代码、功能、系统的设计和开发,我也越来越得心应手,游刃有余。写出高质量代码已经成为了我的习惯,不经意间写出来的代码,都能作为同事学习、临摹的范例,这也成为了我职场中最引以为豪的亮点之一。
## 4. 让读源码、学框架事半功倍
对于一个有追求的程序员来说,对技术的积累,既要有广度,也要有深度。很多技术人早早就意识到了这一点,所以在学习框架、中间件的时候,都会抽空去研究研究原理,读一读源码,希望能在深度上有所积累,而不只是略知皮毛,会用而已。
从我的经验和同事的反馈来看,有些人看源码的时候,经常会遇到看不懂、看不下去的问题。不知道你有没有遇到过这种情况?实际上,这个问题的原因很简单,那就是你积累的基本功还不够,你的能力还不足以看懂这些代码。为什么我会这么说呢?
优秀的开源项目、框架、中间件,代码量、类的个数都会比较多,类结构、类之间的关系极其复杂,常常调用来调用去。所以,为了保证代码的扩展性、灵活性、可维护性等,代码中会使用到很多设计模式、设计原则或者设计思想。如果你不懂这些设计模式、原则、思想,在看代码的时候,你可能就会琢磨不透作者的设计思路,对于一些很明显的设计思路,你可能要花费很多时间才能参悟。相反,如果你对设计模式、原则、思想非常了解,一眼就能参透作者的设计思路、设计初衷,很快就可以把脑容量释放出来,重点思考其他问题,代码读起来就会变得轻松了。
实际上除了看不懂、看不下去的问题还有一个隐藏的问题你可能自己都发现不了那就是你自己觉得看懂了实际上里面的精髓你并没有get到多少因为优秀的开源项目、框架、中间件就像一个集各种高精尖技术在一起的战斗机。如果你想剖析它的原理、学习它的技术而你没有积累深厚的基本功就算把这台战斗机摆在你面前你也不能完全参透它的精髓只是了解个皮毛看个热闹而已。
因此,学好设计模式相关的知识,不仅能让你更轻松地读懂开源项目,还能更深入地参透里面的技术精髓,做到事半功倍。
## 5. 为你的职场发展做铺垫
普通的、低级别的开发工程师只需要把框架、开发工具、编程语言用熟练再做几个项目练练手基本上就能应付平时的开发工作了。但是如果你不想一辈子做一个低级的码农想成长为技术专家、大牛、技术leader希望在职场有更高的成就、更好的发展那就要重视基本功的训练、基础知识的积累。
你去看大牛写的代码,或者优秀的开源项目,代码写得都非常的优美,质量都很高。如果你只是框架用得很溜,架构聊得头头是道,但写出来的代码很烂,让人一眼就能看出很多不合理的、可以改进的地方,那你永远都成不了别人心目中的“技术大牛”。
再者在技术这条职场道路上当成长到一定阶段之后你势必要承担一些指导培养初级员工、新人以及code review的工作。这个时候如果你自己都对“什么是好的代码如何写出好的代码”不了解那又该如何指导别人如何让人家信服呢
还有如果你是一个技术leader负责一个项目整体的开发工作你就需要为开发进度、开发效率和项目质量负责。你也不希望团队堆砌垃圾代码让整个项目无法维护添加、修改一个功能都要费老大劲最终拉低整个团队的开发效率吧
除此之外代码质量低还会导致线上bug频发排查困难。整个团队都陷在成天修改无意义的低级bug、在烂代码中添补丁的事情中。而一个设计良好、易维护的系统可以解放我们的时间让我们做些更加有意义、更能提高自己和团队能力的事情。
最后当你成为leader、或者团队中的资深工程师、技术专家之后你势必要负责一部分团队的招聘工作。这个时候如果你要考察候选人的设计能力、代码能力那设计模式相关的问题便是一个很好的考察点。
不过我也了解到很多面试官实际上对设计模式也并不是很了解只能拿一些简单的单例模式、工厂模式来考察候选人而且所出的题目往往都脱离实践比如如何设计一个餐厅系统、停车场系统、售票系统等。这些题目都是网上万年不变的老题目几乎考察不出候选人的能力。在我的专栏中有200多个真实项目开发中的设计模式相关问题你跟着看下来足以让你成为设计模式方面的大牛再来面试候选人的时候就不用因为题目老套、脱离实践而尴尬了
## 重点回顾
今天,我们讲了为什么要学习设计模式相关的知识,总结一下的话,主要有这样五点:应对面试中的设计模式相关问题;告别写被人吐槽的烂代码;提高复杂代码的设计和开发能力;让读源码、学框架事半功倍;为你的职场发展做铺垫。
投资要趁早,这样我们才能尽早享受复利。同样,有些能力,要早点锻炼;有些东西,要早点知道;有些书,要早点读。这样在你后面的生活、工作、学习中,才能一直都发挥作用。不要等到好多年后,看到了,才恍然大悟,后悔没有早点去学、去看。
设计模式作为一门与编码、开发有着直接关系的基础知识,是你现在就要开始学习的。早点去学习,以后的项目就都可以拿来锻炼,每写一行代码都是对内功的利用和加深,是可以受益一整个职业生涯的事情。
## 课堂讨论
今天课堂讨论的话题有两个:
1. 聊一聊你对设计模式相关知识的重要性的看法;
1. 在你过往的项目开发中,有没有用过某种设计模式?是在什么场景下应用的?解决了什么问题?
欢迎在留言区发表你的观点,积极参与讨论。你也可以把这篇文章分享给你的朋友,邀请他一起学习。

View File

@@ -0,0 +1,131 @@
<audio id="audio" title="02 | 从哪些维度评判代码质量的好坏?如何具备写出高质量代码的能力?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/2c/1d/2c0052a8c67889b258a6b9c62edb151d.mp3"></audio>
在我的工作经历中,每当同事评论起项目代码质量的时候,听到的最多的评语就是:“代码写得很烂”或者“代码写得很好”。用“好”“烂”这样的字眼来描述,非常地笼统。当我具体问到底如何烂、如何好的时候,尽管大部分同事都能简单地罗列上几个点,但往往都不够全面、非常零碎,也切不中要害。
当然,也有一些工程师对如何评价代码质量有所认识,比如,好代码是易扩展、易读、简单、易维护的等等,但他们对于这些评价的理解往往只停留在表面概念上,对于诸多更深入的问题,比如,“怎么才算可读性好?什么样的代码才算易扩展、易维护?可读、可扩展与可维护之间有什么关系?可维护中‘维护’两字该如何理解?”等等,并没有太清晰的认识。
对于程序员来说,辨别代码写得“好”还是“烂”,是一个非常重要的能力。这也是我们写出好代码的前提。毕竟,如果我们连什么是好代码、什么是烂代码,都分辨不清,又谈何写出好代码呢?
所以,今天我们就聊一聊关于代码质量评判的相关问题,希望你在学完今天的内容之后,对代码质量的评判有个更加清晰、更加透彻的认识和理解。
## 如何评价代码质量的高低?
实际上,咱们平时嘴中常说的“好”和“烂”,是对代码质量的一种描述。“好”笼统地表示代码质量高,“烂”笼统地表示代码质量低。对于代码质量的描述,除了“好”“烂”这样比较简单粗暴的描述方式之外,我们也经常会听到很多其他的描述方式。这些描述方法语义更丰富、更专业、更细化。我搜集整理了一下,罗列在了下面。这些几乎涵盖我们所能听到的描述代码质量的所有常用词汇,你可以看一看。
>
灵活性flexibility、可扩展性extensibility、可维护性maintainability、可读性readability、可理解性understandability、易修改性changeability、可复用reusability、可测试性testability、模块化modularity、高内聚低耦合high cohesion loose coupling、高效high effciency、高性能high performance、安全性security、兼容性compatibility、易用性usability、整洁clean、清晰clarity、简单simple、直接straightforward、少即是多less code is more、文档详尽well-documented、分层清晰well-layered、正确性correctness、bug free、健壮性robustness、鲁棒性robustness、可用性reliability、可伸缩性scalability、稳定性stability、优雅elegant、好good、坏bad……
看到如此多的描述词,你可能要问了,我们到底该用哪些词来描述一段代码的质量呢?
实际上,我们很难通过其中的某个或者某几个词汇来全面地评价代码质量。因为这些词汇都是从不同维度来说的。这就好比,对于一个人的评价,我们需要综合各个方面来给出,比如性格、相貌、能力、财富等等。代码质量高低也是一个综合各种因素得到的结论。我们并不能通过单一的维度去评价一段代码写的好坏。比如,即使一段代码的可扩展性很好,但可读性很差,那我们也不能说这段代码质量高。
除此之外不同的评价维度也并不是完全独立的有些是具有包含关系、重叠关系或者可以互相影响的。比如代码的可读性好、可扩展性好就意味着代码的可维护性好。而且各种评价维度也不是非黑即白的。比如我们不能简单地将代码分为可读与不可读。如果用数字来量化代码的可读性的话它应该是一个连续的区间值而非0、1这样的离散值。
不过,我们真的可以客观地量化一段代码质量的高低吗?答案是否定的。对一段代码的质量评价,常常有很强的主观性。比如,怎么样的代码才算可读性好,每个人的评判标准都不大一样。这就好比我们去评价一本小说写得是否精彩,本身就是一个很难量化的、非常主观的事情。
正是因为代码质量评价的主观性,使得这种主观评价的准确度,跟工程师自身经验有极大的关系。越是有经验的工程师,给出的评价也就越准确。相反,资历比较浅的工程师就常常会觉得,没有一个可执行的客观的评价标准作为参考,很难准确地判断一段代码写得好与坏。有的时候,自己觉得代码写得已经够好了,但实际上并不是。所以,这也导致如果没有人指导的话,自己一个人闷头写代码,即便写再多的代码,代码能力也可能一直没有太大提高。
## 最常用的评价标准有哪几个?
仔细看前面罗列的所有代码质量评价标准,你会发现,有些词语过于笼统、抽象,比较偏向对于整体的描述,比如优雅、好、坏、整洁、清晰等;有些过于细节、偏重方法论,比如模块化、高内聚低耦合、文档详尽、分层清晰等;有些可能并不仅仅局限于编码,跟架构设计等也有关系,比如可伸缩性、可用性、稳定性等。
为了做到有的放矢、有重点地学习,我挑选了其中几个最常用的、最重要的评价标准,来详细讲解,其中就包括:可维护性、可读性、可扩展性、灵活性、简洁性(简单、复杂)、可复用性、可测试性。接下来,我们逐一讲解一下。
### 1.可维护性maintainability
我们首先来看,什么是代码的“可维护性”?所谓的“维护代码”到底包含哪些具体工作?
落实到编码开发所谓的“维护”无外乎就是修改bug、修改老的代码、添加新的代码之类的工作。所谓“代码易维护”就是指在不破坏原有代码设计、不引入新的bug的情况下能够快速地修改或者添加代码。所谓“代码不易维护”就是指修改或者添加代码需要冒着极大的引入新bug的风险并且需要花费很长的时间才能完成。
我们知道对于一个项目来说维护代码的时间远远大于编写代码的时间。工程师大部分的时间可能都是花在修修bug、改改老的功能逻辑、添加一些新的功能逻辑之类的工作上。所以代码的可维护性就显得格外重要。
维护、易维护、不易维护这三个概念不难理解。不过,对于实际的软件开发来说,更重要的是搞清楚,如何来判断代码可维护性的好坏。
实际上,可维护性也是一个很难量化、偏向对代码整体的评价标准,它有点类似之前提到的“好”“坏”“优雅”之类的笼统评价。代码的可维护性是由很多因素协同作用的结果。代码的可读性好、简洁、可扩展性好,就会使得代码易维护;相反,就会使得代码不易维护。更细化地讲,如果代码分层清晰、模块化好、高内聚低耦合、遵从基于接口而非实现编程的设计原则等等,那就可能意味着代码易维护。除此之外,代码的易维护性还跟项目代码量的多少、业务的复杂程度、利用到的技术的复杂程度、文档是否全面、团队成员的开发水平等诸多因素有关。
所以从正面去分析一个代码是否易维护稍微有点难度。不过我们可以从侧面上给出一个比较主观但又比较准确的感受。如果bug容易修复修改、添加功能能够轻松完成那我们就可以主观地认为代码对我们来说易维护。相反如果修改一个bug修改、添加一个功能需要花费很长的时间那我们就可以主观地认为代码对我们来说不易维护。
你可能会说这样的评价方式也太主观了吧没错是否易维护本来就是针对维护的人来说的。不同水平的人对于同一份代码的维护能力并不是相同的。对于同样一个系统熟悉它的资深工程师会觉得代码的可维护性还不错而一些新人因为不熟悉代码修改bug、修改添加代码要花费很长的时间就有可能会觉得代码的可维护性不那么好。这实际上也印证了我们之前的观点代码质量的评价有很强的主观性。
### 2.可读性readability
软件设计大师Martin Fowler曾经说过“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.”翻译成中文就是“任何傻瓜都会编写计算机能理解的代码。好的程序员能够编写人能够理解的代码。”Google内部甚至专门有个认证就叫作Readability。只有拿到这个认证的工程师才有资格在code review的时候批准别人提交代码。可见代码的可读性有多重要毕竟代码被阅读的次数远远超过被编写和执行的次数。
我个人认为代码的可读性应该是评价代码质量最重要的指标之一。我们在编写代码的时候时刻要考虑到代码是否易读、易理解。除此之外代码的可读性在非常大程度上会影响代码的可维护性。毕竟不管是修改bug还是修改添加功能代码我们首先要做的事情就是读懂代码。代码读不大懂就很有可能因为考虑不周全而引入新的bug。
既然可读性如此重要,那我们又该如何评价一段代码的可读性呢?
我们需要看代码是否符合编码规范、命名是否达意、注释是否详尽、函数是否长短合适、模块划分是否清晰、是否符合高内聚低耦合等等。你应该也能感觉到,从正面上,我们很难给出一个覆盖所有评价指标的列表。这也是我们无法量化可读性的原因。
实际上code review是一个很好的测验代码可读性的手段。如果你的同事可以轻松地读懂你写的代码那说明你的代码可读性很好如果同事在读你的代码时有很多疑问那就说明你的代码可读性有待提高了。
### 3.可扩展性extensibility
可扩展性也是一个评价代码质量非常重要的标准。它表示我们的代码应对未来需求变化的能力。跟可读性一样,代码是否易扩展也很大程度上决定代码是否易维护。那到底什么是代码的可扩展性呢?
代码的可扩展性表示,我们在不修改或少量修改原有代码的情况下,通过扩展的方式添加新的功能代码。说直白点就是,代码预留了一些功能扩展点,你可以把新功能代码,直接插到扩展点上,而不需要因为要添加一个功能而大动干戈,改动大量的原始代码。
关于代码的扩展性,在后面讲到“对修改关闭,对扩展开放”这条设计原则的时候,我会来详细讲解,今天我们只需要知道,代码的可扩展性是评价代码质量非常重要的标准就可以了。
### 4.灵活性flexibility
灵活性也是描述代码质量的一个常用词汇。比如我们经常会听到这样的描述:“代码写得很灵活”。那这里的“灵活”该如何理解呢?
尽管有很多人用这个词汇来描述代码的质量。但实际上,灵活性是一个挺抽象的评价标准,要给灵活性下个定义也是挺难的。不过,我们可以想一下,什么情况下我们才会说代码写得好灵活呢?我这里罗列了几个场景,希望能引发你自己对什么是灵活性的思考。
- 当我们添加一个新的功能代码的时候,原有的代码已经预留好了扩展点,我们不需要修改原有的代码,只要在扩展点上添加新的代码即可。这个时候,我们除了可以说代码易扩展,还可以说代码写得好灵活。
- 当我们要实现一个功能的时候,发现原有代码中,已经抽象出了很多底层可以复用的模块、类等代码,我们可以拿来直接使用。这个时候,我们除了可以说代码易复用之外,还可以说代码写得好灵活。
- 当我们使用某组接口的时候,如果这组接口可以应对各种使用场景,满足各种不同的需求,我们除了可以说接口易用之外,还可以说这个接口设计得好灵活或者代码写得好灵活。
从刚刚举的场景来看,如果一段代码易扩展、易复用或者易用,我们都可以称这段代码写得比较灵活。所以,灵活这个词的含义非常宽泛,很多场景下都可以使用。
### 5.简洁性simplicity
有一条非常著名的设计原则你一定听过那就是KISS原则“Keep It SimpleStupid”。这个原则说的意思就是尽量保持代码简单。代码简单、逻辑清晰也就意味着易读、易维护。我们在编写代码的时候往往也会把简单、清晰放到首位。
不过,很多编程经验不足的程序员会觉得,简单的代码没有技术含量,喜欢在项目中引入一些复杂的设计模式,觉得这样才能体现自己的技术水平。实际上,**思从深而行从简,真正的高手能云淡风轻地用最简单的方法解决最复杂的问题。这也是一个编程老手跟编程新手的本质区别之一。**
除此之外虽然我们都能认识到代码要尽量写得简洁符合KISS原则但怎么样的代码才算足够简洁不是每个人都能很准确地判断出来这一点。所以在后面的章节中当我们讲到KISS原则的时候我会通过具体的代码实例详细给你解释“为什么KISS原则看似非常简单、好理解但实际上用好并不容易”。今天我们就暂且不展开详细讲解了。
### 6.可复用性reusability
代码的可复用性可以简单地理解为,尽量减少重复代码的编写,复用已有的代码。在后面的很多章节中,我们都会经常提到“可复用性”这一代码评价标准。
比如,当讲到面向对象特性的时候,我们会讲到继承、多态存在的目的之一,就是为了提高代码的可复用性;当讲到设计原则的时候,我们会讲到单一职责原则也跟代码的可复用性相关;当讲到重构技巧的时候,我们会讲到解耦、高内聚、模块化等都能提高代码的可复用性。可见,可复用性也是一个非常重要的代码评价标准,是很多设计原则、思想、模式等所要达到的最终效果。
实际上代码可复用性跟DRYDont Repeat Yourself这条设计原则的关系挺紧密的所以在后面的章节中当我们讲到DRY设计原则的时候我还会讲更多代码复用相关的知识比如“有哪些编程方法可以提高代码的复用性”等。
### 7.可测试性testability
相对于前面六个评价标准,代码的可测试性是一个相对较少被提及,但又非常重要的代码质量评价标准。代码可测试性的好坏,能从侧面上非常准确地反应代码质量的好坏。代码的可测试性差,比较难写单元测试,那基本上就能说明代码设计得有问题。关于代码的可测试性,我们在重构那一部分,会花两节课的时间来详细讲解。现在,你暂时只需要知道,代码的可测试性非常重要就可以了。
## 如何才能写出高质量的代码?
我相信每个工程师都想写出高质量的代码,不想一直写没有成长、被人吐槽的烂代码。那如何才能写出高质量的代码呢?针对什么是高质量的代码,我们刚刚讲到了七个最常用、最重要的评价指标。所以,问如何写出高质量的代码,也就等同于在问,如何写出易维护、易读、易扩展、灵活、简洁、可复用、可测试的代码。
要写出满足这些评价标准的高质量代码,我们需要掌握一些更加细化、更加能落地的编程方法论,包括面向对象设计思想、设计原则、设计模式、编码规范、重构技巧等。而所有这些编程方法论的最终目的都是为了编写出高质量的代码。
比如面向对象中的继承、多态能让我们写出可复用的代码编码规范能让我们写出可读性好的代码设计原则中的单一职责、DRY、基于接口而非实现、里式替换原则等可以让我们写出可复用、灵活、可读性好、易扩展、易维护的代码设计模式可以让我们写出易扩展的代码持续重构可以时刻保持代码的可维护性等等。具体这些编程方法论是如何提高代码的可维护性、可读性、可扩展性等等的呢我们在后面的课程中慢慢来学习。
## 重点回顾
今天的内容到此就讲完了。我们来一起回顾一下,你需要重点掌握的几个知识点。
**1.如何评价代码质量的高低?**
代码质量的评价有很强的主观性,描述代码质量的词汇也有很多,比如可读性、可维护性、灵活、优雅、简洁等,这些词汇是从不同的维度去评价代码质量的。它们之间有互相作用,并不是独立的,比如,代码的可读性好、可扩展性好就意味着代码的可维护性好。代码质量高低是一个综合各种因素得到的结论。我们并不能通过单一的维度去评价一段代码的好坏。
**2.最常用的评价标准有哪几个?**
最常用到几个评判代码质量的标准是:可维护性、可读性、可扩展性、灵活性、简洁性、可复用性、可测试性。其中,可维护性、可读性、可扩展性又是提到最多的、最重要的三个评价标准。
**3.如何才能写出高质量的代码?**
要写出高质量代码,我们就需要掌握一些更加细化、更加能落地的编程方法论,这就包含面向对象设计思想、设计原则、设计模式、编码规范、重构技巧等等,这也是我们后面课程学习的重点。
## 课堂讨论
除了我今天提到的这些,你觉得还有哪些其他的代码评价标准非常重要?聊一聊你心目中的好代码是什么样子的?
欢迎在留言区发表你的观点,积极参与讨论。你也可以把这篇文章分享给你的朋友,邀请他一起学习。

View File

@@ -0,0 +1,113 @@
<audio id="audio" title="03 | 面向对象、设计原则、设计模式、编程规范、重构,这五者有何关系?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/06/cb/06c5e94a9a6e4b020053f559e4da0dcb.mp3"></audio>
在上一节课中,我们讲到,要具备编写高质量代码的能力,你需要学习一些编程方法论,其中就包含面向对象(我们可以把它看成一种设计思想)、设计原则、设计模式、编程规范、重构技巧等。而我们整个专栏的内容也是围绕着这几块展开讲解的。所以,今天我就先来简单介绍一下这几个概念,并且说一说它们之间的联系。
今天的内容相当于专栏的一个教学大纲,或者说学习框架。它能让你对整个专栏所涉及的知识点,有一个全局性的了解,能帮你将后面零散的知识更系统地组织在大脑里。
话不多说我们就一块来看一下接下来的这8个月我们到底要学习哪些内容吧
## 面向对象
现在,主流的编程范式或者是编程风格有三种,它们分别是面向过程、面向对象和函数式编程。面向对象这种编程风格又是这其中最主流的。现在比较流行的编程语言大部分都是面向对象编程语言。大部分项目也都是基于面向对象编程风格开发的。面向对象编程因为其具有丰富的特性(封装、抽象、继承、多态),可以实现很多复杂的设计思路,是很多设计原则、设计模式编码实现的基础。
所以在专栏的最开始我们会详细地讲解面向对象编程的相关的知识为学习后面的内容做铺垫。对于这部分内容你需要掌握下面这7个大的知识点。
- 面向对象的四大特性:封装、抽象、继承、多态
- 面向对象编程与面向过程编程的区别和联系
- 面向对象分析、面向对象设计、面向对象编程
- 接口和抽象类的区别以及各自的应用场景
- 基于接口而非实现编程的设计思想
- 多用组合少用继承的设计思想
- 面向过程的贫血模型和面向对象的充血模型
## 设计原则
设计原则是指导我们代码设计的一些经验总结。设计原则这块儿的知识有一个非常大的特点,那就是这些原则听起来都比较抽象,定义描述都比较模糊,不同的人会有不同的解读。所以,如果单纯地去记忆定义,对于编程、设计能力的提高,意义并不大。对于每一种设计原则,我们需要掌握它的设计初衷,能解决哪些编程问题,有哪些应用场景。只有这样,我们才能在项目中灵活恰当地应用这些原则。
对于这一部分内容,你需要透彻理解并且掌握,如何应用下面这样几个常用的设计原则。
- SOLID原则-SRP单一职责原则
- SOLID原则-OCP开闭原则
- SOLID原则-LSP里式替换原则
- SOLID原则-ISP接口隔离原则
- SOLID原则-DIP依赖倒置原则
- DRY原则、KISS原则、YAGNI原则、LOD法则
## 设计模式
设计模式是针对软件开发中经常遇到的一些设计问题,总结出来的一套解决方案或者设计思路。大部分设计模式要解决的都是代码的可扩展性问题。设计模式相对于设计原则来说,没有那么抽象,而且大部分都不难理解,代码实现也并不复杂。这一块的学习难点是了解它们都能解决哪些问题,掌握典型的应用场景,并且懂得不过度应用。
经典的设计模式有23种。随着编程语言的演进一些设计模式比如Singleton也随之过时甚至成了反模式一些则被内置在编程语言中比如Iterator另外还有一些新的模式诞生比如Monostate
在专栏中我们会重点讲解23种经典的设计模式。它们又可以分为三大类创建型、结构型、行为型。对于这23种设计模式的学习我们要有侧重点因为有些模式是比较常用的有些模式是很少被用到的。对于常用的设计模式我们要花多点时间理解掌握。对于不常用的设计模式我们只需要稍微了解即可。
我按照类型和是否常用,对专栏中讲到的这些设计模式,进行了简单的分类,具体如下所示。
### 1.创建型
常用的有:单例模式、工厂模式(工厂方法和抽象工厂)、建造者模式。
不常用的有:原型模式。
### 2.结构型
常用的有:代理模式、桥接模式、装饰者模式、适配器模式。
不常用的有:门面模式、组合模式、享元模式。
### 3.行为型
常用的有:观察者模式、模板模式、策略模式、职责链模式、迭代器模式、状态模式。
不常用的有:访问者模式、备忘录模式、命令模式、解释器模式、中介模式。
## 编程规范
编程规范主要解决的是代码的可读性问题。编码规范相对于设计原则、设计模式,更加具体、更加偏重代码细节。即便你可能对设计原则不熟悉、对设计模式不了解,但你最起码要掌握基本的编码规范,比如,如何给变量、类、函数命名,如何写代码注释,函数不宜过长、参数不能过多等等。
对于编码规范考虑到很多书籍已经讲得很好了比如《重构》《代码大全》《代码整洁之道》等。而且每条编码规范都非常简单、非常明确比较偏向于记忆你只要照着来做可以。它不像设计原则需要融入很多个人的理解和思考。所以在这个专栏中我并没有花太多的篇幅来讲解所有的编码规范而是总结了我认为的最能改善代码质量的20条规范。如果你暂时没有时间去看那些经典的书籍看我这些就够了。
除此之外,专栏并没有将编码规范单独作为一个模块来讲解,而是跟重构放到了一起。之所以这样做,那是因为我把重构分为大重构和小重构两种类型,而小重构利用的知识基本上就是编码规范。
除了编码规范,我们还会介绍一些代码的坏味道,让你知道什么样的代码是不符合规范的,应该如何优化。参照编码规范,你可以写出可读性好的代码;参照代码的坏味道,你可以找出代码存在的可读性问题。
## 代码重构
在软件开发中,只要软件在不停地迭代,就没有一劳永逸的设计。随着需求的变化,代码的不停堆砌,原有的设计必定会存在这样那样的问题。针对这些问题,我们就需要进行代码重构。重构是软件开发中非常重要的一个环节。持续重构是保持代码质量不下降的有效手段,能有效避免代码腐化到无可救药的地步。
而重构的工具就是我们前面罗列的那些面向对象设计思想、设计原则、设计模式、编码规范。实际上,设计思想、设计原则、设计模式一个最重要的应用场景就是在重构的时候。我们前面讲过,虽然使用设计模式可以提高代码的可扩展性,但过度不恰当地使用,也会增加代码的复杂度,影响代码的可读性。在开发初期,除非特别必须,我们一定不要过度设计,应用复杂的设计模式。而是当代码出现问题的时候,我们再针对问题,应用原则和模式进行重构。这样就能有效避免前期的过度设计。
对于重构这部分内容,你需要掌握以下几个知识点:
- 重构的目的why、对象what、时机when、方法how
- 保证重构不出错的技术手段:单元测试和代码的可测试性;
- 两种不同规模的重构:大重构(大规模高层次)和小重构(小规模低层次)。
希望你学完这部分内容之后,不仅仅是掌握一些重构技巧、套路,更重要的是建立持续重构意识,把重构当作开发的一部分,融入到日常的开发中。
## 五者之间的联系
关于面向对象、设计原则、设计模式、编程规范和代码重构,这五者的关系我们前面稍微提到了一些,我这里再总结梳理一下。
- 面向对象编程因为其具有丰富的特性(封装、抽象、继承、多态),可以实现很多复杂的设计思路,是很多设计原则、设计模式等编码实现的基础。
- 设计原则是指导我们代码设计的一些经验总结,对于某些场景下,是否应该应用某种设计模式,具有指导意义。比如,“开闭原则”是很多设计模式(策略、模板等)的指导原则。
- 设计模式是针对软件开发中经常遇到的一些设计问题,总结出来的一套解决方案或者设计思路。应用设计模式的主要目的是提高代码的可扩展性。从抽象程度上来讲,设计原则比设计模式更抽象。设计模式更加具体、更加可执行。
- 编程规范主要解决的是代码的可读性问题。编码规范相对于设计原则、设计模式,更加具体、更加偏重代码细节、更加能落地。持续的小重构依赖的理论基础主要就是编程规范。
- 重构作为保持代码质量不下降的有效手段,利用的就是面向对象、设计原则、设计模式、编码规范这些理论。
实际上,面向对象、设计原则、设计模式、编程规范、代码重构,这五者都是保持或者提高代码质量的方法论,本质上都是服务于编写高质量代码这一件事的。当我们追本逐源,看清这个本质之后,很多事情怎么做就清楚了,很多选择怎么选也清楚了。比如,在某个场景下,该不该用这个设计模式,那就看能不能提高代码的可扩展性;要不要重构,那就看重代码是否存在可读、可维护问题等。
## 重点回顾
今天的内容到此就讲完了。我画了一张图,总结了专栏中所涉及的知识点。在学习后面的课程的时候,你可以经常翻出来看一下,建立全局意识,不至于迷失在零碎的知识点中。
<img src="https://static001.geekbang.org/resource/image/f3/d3/f3262ef8152517d3b11bfc3f2d2b12d3.png" alt="">
## 课堂讨论
今天课堂讨论的话题有两个。
1. 在今天讲到的内容中,你觉得哪一部分内容对提高代码质量最有效?为什么?除了我罗列的这些内容之外,你还知道哪些可以提高代码质量的方法?
1. 我们知道最经典的设计模式书籍是GoF的《设计模式》它的中文全称是《设计模式可复用面向对象软件的基础》英文全称是“Design Patterns: Elements of Reusable Object-Oriented Software”。为什么它在标题中会特意提到“面向对象”呢
欢迎在留言区写下你的想法,和同学一起交流和分享。如果有收获,也欢迎你把这篇文章分享给你的朋友。