对象和数据结构
使用 getters 和 setters
JS 没有接口或类型,因此实现这一模式是很困难的,因为我们并没有类似 public
和 private
的关键词。
然而,使用 getters 和 setters 获取对象的数据远比直接使用点操作符具有优势。为什么呢?
- 当需要对获取的对象属性执行额外操作时。
- 执行
set
时可以增加规则对要变量的合法性进行判断。 - 封装了内部逻辑。
- 在存取时可以方便的增加日志和错误处理。
- 继承该类时可以重载默认行为。
从服务器获取数据时可以进行懒加载。
反例:
12345678910class BankAccount {constructor() {this.balance = 1000;}}let bankAccount = new BankAccount();// Buy shoes...bankAccount.balance = bankAccount.balance - 100;
正例:
让对象拥有私有成员
可以通过闭包完成
反例:
正例:
类
单一职责原则 (SRP)
如《代码整洁之道》一书中所述,“修改一个类的理由不应该超过一个”。
将多个功能塞进一个类的想法很诱人,但这将导致你的类无法达到概念上的内聚,并经常不得不进行修改。
最小化对一个类需要修改的次数是非常有必要的。如果一个类具有太多太杂的功能,当你对其中一小部分进行修改时,将很难想象到这一修够对代码库中依赖该类的其他模块会带来什么样的影响。
反例:
正例:
开/闭原则 (OCP)
“代码实体(类,模块,函数等)应该易于扩展,难于修改。”
这一原则指的是我们应允许用户方便的扩展我们代码模块的功能,而不需要打开 js 文件源码手动对其进行修改。
反例:
正例:
利斯科夫替代原则 (LSP)
“子类对象应该能够替换其超类对象被使用”。
也就是说,如果有一个父类和一个子类,当采用子类替换父类时不应该产生错误的结果。
反例:
正例:
接口隔离原则 (ISP)
“客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。”
在 JS 中,当一个类需要许多参数设置才能生成一个对象时,或许大多时候不需要设置这么多的参数。此时减少对配置参数数量的需求是有益的。
反例:
正例:
依赖反转原则 (DIP)
该原则有两个核心点:
- 高层模块不应该依赖于低层模块。他们都应该依赖于抽象接口。
- 抽象接口应该脱离具体实现,具体实现应该依赖于抽象接口。
反例:
正例:
使用 ES6 的 classes 而不是 ES5 的 Function
典型的 ES5 的类(function)在继承、构造和方法定义方面可读性较差。
当需要继承时,优先选用 classes。
但是,当在需要更大更复杂的对象时,最好优先选择更小的 function 而非 classes。
反例:
正例:
使用方法链
这里我们的理解与《代码整洁之道》的建议有些不同。
有争论说方法链不够干净且违反了德米特法则,也许这是对的,但这种方法在 JS 及许多库(如 JQuery)中显得非常实用。
因此,我认为在 JS 中使用方法链是非常合适的。在 class 的函数中返回 this,能够方便的将类需要执行的多个方法链接起来。
反例:
正例:
优先使用组合模式而非继承
在著名的设计模式一书中提到,应多使用组合模式而非继承。
这么做有许多优点,在想要使用继承前,多想想能否通过组合模式满足需求吧。
那么,在什么时候继承具有更大的优势呢?这取决于你的具体需求,但大多情况下,可以遵守以下三点:
- 继承关系表现为”是一个”而非”有一个”(如动物->人 和 用户->用户细节)
- 可以复用基类的代码(“Human”可以看成是”All animal”的一种)
- 希望当基类改变时所有派生类都受到影响(如修改”all animals”移动时的卡路里消耗量)
反例:
正例:
测试
单一的测试每个概念
反例:
正例: