不好:
class UserSettings { constructor(user) { this.user = user; } changeSettings(settings) { if (this.verifyCredentials(user)) { // ... } } verifyCredentials(user) { // ... } }
好:
class UserAuth { constructor(user) { this.user = user; } verifyCredentials() { // ... } } class UserSettings { constructor(user) { this.user = user; this.auth = new UserAuth(user) } changeSettings(settings) { if (this.auth.verifyCredentials()) { // ... } } }
开放封装原则(OCP)
正如 Bertrand Meyer 所说,“软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。”这是什么意思呢?这个原则基本上规定了你应该允许用户扩展你的模块,但不需要打开 .js 源代码文件来进行编辑。
不好:
class AjaxRequester { constructor() { // 如果我们需要另一个 HTTP 方法,比如 DELETE,该怎么办? // 我们必须打开这个文件然后手工把它加进去 this.HTTP_METHODS = ['POST', 'PUT', 'GET']; } get(url) { // ... } }
好:
class AjaxRequester { constructor() { this.HTTP_METHODS = ['POST', 'PUT', 'GET']; } get(url) { // ... } addHTTPMethod(method) { this.HTTP_METHODS.push(method); } }
里氏替换原则(LSP)
这是一个吓人的术语,但描述的却是个简单的概念。它的正式定义为“如果 S 是 T 的子类,那所有 T 类型的对象都可以替换为 S 类型的对象(即 S 类型的对象可以替代 T 类型的对象),这个替换不会改变程序的任何性质(正确性、任务执行等)。”这确实是个吓人的定义。
对此最好的解释是,如果你有父类和子类,那么父类和子类可以交替使用而不会造成不正确的结果。这可能仍然让人感到疑惑,那么让我们看看经典的正方形和矩形的例子。在数学上,正方形也是矩形,但是如果你在模型中通过继承使用 “is-a” 关系,你很快就会陷入困境。
不好:
class Rectangle { constructor() { this.width = 0; this.height = 0; } setColor(color) { // ... } render(area) { // ... } setWidth(width) { this.width = width; } setHeight(height) { this.height = height; } getArea() { return this.width * this.height; } } class Square extends Rectangle { constructor() { super(); } setWidth(width) { this.width = width; this.height = width; } setHeight(height) { this.width = height; this.height = height; } } function renderLargeRectangles(rectangles) { rectangles.forEach((rectangle) => { rectangle.setWidth(4); rectangle.setHeight(5); let area = rectangle.getArea(); // 不好:这里对正方形会返回 25,但应该是 20. rectangle.render(area); }) } let rectangles = [new Rectangle(), new Rectangle(), new Square()]; renderLargeRectangles(rectangles);
内容版权声明:除非注明,否则皆为本站原创文章。