Max Koretskyi
Max Koretskyi

Reputation: 105547

when to use factory and when to use service - counter approach is suggested in a book

I'm reading this book about angular's services. When summarizing about when to use service and factory methods of provider the author states the following:

The service method should be used if you define your services as a class and need to invoke the definition's constructor function. Use the factory method if you define your service as an object instance and do not need to invoke a constructor.

I'm wondering whether this is a typo or I have been misusing them. I've always used the factory method to get constructors and service when I needed instances.

EDIT:

For example, I have a validator service and each controller in the app should have it's own instance. I define it as a class:

function ValidatorService() {
    this.addErrorRule = function (event, rule) {};
    this.validate = function (values) {}
}

Now, I would define it in the angular system using factory method like this:

angular.module("validation").factory('ValidatorService', function () {
    return ValidatorService;
});

Whenever a controller requires ValidatorService it will be provided with the constructor from which a service can be instantiated.

But according to the quote:

The service method should be used if you define your services as a class and need to invoke the definition's constructor function.

I should have done like this:

angular.module("validation").service('ValidatorService', ValidatorService);

But in this case angular will instantiate one instance of the service which will be shared among all controllers.

Upvotes: 0

Views: 125

Answers (3)

Akkuma
Akkuma

Reputation: 2265

I'm going to take a different approach to answer your question. I believe the code can be improved to fit into a service and achieve the recommendation you quoted of:

The service method should be used if you define your services as a class and need to invoke the definition's constructor function.

Rather than creating instances of a ValidatorService that requires rules be added to the instance to run validation on, you should try a more functional approach.

function ValidatorService() {
  this.validate = function(rules, values) {
    //Loop over rules/values
    return Math.random() * 10 //used only to show that validates are independent;
  };
}

angular
  .module('test', [])
  .service('validator', ValidatorService)
  .factory('validatorFac', function () {
    return function (rules, values) {
        return Math.random() * 10; //used only to show that validates are independent;
    };
  })
  .controller('TestController', ['$scope', 'validator', function($scope, validator) {
    $scope.isValid = validator.validate([],[])
  }])
  .controller('AnotherTestController', ['$scope', 'validator', function($scope, validator) {
    $scope.isValid = validator.validate([],[])
  }])
  .controller('TestFacController', ['$scope', 'validatorFac', function($scope, validatorFac) {
    $scope.isValid = validatorFac([],[])
  }])
  .controller('AnotherTestFacController', ['$scope', 'validatorFac', function($scope, validatorFac) {
    $scope.isValid = validatorFac([],[])
  }]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test">
  <div ng-controller="TestController">
    <p>Is Valid: {{ isValid }}</p>
  </div>
  <div ng-controller="AnotherTestController">
    <p>Is Valid: {{ isValid }}</p>
  </div>
  <div ng-controller="TestFacController">
    <p>Is Valid: {{ isValid }}</p>
  </div>
  <div ng-controller="AnotherTestFacController">
    <p>Is Valid: {{ isValid }}</p>
  </div>
</div>

As you can see the service and factory approaches are essentially identical. The benefits for this functional approach I'm advocating that works for either service or factory is that you should reduce garbage collection by instantiating less objects, it should be the faster implementation by never instantiating, and there is no state maintained.

Ultimately, to answer your question, you weren't misusing service or factory. Rather, the documentation you quoted appears to expect you to not maintain state within the service directly, since it is a singleton. My recommendation would be to change your code moving forward to behave more like this as you'll probably fit the "angular way" better.

Upvotes: 1

Chandermani
Chandermani

Reputation: 42669

In a Angular service recipe the function passed is invoked like a constructor function and that is what the author is referring to when he says

The service method should be used if you define your services as a class and need to invoke the definition's constructor function.

Whereas for a factory, the framework executes the recipe function and the return value is cached and returned every time you inject the service.

Normally factories are used to return objects but for your factory recipe implementation the return value is a constructor function and hence your interpretation is different from what the author explains.

Upvotes: 1

Michal Kucaj
Michal Kucaj

Reputation: 691

accepted From the AngularJS mailing list I got an amazing thread that explains service vs factory vs provider and their injection usage. Compiling the answers:

Services

Syntax: module.service( 'serviceName', function ); Result: When declaring serviceName as an injectable argument you will be provided with an instance of the function. In other words new FunctionYouPassedToService().

Factories

Syntax: module.factory( 'factoryName', function ); Result: When declaring factoryName as an injectable argument you will be provided with the value that is returned by invoking the function reference passed to module.factory.

Providers

Syntax: module.provider( 'providerName', function ); Result: When declaring providerName as an injectable argument you will be provided with ProviderFunction().$get(). The constructor function is instantiated before the $get method is called - ProviderFunction is the function reference passed to module.provider.

Providers have the advantage that they can be configured during the module configuration phase.

Upvotes: 1

Related Questions