Javascript接口(interface)/松耦合

标签 javascript design-patterns ecmascript-6

在像 PHP 这样的编程语言中,很多具体的实现都放在接口(interface)后面,因此更换具体的实现会容易得多,因为您正在编程到接口(interface)而不是具体化。

在我们的项目中,我们想要实现一个名为 moment.js 的日期库。为我们处理日期,但如果我们在所有的 javascript 中实现它,就会担心与我们的代码耦合太严重。

要在 javascript 中创建一些接口(interface),方法和属性可以由我们自己的库包装,这样我们可以更轻松地换出 concrete我们正在使用的日期库以防万一。

我想知道在javascript中是否有某种模式或标准化方式。乍一看,它只是为我们自己创建一个库,我们将在其中放置仍然使用 moment.js 的复杂可重用逻辑。

如果我们仍然使用 moment.js在这里和那里的功能我们仍然与它紧密耦合。如果我们确实实现了某种只能与 moment.js 对话的模式通过适配器或接口(interface),我们被困在为整个库实现包装器,这似乎很荒谬。

javascript 开发人员如何处理这个问题?

最佳答案

我看到两种方法来解决这个问题。

  • 您当前的方法:包装。
  • Duck typing一路!

  • 当我选择包装的#1 方法时。

    基本上你对库的 API 风格不满意。例如,您反对流畅的 API,反之亦然。因此,您包装整个库以使您感觉更舒适,并且在一天结束时,当您切换到另一个库时,您只需要更改包装器的实现即可。

    当我会去#2方法时,鸭子一路打字!

    您已经真正了解了动态类型语言的优点和缺点,因此您不会沉迷于强类型语言的方法,但您仍然可以在两种编程风格上进行开发。

    此外,您已经了解我们开发人员倾向于认为我们将被迫每年或在 5 年后进行技术转换,但这是一种错误的行为,因为虽然好的决策不是永远的,但它们会持续相当长的时间,因此您的系统或应用程序可能需要的不仅仅是从一个库到另一个库。

    在像 JavaScript 这样的动态类型语言中,我们可以继续用文档代替接口(interface)的需求。检查以下代码片段:
    function doStuff(moment) {
        var currentDate = moment(new Date());
    }
    

    对,你在注入(inject) moment ,但是一旦您意识到需要切换到另一个库,就没有什么能阻止您创建包装器,因为您知道使用日期与任何库都或多或少相同。不再加载 momentjs 并开发整个包装器,并调用您的自定义代码甚至是新的花哨的库!
    function moment(date) {
         return {
              date: date,
              ago: () => {
                  var date = this.date;
    
                  // do the stuff here to return a text like "3 hours ago"
    
                  return text;
              }
         };
    }
    

    而且您知道这将起作用,除非 blabox 不输出给定函数的调用者的预期结果,对吧?

    你现在是否会因为有一天你想从 momentjs 切换到谁知道呢?可能不会,因为你对 momentjs 的 fluent API 没问题,并且创建替代实现并不难,从一个以相同方式调用的函数开始,遵循相同的 API,但公开不同的实现。

    一旦你的鸭子说嘎嘎!,谁在乎它仍然是你的老鸭子还是年轻的鸭子?

    您需要其他建议吗? You're not going to need it ,如果你需要它,那就是提供一只新鸭子的问题。

    关于松耦合

    IMO,动态类型语言本身是松散耦合的。由于调用者和被调用者之间除了 API 标识符(属性名、函数名......)之外没有其他耦合,因此实现在设计上是可热切换的。

    也许有一个异常(exception)情况:API 具有特定于技术的内涵。例如,您需要调用名为 sendUsingWebSockets 的函数。并且您不想与特定的通信技术耦合,因此将该特定功能包装为 send一些设置定义了发送数据的方法(REST、WebSockets、WebRTC ...)。

    回答OP在一些评论中解释的一些担忧......

    The only question remaining is what would you say to people using a wrapper for mutational purposes? People writing a wrapper method to retrieve a date and mutating it always by prefixing it with something like a string of 'date:' or something alike. I keep telling people that writing an entire wrapper just for cases like this is not worth it since there it no guarantee all the little date instances will be needing the same 'date:' string prefixed.



    在过去的 10 年里,Web 开发发生了很大的变化。我们处于 UI 框架的时代,数据绑定(bind)存在于 5 年多以来的每个 UI 框架中。

    为日期添加前缀与 UI 要求相关,我不会在应用程序服务中硬编码类似的东西。

    例如,良好的旧 AngularJS 1.x 具有指令和组件,您可以在这些指令和组件上实现该前缀,而无需在模型或服务中硬编码前缀:
    function showDateDirective() {
         return {
             scope: {
                 date: "="
             },
             link: (scope, element) {
                  element.text(`date: ${scope.date.[call here a formatting function]()}`);
             }
         };
    }
    
    module.directive("showDate", showDateDirective);
    

    也就是说,当您需要显示日期时,只需将其绑定(bind)到某个元素,然后该指令将完成其余工作:
    <span show-date="model.date"></span>
    

    您需要更改该前缀吗?更改指令实现,您在几秒钟内就完成了工作!

    关于Javascript接口(interface)/松耦合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42667848/

    相关文章:

    javascript - 在 TinyMCE 内的元素旁边显示一个按钮

    javascript - 使 slider 动态

    design-patterns - 超链接与按钮

    javascript - 不能在 react 中使用粗箭头函数(ES6)

    javascript - 如何将js中的一堆对象映射到另一个对象

    WKWebView 中的 javascript 桥不起作用

    javascript - 输入字段 .val() 的值不是函数

    c++ - 以下情况的设计模式

    c# - 使用 Model View Presenter 设计模式 (MVP) 的好处

    javascript - ECMAScript v 6 何时成为标准