Javascript 什么是「;“装饰师”;它们是如何使用的?

Javascript 什么是「;“装饰师”;它们是如何使用的?,javascript,angularjs,decorator,angularjs-decorator,Javascript,Angularjs,Decorator,Angularjs Decorator,我很好奇AngularJS的装饰师到底是什么。对于装饰者来说,网上没有太多的信息,除了在文章中的一个简介和在文章中的一个简短(尽管很有趣)的提及 正如那些有棱角的家伙所说,装饰师是: 装饰服务,允许装饰者拦截服务 实例创建。返回的实例可能是原始实例, 或委托给原始实例的新实例 我真的不知道这意味着什么,我也不知道为什么要将此逻辑与服务本身分开。例如,如果我想在不同的条件下返回不同的内容,我只需将不同的参数传递给相关函数,或者使用另一个共享该私有状态的函数 我仍然是一个AngularJS noob

我很好奇AngularJS的装饰师到底是什么。对于装饰者来说,网上没有太多的信息,除了在文章中的一个简介和在文章中的一个简短(尽管很有趣)的提及

正如那些有棱角的家伙所说,装饰师是:

装饰服务,允许装饰者拦截服务 实例创建。返回的实例可能是原始实例, 或委托给原始实例的新实例

我真的不知道这意味着什么,我也不知道为什么要将此逻辑与服务本身分开。例如,如果我想在不同的条件下返回不同的内容,我只需将不同的参数传递给相关函数,或者使用另一个共享该私有状态的函数


我仍然是一个AngularJS noob,所以我确信这只是我的无知和/或坏习惯。

提供$provide.decorator的一个很好的用例是当你需要对你的模块所依赖的第三方/上游服务做一些小的“调整”时,而不改变服务(因为您不是服务的所有者/维护者)。这是在plunkr上的一个演示。

装饰器允许我们分离横切关注点,并允许服务保留单一责任原则,而无需担心“基础架构”代码

装饰师的实际用途:

  • 缓存:如果我们有一个可能进行昂贵的HTTP调用的服务,我们可以将该服务包装在缓存装饰器中,该装饰器在进行外部调用之前检查本地存储
  • 调试/跟踪:根据您的开发/生产配置设置一个开关,该开关使用调试或跟踪包装来装饰您的服务
  • 节流:将频繁触发的调用包装在去抖动包装器中。例如,允许我们轻松地与速率受限的服务交互

在所有这些情况下,我们将服务中的代码限制在其主要职责范围内。

decorator
可以截取由
工厂、服务、价值、提供者创建的服务实例,并提供更改一些
实例(服务)
的选项,这些实例(服务)
在其他情况下无法配置/使用选项


它还可以提供用于测试目的的模型实例,例如
$http

,简单地说,我们可以说它类似于一个扩展方法。例如,我们有一个类,它有两个方法,在运行时,我们想在其中添加更多的方法,然后使用Decorator


我们无法将$Provider.decorator与常量一起使用,因为我们无法更改它们使用的是只读属性的常量。

简而言之,decorator可以描述如下:-

decorator函数拦截服务的创建,允许 重写或修改服务的行为

它通过angular使用
$provide
服务,并修改或替换其他服务的实现

$provide.decorator('service to decorate',['$delegate', function($delegate) {
  // $delegate - The original service instance, 
  //             which can be replaced, monkey patched, 
  //             configured, decorated or delegated to. 
  //             ie here what is there in the 'service to decorate'

  //   This function will be invoked, 
  //   when the service needs to be provided 
  //   and should return the decorated service instance.
  return $delegate;
}]);
例如:

$provide.decorator('$log', ['$delegate', function($delegate) {
  // This will change implementation of log.war to log.error
  $delegate.warn = $delegate.error; 
  return $delegate;
}]);
应用程序

除了@JBland answer

  • 应用程序范围的区域设置:-

    你可以找到一个例子

  • 通过角度服务更改服务的默认行为和现有实现:-

    你可以找到一个朋友

  • 函数在不同环境中的切换行为


很好的例子。我实际上想知道如何扩展第三方模块的功能而不去干涉它们。装饰器实际上会键入一个服务的所有实例,还是只限于装饰它们的模块?换句话说,假设我有模块a装饰模块B的服务。然后我有模块C,这取决于关于模块A和模块B。在模块C内部,模块B提供的服务是原始版本还是经过修饰的版本?@JonJaques-这是一个很好的问题。我没有遇到过这种情况。如果让我猜猜,模块C看到的服务版本应该是模块A提供的经过修饰的版本,但在我亲自尝试之前,我不能肯定这一点。你为什么不写一个简单的plunkr/JSFidle并用它进行实验。如果你能与我们分享你的发现,那将是非常棒的。干杯。@JonJaques-无法抑制我的好奇心,所以我在我的原始示例中添加了几行来找到你问题的答案。简言之,我之前评论中的猜测是正确的。工厂、服务等。是单例(如提供的),因此一旦修饰,总是修饰。值得注意的是,您还可以覆盖
指令
定义,因为这里是官方文档中的参考: