您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > javascript

开发者应知道的方法论:JavaScript中的DILOS原则

时间:2020-11-11 10:22:00  来源:  作者:

本文最初发布于 hackernnon 网站,经原作者授权由 InfoQ 中文站翻译并分享。

SOLID 原则是开发人员创建灵活、可理解和可维护代码的基础。但你要正确遵循这些原则就可能明显减慢开发速度,并且大多数人没那么操心代码质量,因此我发明了一套更好用的原则。

DILOS 原则是我们构建可怕代码的坚实支柱。

我个人已经用上了 DILOS 原则,成功创建出大堆混乱难懂和臃肿的代码,这篇文章我就来具体介绍一下:

DILOS 的含义:

  • D——依赖倒置反转原则
  • I——接口捆绑原则
  • L——里氏分离原则
  • O——开闭原则
  • S——多职责原则

依赖倒置反转原则

高级模块必须依赖低级模块。依赖实体而不是抽象。

把某些东西抽象出来,就是要隐藏这些东西内部的实现细节,有时是原型,有时是函数。因此当你调用这个函数时不必完全了解其机制。如果你非得先搞懂大型代码库中的所有函数,那就别想着写代码了。可能需要几个月的时间才能看完那些东西。

但现在我们要把这条原则倒过来:不要抽象任何东西。也就是尽量少用小块函数,把所有东西都塞到一个单体函数里。如果别人想调用你的函数,让他看懂你的每一行代码再说吧。

下面是整洁代码的一个示例:

function hitAPI(url, httpMethods){
  // Implementation example
}
hitAPI("https://www.kealanparr.com/retrieveData", "GET");
hitAPI("https://www.kealanparr.com/retrieveInitialData", "GET");

你看,你用不着操心 hitAPI 在做什么,我们只传递了一个 URL 和一个 HTTP 请求,然后就搞定了。现在这段代码是高度可重用和可维护的。这个函数可以在一个地方处理所有 URL。我们已经尽可能让高级函数(我们放在 base 原型中的函数,可以和下层的许多东西共享)不依赖于任何低级函数。

那么如果我们反转这个依赖倒置(Dependency-Inversion)原则呢?

function hitDifferentAPI(type, httpMethods){ 
  if (this instanceof initialLoad) { 
    // Implementation example
  } else if (this instanceof navBar) {   
    // Implementation example 
  } else {  
    // Implementation example 
  }
}

现在我们让高级 api 请求依赖于许多较低级别的类型。完成任务后,它不再是完全通用的了,并且会依赖其继承链中较低的类型。

接口捆绑原则

强迫客户端依赖它们不用的 [代码]。

其他语言里的接口用于定义不同对象拥有的方法和属性。

不要向不需要的对象添加代码?不要将太多无关的功能捆绑在一起?嗯,胡扯嘛这是。

我们一定要把松散耦合的代码都绑在一个地方。关键在于一定要依赖你用不着的东西。

我们稍后将在“多重职责原则”中进一步解释,但请记住这条原则,在所有地方疯狂用它。还记得花半天时间查找几百个文件搜索 bug 的经历吗?那种事情不会再有了。搞一个名为 main.js 的 JS 文件,然后把所有代码都塞进去。

让你的站点预加载所有内容,不要搞什么 JS 脚本按需加载,这样初始加载速度就会慢如蜗牛啦。

写代码的时候把宇宙毁灭时的需求都想好,然后提前写好对应的逻辑,反正你迟早用得上嘛。

如果有人需要你代码里的一根香蕉,那就塞给他一头拿着香蕉的大猩猩。客户端要啥就给它附送一堆垃圾,它们肯定会感谢你的。

写的函数越少越好。把什么东西封装在一个放在其他地方的新函数里,并抽象化它的逻辑?可别这么干。怎么让人犯迷糊怎么来,需要代码的时候复制粘贴过来就行。

理想情况下,我们的代码流只有 1 个对象。在非常大的代码库中,我们可能有 2 个对象。通常将其称为“上帝对象”反模式,其中我们要到处用单独的一个对象,因为所有事情都得它来做。稍后我们将详细讨论。

