设计原则-英译中
前言
设计原则只是供开发人员参考的,并不是一定要遵守的规则,但需要了解并尽可能的去满足设计原则。
KISS
Keep It Simple Stupid(保持简单直白)
为什么
- 更少的代码节省更多的时间,减少更多的Bug,以及更容易修改
- 简单是复杂的更高水平
- 完美并不是没有东西可以被添加进来,而是没有东西可以被带走
怎么做
- 不要使用大部分人难以理解的代码,让其晦涩难懂
- 不要过度优化,不是封装的越多越深越好,也不是底层函数或者高级语法用的越多越好
YAGNI
you aren’t gonna need it(你不会需要它-不要实现非必要的东西)
为什么
- 你的时间非常宝贵,任何为将来可能需要的功能做的工作,不但会导致你从当前必须实现的功能分心,而且还浪费了阅读者的时间
- 这将导致代码臃肿、软件变得庞大且复杂
怎么做
- 在日常开发中,需要尽可能评估好设计的复杂度,不要过度设计。发现自己设计有不足的地方,,要有
持续重构
的精神,不断完善自己的设计,不要等到事情累计到不得不重构的时候,那时可能影响范围已经很大,事情往往已经到了积重难返的阶段
KISS和YAGNI的异同
KISS和YAGNI都是在阐述简单
这个事情,只是看待的角度不同,KISS是从如何做
(保持简单)的角度,YAGNI是从要不要做
(不要过度设计)的角度
DTSTTCPW
Do The Simplest Thing That Could Possibly Work(做最简单的事情,如果它可能工作)
为什么
- 如果我们致力于解决真正的问题,就能最大限度地解决真正的问题
- 专业程序员就是能写出白痴程序员都能读懂的代码,白痴程序员就是写出即使专业程序员都无法读懂的代码
怎么做
- 询问自己:完成这件事最简单的方式是什么
Separation of Concerns
关注点分离是将计算机程序分离成不同部分的设计原则,这样每个部分都单独处理自己的关注点。例如,业务逻辑与非业务逻辑是不同的关注点,更改业务逻辑不应该影响到非业务逻辑
为什么
- 简化软件的开发和维护
- 当每个关注点分离足够好时,代码的可复用性更高且开发及迭代更加具备独立性
怎么做
- 将程序尽可能分离成各自独立的单一模块中
DRY
Dont’t Repeat Yourself(不要写重复的代码)
系统中的每一个部分都应该单一、清晰、且具备权威性。项目中每一个重要的功能应该仅在一份源代码中,如果相似的功能出现在两个不同的地方,通过抽象出不同部分将其结合起来往往是有益的
为什么
- 重复可能导致维护困难、因果颠倒、逻辑互斥
- 修改系统中任何一个单一的部分,不会改变到其他没有关联的地方
- 逻辑上相关联的部分修改时,可以保持可预测及同步性
怎么做
- 将业务规则、长的表达式、if语句、数学公式、元数据等等,放在一个地方
- 在代码中使用单一、明确的来源
- 当相似功能的代码出现在不同位置3次时,就应该重构这段代码(为什么不是两次,因为过早的重构可能会导致错误的抽象,而3次时,维护的成本已经超过了重构的成本,以及可能潜在的糟糕设计)
PS
我最怕那些copy别人一大段代码的!!!简直噩梦!!!关键我还碰到了!!!苍天呐!!!
Code For The Maintainer
为维护者而编写
为什么
- 目前为止,维护是任何一个项目最昂贵的阶段
怎么做
- 做一个维护者
- 编写代码时,要将维护你代码的人,当成知道你居住地址且有暴力倾向的精神病患者
- 编写代码和注释时,要关照级别较低的人,让他们也能够愉快的阅读并能从中学习
- 不要让他人思考
- 遵循最小惊讶原则(设计应该按照大多人期望的形式运行,而不是让其感到惊讶或者诧异)
Avoid Premature Optimization
避免过早优化(理解过早和非过早至关重要)
为什么
- 目前还不清楚瓶颈在哪里
- 优化后,可能变得更加难以阅读及维护
怎么做
- 让它更加正确、更加快速
- 不要在不需要时优化,而是在分析及发现瓶颈后再优化
Minimise Coupling
最小化耦合(耦合是模块/组件间项目依赖的程度)
为什么
一个模块的改变经常会对其他模块造成影响
由于模块间的相互依赖,使用及组装可能花费更多的时间
模块间相互依赖程度高容易导致复用性及可测试降低
怎么做
- 消除或者减少不必要的联系
- 通过隐藏实现细节来减少耦合
- 遵循
迪米特法则
Law of Demeter
迪米特法则(不要和陌生人说话。如果两个类无需直接通信,那么就不应该发生直接的相互调用,而应该通过第三方转发调用)
为什么
- 直接通常导致增强耦合
- 直接通常显示了过多的实现细节
怎么做
一个对象的方法只能通过一下方式调用:
- 对象本身
- 方法中的一个参数
- 方法中被创建的对象
- 对象中的直接属性或字段
Composition Over Inheritance
组合优于继承
为什么
- 类之间的耦合更低
- 继承打破封装
怎么做
- 继承前考虑父类是否有缺陷,而你是否愿意将缺陷传播到你的类中
- [has a]或者[use a]的类关系用组合;[is a]的情况,才能使用继承
Orthogonality
正交性,系统中概念上不相干的事情不应该联系在一起
为什么
- 设计越正交,异常越少,使得学习、阅读、编写代码更加容易
Robustness Principle
伯斯塔尔定律,对你想要做的要求严格,对你从其他人那里接收的保持宽松
为什么
为了在服务迭代过程中,提供者能够做出新的需求,同时对现有客户造成最小的影响
怎么做
发送给其他机器的代码或者是命令,应该确保完全符合规范。但是接收的输入应该接受不符合规范的,只要含义清楚。
Inversion of Control
控制反转原则,也叫好莱坞原则(不要打电话给我,我们会打电话给你),使可重用的代码和解决具体问题的代码,即使他们在一个应用里
为什么
- 控制反转被用来增加程序的模块化以及可扩展性
- 将任务的执行与实现解耦
- 将模块专注于他们所涉及的任务
- 防止模块被替换带来的副作用
怎么做
- 使用工厂模式
- 使用服务定位模式
- 使用依赖注入
- 使用上下文查找
- 使用模板方法模式
- 使用策略模式
Maximise Cohesion?
最大化内聚,
Liskov Substitution Principle
里氏替换原则,程序中的对象可以被其子类替换,而不改变程序的正确性
Open/Closed Principle
开闭原则,软件实体应该对扩展开放,对修改关闭
为什么
- 通过对现有代码最小化的改动来改善代码的可维护性和稳定性
怎么做
编写可以扩展的类(而不是可以修改的类)
仅暴露可移动可修改的部分,隐藏其他部分
Single Responsibility Principle
单一责任原则,一个类不应该有超过一个需要改变的理由
为什么
- 可维护性:改变应该仅在一个模块或者类中进行
怎么做
- 参考Curly’s Law
Hide Implementation Details
隐藏实现细节,一个软件模块通过提供一个接口来隐藏信息,同时不泄露任何不必要的信息
为什么
- 当一个实现改变,使用接口的客户端不用进行更改
怎么做
- 最小化类和变量的可访问性
- 不要将变量数据设置为public
- 避免放置私有的实现细节放到类的接口上
- 减少耦合以隐藏更多的实现细节
Curly’s Law
科里定律,为任何特定代码选择一件单一、明确的目标,做一件事情
Encapsulate What Changes
封装经常修改的代码
为什么
- 当改变发生时,减少需要修改的地方
怎么做
- 封装API背后不同的概念
- 尽可能将不同概念分离到它自己的模块
Interface Segregation Principle
接口隔离原则。将臃肿的接口减少为多个更小、更具体的客户端特定接口。接口应该更依赖于调用它的代码,而不是实现它的代码。
Command Query Separation
命令查询分离,每个方法要么是执行操作的命令,要么是向调用者返回数据的查询,但不能两个同时存在。这样就能使得使用者更加方向的调用。
为什么
- 通过清除的将发放划分为查询和命令,程序员可以在不知道方法实现细节的情况下,更加有信心进行编码
怎么做
- 将一个方法作为查询或命令实现
- 明确方法的名称,通过约定名称的方式告知是查询还是命令
Murphy’s Law
墨菲定律,任何可能出错的都会出错
Brooks’s Law
布鲁克斯法则,向已经延误的项目添加人力,只会使其更晚
Linus’s Law
林纳斯定律,给予足够的眼睛关注,所有的bug都会显现,代码检视很重要