洋蔥

耳不闻人是非,目不视人之短,口不言人之过。

从今天开始,我们正式进入到设计模式的学习。我们知道,经典的设计模式有23种。其中,常用的并不是很多。据我的工作经验来看,常用的可能都不到一半。如果随便抓一个程序员,让他说一说最熟悉的3种设计模式,那其中肯定会包含今天要讲的单例模式。

网上有很多讲解单例模式的文章,但大部分都侧重讲解,如何来实现一个线程安全的单例。我今天也会讲到各种单例的实现方法,但是,这并不是我们专栏学习的重点,我重点还是希望带你搞清楚下面这样几个问题(第一个问题会在今天讲解,后面三个问题放到下一节课中讲解)。

  • 为什么要使用单例?
  • 单例存在哪些问题?
  • 单例与静态类的区别?
  • 有何替代的解决方案?

话不多说,让我们带着这些问题,正式开始今天的学习吧!

阅读全文 »

上一节课中,我们针对版本1存在的问题(特别是Aggregator类、ConsoleReporter和EmailReporter类)进行了重构优化。经过重构之后,代码结构更加清晰、合理、有逻辑性。不过,在细节方面还是存在一些问题,比如ConsoleReporter、EmailReporter类仍然存在代码重复、可测试性差的问题。今天,我们就在版本3中持续重构这部分代码。

除此之外,在版本3中,我们还会继续完善框架的功能和非功能需求。比如,让原始数据的采集和存储异步执行,解决聚合统计在数据量大的情况下会导致内存吃紧问题,以及提高框架的易用性等,让它成为一个能用且好用的框架。

话不多说,让我们正式开始版本3的设计与实现吧!

阅读全文 »

第25节第26节中,我们讲了如何对一个性能计数器框架进行分析、设计与实现,并且实践了之前学过的一些设计原则和设计思想。当时我们提到,小步快跑、逐步迭代是一种非常实用的开发模式。所以,针对这个框架的开发,我们分多个版本来逐步完善。

在第25、26节课中,我们实现了框架的第一个版本,它只包含最基本的一些功能,在设计与实现上还有很多不足。所以,接下来,我会针对这些不足,继续迭代开发两个版本:版本2和版本3,分别对应第39节和第40节的内容。

在版本2中,我们会利用之前学过的重构方法,对版本1的设计与实现进行重构,解决版本1存在的设计问题,让它满足之前学过的设计原则、思想、编程规范。在版本3中,我们再对版本2进行迭代,并且完善框架的功能和非功能需求,让其满足第25节课中罗列的所有需求。

话不多说,让我们正式开始版本2的设计与实现吧!

阅读全文 »

到今天为止,设计原则和思想已经全部讲完了,其中包括:面向对象、设计原则、规范与重构三个模块的内容。除此之外,我们还学习了贯穿整个专栏的代码质量评判标准。专栏的进度已经接近一半,马上就要进入设计模式内容的学习了。在此之前,我先带你一块来总结回顾一下,我们已经学过的所有知识点。

今天的内容比较多,有一万多字,但都是之前学过的,算是一个总结回顾,主要是想带你复习一下,温故而知新。如果你看了之后,感觉都有印象,那就说明学得还不错;如果还能在脑子里形成自己的知识架构,闭上眼睛都能回忆上来,那说明你学得很好;如果能有自己的理解,并且在项目开发中,开始思考代码质量问题,开始用已经学过的设计原则和思想来审视代码,那说明你已经掌握这些内容的精髓。

阅读全文 »

平时进行软件设计开发的时候,我们除了要保证正常情况下的逻辑运行正确之外,还需要编写大量额外的代码,来处理有可能出现的异常情况,以保证代码在任何情况下,都在我们的掌控之内,不会出现非预期的运行结果。程序的bug往往都出现在一些边界条件和异常情况下,所以说,异常处理得好坏直接影响了代码的健壮性。全面、合理地处理各种异常能有效减少代码bug,也是保证代码质量的一个重要手段。

