云服务器价格_云数据库_云主机【优惠】最新活动-搜集站云资讯

企业网站_孤独灿烂的鬼怪百度云_折扣

小七 141 0

NgRx公司NgRx正面:利弊了解facade模式,为什么您可能希望或不希望使用NgRx,以及如何创建facade。

你最近可能听说过一个围绕着这个角度社区的话题:NgRx中的外观。我觉得写一篇文章来讨论这个问题是个好主意。让我们学习外观是什么,支持和反对它们的论据,以及如何实现它。(您可以在此存储库中找到示例代码。)什么是立面?今年11月我在伦敦时,拍了这张白金汉宫正面的照片。尽管我看了它就知道它是白金汉宫,但我不知道里面有什么——那些警卫在那里是为了确保我不会发现。在代码中,"facade"一词指的是facade模式,它是来自著名书籍《design Patterns》(作者通常称为"四人帮")的结构设计模式。就像建筑物的正面对过路人隐藏了里面的东西一样,代码中的门面通过只公开某些方法来隐藏底层服务的复杂性。您经常会听到这种隐藏复杂性的方法被称为"添加抽象层"。抽象是一种更简单、更通用的东西模型,它只提供使用者需要知道的东西。外观模式,以及一般的抽象,类似于你和你的车之间的关系。你只需要知道,当你转动钥匙,踩下油门,你的车就会前进。为了去杂货店,你不需要关心发动机的基本力学原理或燃烧科学。下面是如何在图表中表示立面图案:来源你可以在这里看到客户对其他服务一无所知。它们简单地调用doSomething(),facade处理后台服务的工作。NgRx中的立面最近,关于是否使用NgRx的facade来隐藏诸如存储、操作和选择器之类的信息,有很多讨论。这是由thomasburleson的一篇文章所引发的,文章名为NgRx+Facades:betterstatemanagement。门面基本上就是一个角度服务,处理与商店的任何交互。当一个组件需要调度一个操作或获取选择器的结果时,它将转而在facade服务上调用适当的方法。该图说明了组件、立面和NgRx其余部分之间的关系:让我们看一个例子来更好地理解这一点。以下是我的NgRx认证教程示例代码中的BooksPageComponent(为了便于阅读,我将代码隐藏在Component decorator中)://src/app/books/组件/books-page.component.ts页从'@angular/core'导入{changedeptectionstrategy,Component,OnInit};{ngrx从商店导入;从'rxjs'导入{Observable};将*作为BooksPageActions从"../actions/books"导入-第页操作';从"../models/Book"导入{Book};从'../reducers'导入*as fromBooks;从'@app/auth/actions导入{Logout}/授权操作';@组件({/*…为了可读性而隐藏*/})导出类BooksPageComponent实现OnInit{books$:可观察;构造函数(私有存储:存储) {这个。书$ = 存储.管道(选择(从books.getAllBooks));}恩戈尼尼特(){本店配送(新的BooksPageActions.加载());}注销(){本店配送(new Logout());}}此组件导入存储、一些操作和一些减速器。它在ngOnInit期间分派加载操作,并在构造函数中使用books的选择器。当用户注销时,它还会发送一个操作。如果我们在组件中使用facade,那么该类将如下所示(为了简洁起见,我将省略imports和decorator)://src/app/books/组件/books-page.component.ts页//除进口货物外,上述内容不变导出类BooksPageComponent实现OnInit{books$:可观察;构造器(私有booksFacade:booksFacade){这个。书$ = 这是booksFacade.allBooks$;}恩戈尼尼特(){this.booksFacade.loadBooks();}注销(){this.booksFacade.logout();}}我们用booksFacade服务上的observate替换了选择器。我们还用booksFacade服务上的方法调用替换了这两个action分派。正面看起来像这样(为了简洁起见,再次省略了进口部分)://以上进口@可注射()出口类图书门面{allBooks$:可观察;构造函数(私有存储:存储) {这是所有的书$ = 存储.管道(选择(从books.getAllBooks));}getBooks(){本店配送(新的BooksPageActions.加载());}注销(){本店配送(new Logout());}}孤立地看组件代码,您可能不知道这个角度的应用程序正在使用NgRx进行状态管理。那么,这是好事还是坏事?让我们来谈谈这种方法的利弊。正面的情况让我们首先考虑一下NgRx的外观模式的一些优点。优点1:外观提供更好的开发体验。使用facade模式的最大理由之一是它对开发人员体验的提升。NgRx经常受到抨击,因为它需要大量重复的代码来进行设置,并且很难维护和缩放许多移动部件。每个功能都需要对状态、存储、操作、还原器、选择器和效果进行更改。通过在外观中添加抽象层,我们减少了直接与这些部分交互的需要。例如,一个新开发人员编写一个列出图书的新特性,只需注入BooksFacade并调用loadBooks(),而无需担心如何学习商店的复杂性。优点2:正面图案比普通NgRx更容易缩放。facade模式的第二个论据是伸缩性有多容易。例如,我们需要为一个大型应用程序开发七个新特性。其中一些特性可能在影响应用程序状态的某些方式上以及它们所使用的数据方面重叠。我们可以通过使用立面来减少大量重复性工作:首先,我们将根据独特的用例确定需要进行的最小数量的状态更改。下一步,我们将它们添加到应用程序范围的NgRx设置文件中的正确位置(比如对应用程序状态或reducer的更改)。最后,我们将适当的方法和选择器应用于我们的外观。这七个新功能可以快速添加,同时让门面担心潜在的NgRx部分。"在NgRx中使用facades可以提高开发效率,并使应用程序更易于扩展。"在推特上留言反对正面的案子这种减少了开发和缩放的摩擦听起来真的很棒,但一切都是美好的吗?让我们看看争论的另一面。缺点1:正面破坏了NgRx的间接性。当我第一次看到NgRx使用的外观时,我马上就有了一个反应:"等等,我们只是花了这么多时间来设置NgRx操作、还原器和效果,但现在我们用一个服务来隐藏所有这些?"事实证明,我的直觉是反对使用外墙的主要理由之一。虽然NgRx确实因为有很多活动部件而受到批评,但是这些部件中的每一个都被设计成执行特定功能并以特定方式与其他部件通信。NgRx的核心就像一个消息传递系统。当用户单击"loadbooks"按钮时,组件将发送一条消息(一个操作),该消息说:"嘿,加载一些图书!"这个效果会听到这个消息,从服务器获取数据,然后以动作的形式发送另一条消息:"Books are loaded!"reducer会听到此消息并将应用程序的状态更新为"Books loaded"我们称之为间接。间接寻址是指应用程序的一部分负责某些事情,而其他部分只是通过消息传递与它进行通信。减速器和特效都不知道被按下的按钮。同样,reducer也不知道数据来自何处或API端点的地址。当你在NgRx中使用立面时,你就避开了这个设计(至少在实践中)。facade现在知道调度操作和访问选择器。同时,开发应用程序的开发人员不再了解这种间接寻址。现在有一个新的服务可以呼叫。缺点2:外观可能导致重复使用操作。由于NgRx的间接性被绕过并隐藏在开发人员之外,重用动作变得非常诱人。这是立面模式的第二个主要缺点。假设我们正在处理图书应用程序。我们有两个用户可以添加新书的地方:1)图书列表和2)图书的详细信息页面。在facade中添加一个名为addBook()的方法,并使用它在这两个实例中分派相同的操作(类似于[Books]add Book)。然而,这将是不良行为卫生的一个例子。当我们在一两年后因为出现了一个bug而返回到这个代码中时,我们将不知道何时调试[Books]Add Book的来源。相反,我们最好还是听从迈克·瑞安(Mike Ryan)在《2018年ng conf talk Good Action Health》中的建议。最好使用动作来捕捉事件,而不是命令。在我们的例子中,我们的减速机可以有一个额外的例子:功能减速机(状态、动作){交换机(动作类型) {案例"[Books List]Add Book':案例"[Book Detail]Add Book':return[…状态,动作.book];违约:返回状态;}}在写动作的时候,我们总是希望专注于清晰而不是简洁。好的行动是一年后你可以阅读的行动,并告诉他们在哪里被派遣。当涉及到facade模式时,我们可以通过在facade中创建一个分派方法来缓解这个问题,而不是抽象出操作。在我们上面的示例中,而不是让一个通用的addBook()满足