现代JavaScript开发中的设计模式

该材料的作者(我们将其翻译发表)说,在软件开发的世界中,“体系结构设计”可以称为构建应用程序的过程,在此过程中,他们努力使之成为高质量,可靠且易于接受的应用程序。 此外,设计模式(模式)使您可以使用一些概念作为解决常见问题的方法。 这些决定可以从抽象的,概念的到非常具体的不等。 他们的知识使开发人员可以有效地相互交流。

如果团队中至少有两个开发人员了解模式,那么谈论解决团队面临的问题将变得非常有成效。 如果团队中只有一名成员知道这些模式,那么通常只是为了向团队其他成员阐明他所知道的内容。

图片

本文的目的是通过对软件开发领域的知识的正式介绍来吸引读者,向他们展示设计模式的思想,并描述几种有趣的模式,因为它们可以在现代JavaScript开发中找到应用。

单例模式


▍一般


设计模式“ singleton”(也称为“ singleton”)不能被称为使用最广泛的模式之一,但是我们开始与他对话,因为它相对容易理解。

此模式源自单例的数学概念-单例集,即仅包含一个元素的集。 例如,集合{null}是单例。

在软件开发领域,“单一”模式的含义归结为以下事实:我们将某个类的可能实例的数量限制为一个对象。 首次尝试基于实现此模式的类创建对象时,实际上是创建了这样的对象。 所有随后创建类实例的尝试都将返回在第一次尝试获得类实例时创建的对象。


当我们拥有蝙蝠侠时,为什么还要另一个超级英雄呢?

上面是实现单例模式的类的示例。

▍为什么需要它?


显然,这种模式允许我们将自己限制为一个“超级英雄”(显然是蝙蝠侠)。 但是他为什么还需要呢?

尽管这种模式并非没有其自身的问题(鉴于单身人士称其为病理骗子 ,以前也被称为邪恶),但在某些情况下它可能非常有用。 这些情况之一是初始化配置对象。 在典型的应用程序中,仅保留该对象的一个​​实例是有意义的,除非根据项目的功能,在其中使用了几个类似的对象。

here在哪里使用?


在大型流行框架中使用单例模式的主要示例是Angular服务。 Angular文档有单独的页面,说明如何使服务成为单例。

单调形式的服务设计具有深层含义,因为服务被用作状态,配置的存储库,并允许您组织组件之间的交互。 所有这些导致了开发人员需要这样一个事实,即他的应用程序将不会具有同一服务的多个实例。

考虑一个例子。 假设我们有一个简单的应用程序,用于计算按钮的点击次数。


每次单击任何按钮都会更新计数器

按钮的单击次数必须存储在一个对象中,该对象实现以下功能:

  • 它允许您计算按钮的点击次数。
  • 这样就可以读取点击计数器的当前值。

如果此类对象不是单例(并且每个按钮都有其自己的实例),则程序将错误地计算按钮的单击次数。 此外,使用这种方法,必须解决以下问题:“将从哪个负责计算点击次数的特定对象获取屏幕上显示的数据?”

观察者模式


▍一般


观察者模式是一种设计模式,其中一个称为主题的对象维护一个称为观察者的依赖对象的列表,并在它们的状态改变时自动通知它们,通常通过调用其方法之一。

如果您在现实世界中发现了这种比喻,那么理解这种模式并不困难。 即,我们正在谈论报纸订阅。

假设您通常在售货亭买报纸。 您去那里,问是否有您最喜欢的报纸的新鲜发行。 如果您需要的不在自助服务亭中,那么您要回家,浪费时间,然后再次前往自助服务亭。 如果我们认为这种情况适用于JavaScript,那么就好像是对某个实体的周期性轮询,直到从该实体接收到必要的数据为止。

之后,当您最终获得所需的报纸时,就可以继续进行您一直以来努力的工作-喝杯咖啡,扩大报纸。 在JavaScript中,这相当于调用回调,我们将在获得所需结果后调用该回调。


最后你可以看报纸

这样做会更合理:订阅报纸并每天接收最新一期。 通过这种方法,出版商将让您知道已经发行了新报纸,并将其交付给您。 您不必再去售货亭了。 不再浪费时间。

如果再次切换到JavaScript,则意味着您不必再在循环中等待某些结果,并且在收到结果后,调用某个函数。 相反,您通知主题您对某些事件(消息)感兴趣,然后将回调函数传递给该主题,当相关数据准备就绪时应调用该回调函数。 在这种情况下,您将成为观察员。


现在,您将永远不会错过自己喜欢的早报

有问题的模式具有一个不错的功能:您不必成为唯一的观察者。 如果您找不到自己喜欢的报纸,那会让您不高兴。 但是其他无法购买的人也会遇到同样的事情。 这就是为什么几个观察者可以订阅一个主题的原因。

▍为什么需要它?


模式“观察者”在许多情况下都会使用,但是通常在要在对象之间创建一对多关系时应使用它,同时,不应牢固地连接此类对象。 另外,系统应该能够通知无数对象有关某些更改的信息。

