AngularJS中的非单身人士服务

Und*_*ion 89 service singleton factory instance angularjs

AngularJS在其文档中明确指出服务是单身人士:

AngularJS services are singletons
Run Code Online (Sandbox Code Playgroud)

与直觉相反,module.factory也返回一个Singleton实例.

鉴于非单例服务有很多用例,实现工厂方法返回服务实例的最佳方法是什么,这样每次ExampleService声明一个依赖项时,它都会被一个不同的实例所满足ExampleService

Jon*_*mbo 77

我不完全确定你试图满足的用例.但是可以有一个对象的工厂返回实例.您应该能够根据自己的需要进行修改.

var ExampleApplication = angular.module('ExampleApplication', []);


ExampleApplication.factory('InstancedService', function(){

    function Instance(name, type){
        this.name = name;
        this.type = type;
    }

    return {
        Instance: Instance
    }

});


ExampleApplication.controller('InstanceController', function($scope, InstancedService){
       var instanceA = new InstancedService.Instance('A','string'),
           instanceB = new InstancedService.Instance('B','object');

           console.log(angular.equals(instanceA, instanceB));

});
Run Code Online (Sandbox Code Playgroud)

的jsfiddle

更新

考虑以下非单身人士服务请求.Brian Ford在其中指出:

所有服务都是单例的想法并不能阻止你编写可以实例化新对象的单例工厂.

和他从工厂返回实例的例子:

myApp.factory('myService', function () {
  var MyThing = function () {};
  MyThing.prototype.foo = function () {};
  return {
    getInstance: function () {
      return new MyThing();
    }
  };
});
Run Code Online (Sandbox Code Playgroud)

我还认为他的例子很优越,因为你不必new在控制器中使用关键字.它封装在getInstance服务的方法中.

  • 为什么使用新运算符不好?我觉得如果你的目标是非单身人士,那么使用"new"是声明性的,并且很容易立即告诉我们哪些服务是单身,哪些服务不是.基于是否正在创建对象. (4认同)

Jos*_*ler 44

我不认为我们应该有一个工厂返回一个new能力函数,因为这开始打破依赖注入,并且库将表现得很尴尬,特别是对于第三方.简而言之,我不确定非单件服务是否有任何合法用例.

完成同样事情的更好方法是使用工厂作为API来返回附加了getter和setter方法的对象集合.下面是一些伪代码,展示了如何使用这种服务:

.controller( 'MainCtrl', function ( $scope, widgetService ) {
  $scope.onSearchFormSubmission = function () {
    widgetService.findById( $scope.searchById ).then(function ( widget ) {
      // this is a returned object, complete with all the getter/setters
      $scope.widget = widget;
    });
  };

  $scope.onWidgetSave = function () {
    // this method persists the widget object
    $scope.widget.$save();
  };
});
Run Code Online (Sandbox Code Playgroud)

这只是用于按ID查找窗口小部件然后能够保存对记录所做的更改的伪代码.

这是服务的一些伪代码:

.factory( 'widgetService', function ( $http ) {

  function Widget( json ) {
    angular.extend( this, json );
  }

  Widget.prototype = {
    $save: function () {
      // TODO: strip irrelevant fields
      var scrubbedObject = //...
      return $http.put( '/widgets/'+this.id, scrubbedObject );
    }
  };

  function getWidgetById ( id ) {
    return $http( '/widgets/'+id ).then(function ( json ) {
      return new Widget( json );
    });
  }


  // the public widget API
  return {
    // ...
    findById: getWidgetById
    // ...
  };
});
Run Code Online (Sandbox Code Playgroud)

虽然未包含在此示例中,但这些灵活的服务也可以轻松管理状态.


我现在没有时间,但是如果它会有所帮助,我可以稍后组合一个简单的Plunker进行演示.

  • @JoshDavidMiller你能说明为什么/什么会"破坏依赖注入和[为什么/什么]库会表现得很笨拙"? (15认同)
  • @Pedr抱歉,我忘了这件事.这是一个超级简单的演示:http://plnkr.co/edit/Xh6pzd4HDlLRqITWuz8X (4认同)

Evg*_*nii 20

另一种方法是使用复制服务对象angular.extend().

app.factory('Person', function(){
  return {
    greet: function() { return "Hello, I'm " + this.name; },
    copy: function(name) { return angular.extend({name: name}, this); }
  };
});
Run Code Online (Sandbox Code Playgroud)

然后,例如,在您的控制器中

app.controller('MainCtrl', function ($scope, Person) {
  michael = Person.copy('Michael');
  peter = Person.copy('Peter');

  michael.greet(); // Hello I'm Michael
  peter.greet(); // Hello I'm Peter
});
Run Code Online (Sandbox Code Playgroud)

这是一个插件.


小智 8

我知道这篇文章已经得到了解答,但我仍然认为有一些合法的场景需要非单身人士服务.假设有一些可重用的业务逻辑可以在几个控制器之间共享.在这种情况下,放置逻辑的最佳位置是服务,但是如果我们需要在可重用逻辑中保留一些状态呢?然后我们需要非单一服务,因此可以在app中的不同控制器之间共享.这就是我实现这些服务的方式:

angular.module('app', [])
    .factory('nonSingletonService', function(){

        var instance = function (name, type){
            this.name = name;
            this.type = type;
            return this;
        }

        return instance;
    })
    .controller('myController', ['$scope', 'nonSingletonService', function($scope, nonSingletonService){
       var instanceA = new nonSingletonService('A','string');
       var instanceB = new nonSingletonService('B','object');

       console.log(angular.equals(instanceA, instanceB));

    }]);
Run Code Online (Sandbox Code Playgroud)