里氏分离原则

软件各部分的子级和父级不可以互换。

你竟然会在代码中使用继承吗?这绝对要注意。你应该复制粘贴而不是继承代码。Copy-Paste 反模式就是这个意思,你不应该把代码的通用功能抽象为模块化的可重用功能,而应当在所有需要的地方都复制代码。这会增加技术债(将来你迟早要回来修复的),而且每更改一段代码,都需要多次搜索才能找到它在代码库中出现在了哪些位置。

DRY 原则表示 Don't Repeat Yourself,而 WET 原则恰恰相反,指的是我们 Write Everything Twice。必要时应该写更多次数。抵制继承,随意复制粘贴。

但是,如果你确实需要利用里氏分离原则,请确保在与继承链中较高子级(父级)交换对象时,继承链中较低子级的对象原型不能正常工作。

为什么?

因为如果我们不遵循里氏分离原则,我们就会构建准确而健壮的继承链。将逻辑抽象为封装好的 base 原型 / 对象。我们还会对原型链中的不同方法按逻辑分组,它们的特定覆盖会让代码路径更加可预期和可发现。

如果你正确地遵循了这一原则,那么父级能用的时候子级也没法用,继承就会毫无意义。如果你的程序尝试引用的函数并不存在于自己的子级中,因此崩溃掉——你就会完全避免继承会给你带来的任何好处——这正是我们遵循这一原则的目的。

开闭原则

对象应对修改开放,对扩展封闭。

好的代码通常会扩展对象的代码,以限制修改 base 原型。这样,完成扩展的对象就可以处理自己的状态以及需要执行的新功能(仅处理子项需要做的少量更改即可)。

上面这段话是胡说八道,我们真正应该做的是:

  • 对修改开放——要做任何更改,我们都要更改 base 原型 / 函数。
  • 对扩展封闭——如果要扩展,你就会开始模块化代码,不要这么做。确保所有事情都在 base 原型 / 函数中完成。

如果在处理每个场景时都分支,那么上面这两步带来的负担就更重了。所以最后你会看到诸如这样的代码:

function makeSound(animal) {
  if (animal == "dog") { 
    return "bark"; 
  } else if (animal == "duck") { 
    return "quack"; 
  } else if (animal == "cat") {  
    return "meow"; 
  } else if (animal == "crow") { 
    return "caw";  
  } else if (animal == "sheep") {  
    return "baa";  
  } else if (animal == "cow") {  
    return "moo";   
  } else if (animal == "pig") {  
    return "oink";   
  } else if (animal == "horse") {  
    return "neigh";   
  } else if (animal == "chicken") {  
    return "cluck";  
  } else if (animal == "owl") {
    return "twit-twoo";    } else {  
      /// It has to be a human at this point
      return "hi";  
    }
}

现在,如果你需要更改某些内容,只需添加另一个 if 检查即可。这和下文列出的多职责原则有关,但核心在于将所有内容都包含在 base 函数 / 原型中。

这样你就会进入“脆弱基类”反模式。在这种模式下,更改 base 函数 / 原型时,你最后会在调用此函数的其他触点上出现错误。

例如,假设 human 不该再掉进 else 里,而你添加了新的 animal,名为 wolf,你就会引入错误(除非你更新了期望 human 被记录的位置)。

多职责原则

确保你的函数 / 对象有多重职责。

优秀的编程人员常常会将他们的代码分成多个不同的对象或模块。但我可搞不清楚这种事情,我记不住它们都负责什么事情。

下面是一个例子:

const godObject = { 
  handleClicks: function(){},
  getUserName: function(){}, 
  handleLogin: function(){}, 
  logTransactionId: function(){},  
  initialSiteLoad: function(){} };

godObject 负责网站的许多功能。付款、登录、网站负载、记录交易 ID 以及网站上的所有点击功能都包括在其中。太棒了,这样如果你遇到了错误,就会知道它只能出现在这里。确保代码库中的每个地方都需要访问 godObject。让它做一切工作。

我们在代码中真正想要的是高耦合(确保系统的各个部分相互依赖)和低内聚(将许多随机的数据和片段放在一起)。

