Angular2.0の足音がだんだん聞こえてくるけど、1.x系でserviceとfactoryの違いにハマったのでメモ
factory | service | |
---|---|---|
何を定義? |
値を返す関数を定義 値にはオブジェクトも含む |
関数を定義 オブジェクトのコンストラクタを定義とも言える |
何までOK? | 値は数値、文字列、 オブジェクト、関数...なんでもOK |
関数以外は不可 |
引数依存は? DIのこと | 可能 | 可能 |
どういう時に使う? | 文字列や数値を返したい ・他Angular moduleとインスタンスを共有したい |
便利メソッドを集めたい・初期化処理が欲しい・class(typeScript/ES6)を使いたい |
1.DIのこと $dependencyName
と引数名書くと、そのServiceとかをAngularが自動で入れてくれる依存性解決のやつ
コード(実例)を見る
以下はぶっちゃけ同じ
serviceAndFactory.js
// 独自オブジェクトのコンストラクタを定義(実際は無名関数が多い)
var myObjConstructor = function(){
this.Hello = function(){ console.log("Hello!"); }
this.Do = function(task){ console.log(task + "is done!"); }
//prototypeで拡張した関数を呼ぶ
this.ProtoMethod();
}
//prototypeで拡張
myObjConstructor.prototype.ProtoMethod = function(){
console.log("Prototype Method");
return 42; //人生、宇宙、すべての答えである数字
}
//使うとき(angular関係ない一般例)
var myObj = new myObjConstructor();
// ----------
var myModule = angular.module("myModule", []);
// サービスを定義。コンストラクタの関数を呼ぶ。自動で new myConstructor() される
myModule.service("myService", myObjConstructor);
// ファクトリーを定義。 new myConstructor() は自分でやる
myModule.factory("myFactory_1",
function(){
return new myObjConstructor();
}
);
// ファクトリーは、他でnewしたインスタンスを渡してもOK
var myInstance = new myObjConstructor();
myModule.factory("myFactory_2", function(){ return myInstance; });
どれも、controllerとかでDIツール経由で入ってくるものは同じように使える。
使用例
myModule
.controller('myCtrl', function(myService, myFactory_1){
if(myService.ProtoMethod() == myFactory_1.ProtoMethod()){
console.log("Wow! 42!"); //必ずここを通るはず
}
});
serviceとfactoryを間違えた場合
なんか動かないな???というとき…
TypeError: this.ProtoMethod is not a function
とか
Error: [$injector:undef] Provider 'myService' must return a value from $get factory method.
とか言われていたら、おそらく factoryとserviceを間違えています。
ダメな例
myModule.factory("myService", myObjConstructor); // factoryに値を返さない関数を渡している
とりあえず動く例
myModule.factory("myService", function(){ return new myObjConstructor() }); // 良いが冗長。
より良い例
myModule.service("myService", myObjConstructor); //"とりあえず動く例"でやっていた `return new...`部をAngularに任せている
service と factory 同じじゃね? 文字数少ないぶんserviceがよくね??
前述の例ではそうだけど、 オブジェクト(コンストラクタ関数)以外でも登録できる のがメリットのときもある…かも。
factoryでしか出来ないこと
myModule
.factory('httpPromise', function($http){
// Promise を直接返すとか
return $http().jsonp("http://jsonplaceholder.typicode.com/posts/1")
})
.factory('myValue', function(){
// 非常に複雑な計算が必要だけど、1度計算したら使いまわしてOKな値とか…
// 省略: 複雑な計算
return 42;
})
.factory('myFunc', function(){
// オブジェクトでなく関数を渡す
return function(name){ console.log("hello, " + name); };
})
.controller('myCtrl2', function(httpPromise, myValue, myFunc){
// Promiseを受け取って通信完了したら処理
httpPromise.success(function(data){ console.log(data); })
//複雑な計算結果だけ受け取る
console.log(myValue);
//関数を使う(valueレシピでもいいのでは)
myFunc("Taro");
})