什么是“装饰器”?如何使用?


148

我很好奇AngularJS中的装饰器到底是什么。除了AngularJS文档中的简短内容youtube视频中的简短提及(尽管很有趣)之外,装饰者在线上没有太多信息。

正如Angular所说的那样,装饰器是:

装饰服务,允许装饰者截取服务实例的创建。返回的实例可以是原始实例,也可以是委派给原始实例的新实例。

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

我仍然是AngularJS菜鸟,所以我敢肯定,这只是我的愚昧和/或坏习惯。

Answers:


219

一个很好的用例$provide.decorator是,当您需要对模块所依赖的某些第三方/上游服务进行较小的“调整”时,保持服务不变(因为您不是该服务的所有者/维护者)。是关于plunkr的演示。


6
很棒的例子。我实际上是在想如何扩展第三方模块的功能而不干预它们
Arthur Kovacs 2014年

5
装饰器实际上是对服务的所有实例进行鸭式打印吗,还是仅将它们限定为装饰它们的模块?换句话说,假设我有模块A装饰了模块B的服务。然后,我有了模块C依赖于模块A和模块B。在模块C内,模块B的服务是原始版本还是修饰版本?
乔恩·雅克

3
@JonJaques-这是一个很好的问题。我还没有遇到过这种情况。如果我猜到了,模块C看到的服务版本应该是模块A修饰后的版本,但是直到我自己尝试之前,我不能肯定地说出来。您为什么不编写一个简单的plunkr / jsffidle并尝试一下呢?如果您可以与我们分享您的发现,那就太好了。干杯。
tamakisquare

6
@JonJaques-无法抑制我的好奇心,因此我在原始示例中添加了几行内容,以找到您的问题的答案link。简而言之,我之前的评论中的猜测是正确的。
tamakisquare

17
工厂,服务等是单例(按提供),因此一旦装饰,就始终装饰。
FlavorScape 2014年

66

装饰器使我们能够分离出跨领域的问题,并允许服务保留单一职责原则,而无需担心“基础结构”代码。

装饰器的实际用途:

  • 缓存:如果我们有一个服务可能进行昂贵的HTTP调用,则可以将该服务包装在一个缓存装饰器中,该装饰器在进行外部调用之前会检查本地存储。
  • 调试/跟踪:根据您的开发/生产配置进行切换,以调试或跟踪包装器装饰服务。
  • 节流:将经常触发的呼叫包装在一个防反弹包装器中。例如,使我们能够轻松地与限速服务进行交互。

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


10

decorator可以拦截由创建的服务实例factory, service, value, provider,并提供选项来更改某些instance(service)原本无法配置的选项。

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


1
值得注意的是,您还可以覆盖Ben Nadeldirective
David Salamon

以下是Angular官方文档中的参考:https
David Salamon

3

简单来说,我们可以说这就像是扩展方法。对于前 我们有一个类,它有两个方法,在运行时,我们想在其中添加更多的方法,然后再使用Decorator。

我们不能将$ provide.decorator与常量一起使用,因为我们无法更改它们具有只读属性的常量。


1

简而言之,装饰器可以描述如下:

装饰器功能拦截服务的创建,从而允许其覆盖或修改服务的行为。

$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答案。

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

    你可以在这里找到一个例子

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

    你可以在这里找到一个样品

  • 功能在不同环境中的切换行为。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.