这种反模式有时被称为“瑞士军刀”,因为就算你要的只是一把剪子,但它也可以是指甲锉、锯子、镊子、开瓶器,也可以是软木钉。

我不断强调的是,要把所有东西放在一起,然后绑定、打包、捆在一起。

总 结

我希望大家看完这篇文章后,就知道软件究竟应该怎么写才能尽可能增加调试需求、尽可能把人搞糊涂,并且搞出来最多的技术债。

延伸阅读:

https://hackernoon.com/introducing-dilos-principles-for-JAVAscript-code-jp1d3w1b



Tags:JavaScript DILOS原则   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
本文最初发布于 hackernnon 网站,经原作者授权由 InfoQ 中文站翻译并分享。SOLID 原则是开发人员创建灵活、可理解和可维护代码的基础。但你要正确遵循这些原则就可能明显减...【详细内容】
2020-11-11  Tags: JavaScript DILOS原则  点击:(74)  评论:(0)  加入收藏
▌简易百科推荐
1、通过条件判断给变量赋值布尔值的正确姿势// badif (a === 'a') { b = true} else { b = false}// goodb = a === 'a'2、在if中判断数组长度不为零...【详细内容】
2021-12-24  Mason程    Tags:JavaScript   点击:(5)  评论:(0)  加入收藏
给新手朋友分享我收藏的前端必备javascript已经写好的封装好的方法函数,直接可用。方法函数总计:41个;以下给大家介绍有35个,需要整体文档的朋友私信我,1、输入一个值,将其返回数...【详细内容】
2021-12-15  未来讲IT    Tags:JavaScript   点击:(19)  评论:(0)  加入收藏
1. 检测一个对象是不是纯对象,检测数据类型// 检测数据类型的方法封装(function () { var getProto = Object.getPrototypeOf; // 获取实列的原型对象。 var class2type =...【详细内容】
2021-12-08  前端明明    Tags:js   点击:(23)  评论:(0)  加入收藏
作者:一川来源:前端万有引力 1 写在前面Javascript中的apply、call、bind方法是前端代码开发中相当重要的概念,并且与this的指向密切相关。本篇文章我们将深入探讨这个关键词的...【详细内容】
2021-12-06  Nodejs开发    Tags:Javascript   点击:(19)  评论:(0)  加入收藏
概述DOM全称Document Object Model,即文档对象模型。是HTML和XML文档的编程接口,DOM将文档(HTML或XML)描绘成一个多节点构成的结构。使用JavaScript可以改变文档的结构、样式和...【详细内容】
2021-11-16  海人为记    Tags:DOM模型   点击:(34)  评论:(0)  加入收藏
入口函数 /*js加载完成事件*/ window.onload=function(){ console.log("页面和资源完全加载完毕"); } /*jQuery的ready函数*/ $(document).ready(function(){ co...【详细内容】
2021-11-12  codercyh的开发日记    Tags:jQuery   点击:(35)  评论:(0)  加入收藏
一、判断是否IE浏览器(支持判断IE11与edge)function IEVersion() {var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串var isIE = userAgent.indexOf("comp...【详细内容】
2021-11-02  V面包V    Tags:Javascript   点击:(39)  评论:(0)  加入收藏
Null、Undefined、空检查普通写法: if (username1 !== null || username1 !== undefined || username1 !== '') { let username = username1; }优化后...【详细内容】
2021-10-28  前端掘金    Tags:JavaScript   点击:(50)  评论:(0)  加入收藏
今天我们将尝试下花 1 分钟的时间简单地了解下什么是 JS 代理对象(proxies)?我们可以这样理解,JS 代理就相当于在对象的外层加了一层拦截,在拦截方法里我们可以自定义一些个性化...【详细内容】
2021-10-18  前端达人    Tags:JS   点击:(51)  评论:(0)  加入收藏
带有多个条件的 if 语句把多个值放在一个数组中,然后调用数组的 includes 方法。// bad if (x === "abc" || x === "def" || x === "ghi" || x === "jkl") { //logic } // be...【详细内容】
2021-09-27  羲和时代    Tags:JS   点击:(58)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条