JavaScript应用程序是应用观察者模式的好地方,因为此处所有内容都是事件驱动的,与其不断引用某个实体来确定是否发生了您感兴趣的事件,不如让它通知您何时会更好事件的发生(这与古老的谚语类似:“请勿致电我们。必要时我们会自行致电您”)。

您可能已经使用了类似于观察者模式的设计。 例如,这是addEventListener 。 向元素添加事件侦听器具有使用观察者模式的所有迹象:

  • 您可以订阅该对象。
  • 您可以取消订阅该对象。
  • 对象可以将事件通知所有订阅者。

从某种意义上来说,了解“观察者”模式的存在是很有用的,因为这种知识可以让您实现自己的主题,或者比以前快得多,以找出使用该模式的现有解决方案。

here在哪里使用?


这种模式的基本实现不必特别复杂,但是有出色的库可以实现它,并在许多项目中使用。 我们正在谈论ReactiveX项目及其RxJS的 JavaScript版本。

RxJS库不仅允许订阅主题,还使程序员能够以多种方式转换数据,允许您组合许多订阅,提高了管理异步操作的能力。 另外,她的能力不限于此。 如果您想提高程序处理和将数据转换为更高级别的功能,那么建议您学习RxJS库。

除了“观察者”模式之外,ReactiveX项目还可以为“迭代器”模式的实现而感到自豪,该模式允许主体将订阅的完成情况通知订阅者,实质上,允许主体主动取消订阅。 在本文中,我不会讨论“迭代器”模式,但是,如果您刚刚开始学习设计模式,那么研究这种模式并考虑它如何与“观察者”模式组合可能是不错的练习。

外墙图案


▍一般


外墙图案因建筑而得名。 在建筑中,立面通常是建筑物的外侧之一,通常是正面。 英文是从法语借来的“ facade”一词。 我们谈论的是“外墙”一词,除其他外,它被翻译为“建筑物的正面”。

建筑中建筑物的正面是建筑物的外部,隐藏了内部。 在“外观”模式中可以注意到类似的属性,因为它旨在将复杂的内部机制隐藏在某个外部接口之后。 它的应用程序使开发人员可以使用非常简单的外部API进行工作,同时,还可以更改隐藏在外观背后的内部机制,而不会影响系统性能。

▍为什么需要它?


“外观”模式可用于多种情况,其中尤其值得一提的是,它们试图使代码更易于理解时(即,它们将复杂的机制隐藏在简单的API后面),以及那些系统片段倾向于尽可能多地使用的情况。松散的彼此连接。


这些物品需要龙穴中的东西。

显而易见,立面对象(或包含多个对象的图层)是非常有用的抽象。 如果可以避免的话,任何人都不大可能会碰上龙。 需要Facade对象才能为其他对象提供便捷的API,并且该对象将自行处理所有的龙门戏法。

“外观”模式的另一个有用功能是可以根据需要“重制”龙,但这不会影响应用程序的其他部分。 假设您想用一只小猫代替一条龙。 小猫像龙一样,有爪子,但喂养起来更容易。 将龙换成小猫-这意味着-重写外观对象的代码,而无需更改相关对象。

here在哪里使用?


外观模式通常在Angular中找到。 在那里,服务被用作简化一些基本逻辑的手段。 但是这种模式不仅适用于Angular,在下面您可以看到。

假设我们需要向应用程序添加状态管理系统。 要解决此问题,您可以使用各种工具,例如Redux,NgRx,Akita,MobX,Apollo以及不断涌现的新工具。 为什么不尝试全部?
状态管理库应提供的主要功能是什么? 这些可能是以下功能:

  • 一种通知状态管理系统我们需要更改状态的机制。
  • 获取当前状态或其片段的机制。

看起来还不错。

现在,有了“外观”模式,您就可以编写外观以与状态的各个部分配合使用,并提供可在程序中使用的便捷API。 例如,诸如facade.startSpinner()facade.stopSpinner()facade.getSpinnerState() 。 这样的方法很容易理解,您可以在有关程序的对话中轻松引用它们。

之后,您可以使用实现“外观”模式的对象并编写将转换代码的代码,以使其可以与Apollo一起使用(使用GraphQL管理状态是一个热门话题)。 也许在测试期间您会发现Apollo不适合您,或者您不满意基于此状态管理系统编写单元测试。 没问题-编写一个旨在支持MobX的新外观,然后重试该系统。


通过单个外观访问的用于管理应用程序状态的不同系统也可能是龙...

总结


您可能已经注意到,当我们谈论设计模式时,我们并未考虑代码示例。 事实是,对每种模式的深入分析在距离最薄的书本不远的地方至少绘制了一个单独的章节。 顺便说一下,由于我们在谈论书籍,因此在这里我们 有一些有趣的出版物,对于那些想要研究模式研究的人来说,您可以参考。

最后,我想说的是,在模式开发中,没有什么比在互联网上搜索,阅读和独立测试各种想法更胜一筹了。 即使事实证明您永远不会使用模式,您也将了解新知识并了解它们,并在您意想不到的领域中成长。

亲爱的读者们! 您使用什么设计模式?

Source: https://habr.com/ru/post/zh-CN450318/


All Articles