在上一节课中,我们讲解了几种异常情况的处理方式,比如返回错误码、NULL值、空对象、异常对象。针对最常用的异常对象,我们还重点讲解了两种异常类型的应用场景,以及针对函数抛出的异常的三种处理方式:直接吞掉、原封不动地抛出和包裹成新的异常抛出。

除此之外,在上一节课的开头,我们还针对ID生成器的代码,提出了4个有关异常处理的问题。今天,我们就用一节课的时间,结合上一节课讲到的理论知识,来逐一解答一下这几个问题。

话不多说,让我们正式开始今天的内容吧!

阅读全文 »

我们可以把函数的运行结果分为两类。一类是预期的结果,也就是函数在正常情况下输出的结果。一类是非预期的结果,也就是函数在异常(或叫出错)情况下输出的结果。比如,在上一节课中,获取本机名的函数,在正常情况下,函数返回字符串格式的本机名;在异常情况下,获取本机名失败,函数返回UnknownHostException异常对象。

在正常情况下,函数返回数据的类型非常明确,但是,在异常情况下,函数返回的数据类型却非常灵活,有多种选择。除了刚刚提到的类似UnknownHostException这样的异常对象之外,函数在异常情况下还可以返回错误码、NULL值、特殊值(比如-1)、空对象(比如空字符串、空集合)等。

每一种异常返回数据类型,都有各自的特点和适用场景。但有的时候,在异常情况下,函数到底该返回什么样的数据类型,并不那么容易判断。比如,上节课中,在本机名获取失败的时候,ID生成器的generate()函数应该返回什么呢?是异常?空字符?还是NULL值?又或者是其他特殊值(比如null-15293834874-fd3A9KBn,null表示本机名未获取到)呢?

函数是代码的一个非常重要的编写单元,而函数的异常处理,又是我们在编写函数的时候,时刻都要考虑的。所以,今天我们就聊一聊,如何设计函数在异常情况下的返回数据类型。

话不多说,让我们正式开始今天的学习吧!

阅读全文 »

上一节课中,我们结合ID生成器代码讲解了如何发现代码质量问题。虽然ID生成器的需求非常简单,代码行数也不多,但看似非常简单的代码,实际上还是有很多优化的空间。综合评价一下的话,小王的代码也只能算是“能用”、勉强及格。我们大部分人写出来的代码都能达到这个程度。如果想要在团队中脱颖而出,我们就不能只满足于这个60分及格,大家都能做的事情,我们要做得更好才行。

上一节课我们讲了,为什么这份代码只能得60分,这一节课我们再讲一下,如何将60分的代码重构为80分、90分,让它从“能用”变得“好用”。话不多说,让我们正式开始今天的学习吧!

阅读全文 »

在前面几节课中,我们讲了一些跟重构相关的理论知识,比如:持续重构、单元测试、代码的可测试性、解耦、编码规范。用一句话总结一下,重构就是发现代码质量问题,并且对其进行优化的过程。

前面的内容相对还是偏理论。今天,我就借助一个大家都很熟悉的ID生成器代码,给你展示一下重构的大致过程。整个内容分为两节课。这一节课我们讲述如何发现代码质量问题,下一节课讲述如何针对发现的质量问题,对其进行优化,将它从“能用”变得“好用”。

话不多说,让我们正式开始今天的学习吧!

阅读全文 »

上两节课,我们讲了命名和注释、代码风格,今天我们来讲一些比较实用的编程技巧,帮你切实地提高代码可读性。这部分技巧比较琐碎,也很难罗列全面,我仅仅总结了一些我认为比较关键的,更多的技巧需要你在实践中自己慢慢总结、积累。

话不多说,让我们正式开始今天的学习吧!

阅读全文 »

上一节课中我们讲了命名和注释,这一节课我们来讲一下代码风格(Code Style)。说起代码风格,我们其实很难说哪种风格更好。最重要的,也是最需要我们做到的,是在团队、项目中保持风格统一,让代码像同一个人写出来的,整齐划一。这样能减少阅读干扰,提高代码的可读性。这才是我们在实际工作中想要实现的目标。

关于代码风格,我总结了6点我认为最值得关注的,今天跟你一块讨论学习一下。

阅读全文 »
0%