Angular.jsのServiceとFactoryの違いを考える

  • 33
    いいね
  • 1
    コメント
この記事は最終更新日から1年以上が経過しています。

前回valueとfactoryの違いを考えたので、今回はServiceFactoryの違いを考えたいと思う。

違いはある?ない?

とりあえずFactoryを使っているという声も聞かれるが、例えば angular-ui/ng-gridGitHubのソースを見ると、下記のようなフォルダ構成になっていて、明示的に用途を分けている。

ng-grid_src_js_core_at_master_·_angular-ui_ng-grid_·_GitHub.png

どういう意図で分けているのか、まず、What is the difference between module.factory and module.service and how might both be applied?のスレッドに書かれてることを意訳したい。

Service

Services
Syntax: module.service( 'serviceName', function );
Result: When declaring serviceName as an injectable argument you will get an instance of the function. In other words new FunctionYouPassedToService().
Usage: Could be useful for sharing utility functions that are useful to invoke by simply appending () to the injected function reference.

Services
表記: module.service( 'serviceName', function );
結果: serviceNameを宣言した時点で、関数のインスタンスが生成される。別の書き方をするなら new FunctionYouPassedToService();
用法: 括弧"()"を付けるだけで参照したい共通関数などを共有する場合に適している。

Factory

Factories
Syntax: module.factory('factoryName', function);
Result: When declaring factoryName as an injectable argument you will be provided the value that is returned by invoking the function reference passed to module.factory.
Usage: Could be useful for returning a 'class' function that can then be new'ed to create instances.

Factories
表記: module.factory('factoryName', function);
結果: factoryNameを宣言した時点で、module.factoryに渡している関数がreturnしている値が提供される。
用法: newでインスタンス化したいクラスがある場合に適している。

つまり

クラス化せずに、共通関数の束として使いたい場合はService。クラス化した方が便利なのであればFactoryということらしい。

サンプルソース

足し算と引き算をする簡単な例を作ってみる。

index.html
<!doctype html>
<html lang="jp" ng-app="App">
<head>
  <meta charset="utf-8">
  <script src="bower_components/angular/angular.js"></script>
  <script src="app.js"></script>
</head>
<body>
<div ng-controller="Ctrl">
  3+2-1={{answer_service}}<br/>
  3+2-1={{answer_factory}}
</div>
</body>
</html>
app.js
angular.module('App',[])
  .service('MyUtils', function(){
    var service = {
      add: function(a,b){ return a+b; },
      sub: function(a,b){ return a-b; }
    };
    return service;
  })
  .factory('MyMath', function(){
    function MyKlass(n){ this.n = n; }
    MyKlass.prototype.add = function(a){ this.n += a; return this; };
    MyKlass.prototype.minus = function(a){ this.n -= a; return this; };
    return MyKlass;
  })
  .controller('Ctrl',
    ["$scope", "MyUtils", "MyMath",
      function($scope, MyUtils, MyMath){
        // 関数群として呼び出す - Service
        $scope.answer_service = MyUtils.sub(MyUtils.add(3,2),1);
        // クラスとして呼び出す - Factory
        $scope.answer_factory = (new MyMath(3)).add(2).minus(1).n;
      }
    ]
  );