代码整洁之道学习总结
单一职责原则
1、单一职责原则的由来
初学者在编程的时候可能一开始会有这样的经历,使用一个类来实现很多的功能,新添加的甚至不相关的功能都放在一个类中来实现,煮成了一锅大杂烩,往往使得某个类包罗万象,无所不能。可能刚开始实现的功能比较简单,这样做不会引起很大的问题。但是随着之后项目复杂度的提升,各种不相关的代码耦合在一起,一旦有功能的更改或增删,修改的代码很可能导致其他功能不能正常运行,也就是违背了单一职责原则
2、什么是单一职责原则
不要存在多于一个导致类变更的原因。通俗的说,就是一个类只负责一项职责 在软件设计中,秉承着“高内聚,低耦合”的思想,让一个类仅负责一项职责,如果一个类有多于一项的职责,那么就代表这个类耦合性变高了,这些职责耦合在了一起,这是比较脆弱的设计。因为一旦某一项职责发生了改变,需要去更改代码,那么有可能会引起其他职责改变。所谓牵一发而动全身,这显然是我们所不愿意看到的,所以我们会把这个类分拆开来,由两个类来分别维护这两个职责,这样当一个职责发生改变,需要修改时,不会影响到另一个职责。 单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则。
3、为什么要用单一职责原则
说到单一职责原则,很多人都不屑一顾,因为它太简单了,这是常识。在编程中,谁也不希望因为修改了一个功能导致其他的功能发生故障。而避免出现这一问题的解决方法就是遵循单一职责模式。虽然单一模式如此简单,但是也会有违背这一原则的代码存在。为什么会出现这种现象?因为有职责扩散,就是因为某种原因,职责P被分化为粒度更细的职责P1和P2
4、遵循单一职责原则的优点
(1)降低了类的复杂度。一个类只负责一项职责比负责多项职责要简单得多
(2)提高了代码的可读性。一个类简单了,可读性自然就提高了
(3)提高了系统的可维护性。代码的可读性高了,并且修改一项职责对其他职责影响降低了,可维护性自然就提高了
(4)变更引起的风险变低了。单一职责最大的优点就是修改一个功能,对其他功能的影响显著降低
开放-封闭原则
1、什么是开放封闭原则
开放封闭原则是所有面向对象原则的核心。 所谓开放封闭原则,软件实体(类、模块、函数等等)应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的 开放封闭原则主要体现在两个方面: (1)对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况 (2)对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要求对类进行任何修改
2、为什么要用开放-封闭原则
对于程序设计而言,如何设计才能面对需求的改变却可以保持相对的稳定,从而可以使得系统可以在第一个版本的基础上不断的推出新的版本呢?答案是在程序设计的时候使用开放封闭原则。但是在设计的时候,绝对对修改的关闭是不可能的,无论模块是多么的封闭,都存在一些无法对之封闭的变化,既然不可以完全的封闭,设计人员必须对他设计的模块应该对哪种变换的封闭做出选择,他必须猜测出最有可能发生变换的种类,然后构造抽象来隔离那些变化 在我们最初写代码的时候,假设变化不会发生,当变化发生时我们就构造抽象类来隔离变化。当然,不是在什么情况下应对变化都是容易的 开放封闭原则是面向对象的核心所在,遵循这个原则可以带来面向对象所谓的巨大的好处,也就是可维护、可扩展、可复用、灵活性好。然而,对于应用程序中的每个部分都刻意的抽象同样不是一个好主意,拒绝成熟的抽象和抽象一样重要。
3、如何使用开放封闭原则?
实现开放封闭的核心思想就是对抽象编程,而不对具体编程,因为抽象相对稳定。让类依赖于固定的抽象,所以对修改就是封闭的,而通过面向对象的继承和多态机制,可以实现对抽象体的继承,通过覆写其方法来改变故友行为,实现新的扩展方法,所以对于扩展就是开放的 对于违反这一原则的类,必须通过重构来进行改善。常用于实现的设计模式主要有Template Method模式和Strategy模式。而封装变化,是实现这一原则的重要手段,将经常变化的状态封装为一个类 开闭原则无非就是想表达这样一层意思:用抽象构建框架,用实现扩展细节。因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节,我们用从抽象派生的实现类来进行扩展,当软件需要发生变化时,我们只需要根据需求重新派生一个实现类来扩展就可以了。当然前提是我们的抽象要合理,要对需求的变更有前瞻性和预见性才行。
注释
- 好的名字比注释更重要。
- 给常量加注释。
- 在类级别使用全局注释来解释所有部分如何工作。
- 尽量不要注释废弃代码,版本控制代码不会丢失的。
- 注释应申明代码高层次意图,而非明显细节。
- 真正的好注释是你想办法不去写的注释。
有意义的命名
- 尽可能的使用标准命名方法。
- 命名要找更有表现力的词,类名和对象名应该是名词或名词短语,如Customer WikiPage Account、方法名应。该是动词或动词短语,如postPayment deletePage save。
- 避免误导,做有意义的区分、使用读得出来的名称、使用可搜索的名称。
- 名称长短适宜。 (这一点,我认为,如果在迫不得已的情况下,长的比短的更合适)。
变量
- 减少没有价值的临时变量。
- 变量的用途单一,避免多用途。
- 尽可能的减少中间结果。 解释变量除外。
- 变量的作用域尽可能地小,存活时间尽可能地短。
- 临时变量不要远离它的业务代码。
常量
- 使用类或者枚举类来替代类别码
函数
- 短小是函数的第一规则,函数20行封顶最好,不应该写太长。
- 只做一件事,做好这件事。
- 别返回或传入null,或返回特殊对象。
- 函数参数最理想的参数是零(零参数函数),其次是一,尽量避免三个参数及以上的函数。如果函数看来需要三个或以上参数,说明其中一些参数应该封闭为类。从测试角度,参数越多越难测。
- 应该尽量将二元函数转换为一元函数(元:参数个数)。
代码结构
- 代码行长度控制在100-120个字符。
- 关系密切的代码应该互相靠近。(使用空白行进行分割)
- 提早返回可以减少嵌套并让代码整洁。
设计
- 类应该足够短小。
- 减少变量的数量来让代码更有可读性。
- 最好的代码就是没有代码,消除不必要的功能。
- 设计尽可能简单,不可重复代码内容。
关于代码的坏味道
关于这一点,不得不承认,代码很难做到一点坏味道也没有。但我想表达的时,我们需要培养这种嗅觉。 如同一个摄影师,要想出好的作品,首先需要培养审美能力,否则,再好的器材,也出不了好作品。
代码中有哪些常见的坏味道,在此,我只列举一些,有空无空看一眼,以培养自己嗅觉。
- 重复的代码。
- 过长的函数 (函数的代码过长)。
- 过大的类。
- 过长参数列表。
- 发散式变化(如果对程序进行例行维护的时候, 添加新功能的时候, 要同时修改一个类中的多个方法, 那么这就是发散式修改)。
- 霰弹式变化(遇到的每种变化都需要在许多不同类内做出小修改, 即要修改的代码散布于四处, 不但很难找到, 而且容易忘记重要的修改,这种情况就是霰弹式修改)。
- 过度耦合的消息链(这个比较通俗的理解是: a调b,然后a调c, 然后又有b调c等等,可以改在 a调b, b调c。)。
- 过多的注释。
对于出现了坏味道的代码,也不太可能一味地追求去消除它,毕竟追求极致是要付出时间成本的,而且有些时间会出现首鼠两端的情况,一定要权衡利弊。
关于重构
- 持续进行,而不在版本发布后才想起重构。
- 小步骤进行,不要尝试硬着陆。