Angular
service
factory

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

More than 3 years have passed since last update.

前回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;
}
]
);