說明:兩篇文章均是老外寫的文章呀潭,由高手翻譯而成,個人感覺很不錯至非,引用在此钠署。感謝原作者。
注釋:單體是一種設(shè)計(jì)模式荒椭,它限制了每一個類僅能夠?qū)嵗癁橐粋€對象谐鼎。無論我們在什么地方注入我們的service,將永遠(yuǎn)使用同一個實(shí)例趣惠。
第一篇:
幾種不同類型的Services狸棍。Angular中有幾種不同類型的services。每一種都有自己的獨(dú)特用法信卡。
Constant#
列子:
app.constant('fooConfig',{
config1: true,
config2: "Default config2"
});
Constant是一個非常有用的service隔缀,她經(jīng)常被用來在指令中提供默認(rèn)配置。因此如果你正在創(chuàng)建一個指令傍菇,并且你想要再給指令傳遞可選參數(shù)的同時(shí)進(jìn)行一個默認(rèn)配置猾瘸,一個Constant就是一個好辦法。
作為一個constant,我們放入其中的值將不會改變。Constant service 基本上會是一個基本類型的值或者是一個對象牵触。
value
列子:
app.value('fooConfig',{
config1: true,
config2: "Default config2 but it can change"
});
一個value service有點(diǎn)像是一個constant但是它是可以被改變的淮悼。它也經(jīng)常被用在一個指令上面,來進(jìn)行配置揽思。一個value service有點(diǎn)像是一個factory service的縮小版袜腥,它經(jīng)常用來保存值但是我們不能在其中對值進(jìn)行計(jì)算。
我們可以使用angular對象的extend方法來改變一個value service:
app = angular.module("app", []);
app.controller('MainCtrl', function($scope, fooConfig) {
$scope.fooConfig = fooConfig;
angular.extend(fooConfig, {config3: "I have been extended"});
});
app.value('fooConfig', {
config1: true,
config2: "Default config2 but it can changes"
});
Factory
列子:
app.factory('foo', function() {
var thisIsPrivate = "Private";
function getPrivate() {
return thisIsPrivate;
}
return {
variable: "This is public",
getPrivate: getPrivate
};
});
// or..
app.factory('bar', function(a) {
return a * 2;
});
Factory service是最普通使用的service.它同樣也是非常容易理解钉汗。
一個Factory是一個能狗返回任何數(shù)據(jù)類型的service羹令。對于你如何創(chuàng)建它并沒有什么可選項(xiàng),你僅僅需要在其中返回一些東西即可损痰。
正如前面所說福侈,所有的service類型都是單體,因此如果我們在一個地方修改了foo.variable卢未,其他的地方也會相應(yīng)發(fā)生改變肪凛。
Service
列子:
app.service('foo', function() {
var thisIsPrivate = "Private";
this.variable = "This is public";
this.getPrivate = function() {
return thisIsPrivate;
};
});
Service service 和 factory差不多。它們之間的區(qū)別在于service會接收一個構(gòu)造器辽社,因此當(dāng)你第一次使用它的時(shí)候伟墙,它將會自動運(yùn)行new
Foo()
來實(shí)例化一個對象。一定要記住如果你在其他的地方也使用了這個service滴铅,它將返回同一個對象戳葵。
事實(shí)上,上面的代碼和下面的代碼等價(jià):
app.factory('foo2', function() {
return new Foobar();
});
function Foobar() {
var thisIsPrivate = "Private";
this.variable = "This is public";
this.getPrivate = function() {
return thisIsPrivate;
};
}
Foobar
是一個類汉匙,我們在首次使用它的時(shí)候在我們的factory中將它實(shí)例化然后將它返回譬淳。和service一樣,F(xiàn)oobar將只會實(shí)例化一次然后下次當(dāng)我們再次使用factory時(shí)它將返回同一個實(shí)例盹兢。
如果我們已經(jīng)有了一個類邻梆,并且我們想將它用在service中,我們只需要編寫如下的代碼:
app.service('foo3',Foobar);
Provider
Provider是factory的加強(qiáng)版绎秒。事實(shí)上浦妄,上一個例子中的factory代碼等價(jià)于下面的provider代碼:
app.provider('foo', function() { var thisIsPrivate = "Private"; return { setPrivate: function(newVal) { thisIsPrivate = newVal; }, $get: function() { function getPrivate() { return thisIsPrivate; } return { variable: "This is public", getPrivate: getPrivate }; } };});app.config(function(fooProvider) { fooProvider.setPrivate('New value from config');});
在這里我們將thisIsPrivate移到了我們的$get函數(shù)的外面,然后我們創(chuàng)建了一個setPrivate來在一個config函數(shù)中修改thisIsPrivate见芹。為什么我們需要這樣做剂娄?這難道不比在factory中添加setter要容易嗎?除此之外玄呛,還有另外一個原因阅懦。
在這里我們將thisIsPrivate移到了我們的$get函數(shù)的外面,然后我們創(chuàng)建了一個setPrivate來在一個config函數(shù)中修改thisIsPrivate徘铝。為什么我們需要這樣做耳胎?這難道不比在factory中添加setter要容易嗎惯吕?除此之外,還有另外一個原因怕午。
要注意到我們在config函數(shù)中放入的是nameProvider
而不是name
废登。在這里,我們實(shí)際上還是對name
進(jìn)行配置郁惜。
看到這里我們其實(shí)已經(jīng)意識到了我們已經(jīng)在應(yīng)用中進(jìn)行過一些配置了堡距,像是$routeProvider
以及$locationProvider
,兩者分別用來配置我們的路由了HTML5模式兆蕉。
Decorator
那么現(xiàn)在已經(jīng)決定要使用前面的 foo service羽戒,但是其中還是缺少一個你想要的greet
函數(shù)。你可以修改factory嗎虎韵?答案是不行半醉!但是你可以裝飾它:
app.config(function($provide){ $provide.decorator('foo',function($delegate){ $delegate.greet = function(){ return "Hello, I am a new function of 'foo'"; } });});
$provide是Angular用來在內(nèi)部創(chuàng)建我們的service的東西。如果我們想要使用它的話可以手動來使用它或者僅僅使用在我們的模塊中提供的函數(shù)(我們需要使用$provide來進(jìn)行裝飾)劝术。$provide有一個函數(shù),decorator呆奕,它讓我們可以裝飾我們的service养晋。它接收我們想要裝飾的service的名字并且在回調(diào)函數(shù)中接收一個$delegate來代表我們實(shí)際上的service實(shí)例。
在這里我們可以做一切我們想要的事情來裝飾我們的service梁钾。在上面的例子中绳泉,我們?yōu)槲覀冊瓉淼膕ervice添加了一個greet函數(shù)。接著我們返回了修改后的service姆泻。
經(jīng)過修改以后零酪,現(xiàn)在我們的factory中已經(jīng)有了一個叫做greet的函數(shù)。
裝飾一個service的能力是非常實(shí)用的拇勃,尤其是當(dāng)我們想要使用第三方的service時(shí)四苇,此時(shí)我們不需要將代碼復(fù)制到我們的項(xiàng)目中,而只需要進(jìn)行一些修改即可方咆。
注意:constant service不能被裝飾月腋。
創(chuàng)建一個實(shí)例
我們的services都是單體但是我們可以創(chuàng)建一個單體factory來創(chuàng)建新的實(shí)例。在你深入之前瓣赂,記住Angular中的服務(wù)都是單體并且我們不想改變這一點(diǎn)榆骚。但是,在極少數(shù)的情況下你需要生成一個新的實(shí)例煌集,你可以像下面這樣做:
//我們的類
function Person(json){
angular.extend(this,json);
}
Person.prototype = {
update: function(){
//更新內(nèi)容
this.name = "Dave";
this.country = "Canada";
}
};
Person.getById = function(id){
//由id來獲取一個Person的信息
return new Person({
name: "Jesus",
country: "Spain"
});
};
//我們的factory
app.factory('personService',function(){
return {
getById: Person.getById
};
});
在這里我們創(chuàng)建了一個Person
對象妓肢,它接收一些json數(shù)據(jù)來初始化對象。然后我們在我們的原型(原型中的函數(shù)可以被Person的實(shí)例所用)中創(chuàng)建了一個函數(shù)苫纤,并且在Person上直接創(chuàng)建了一個函數(shù)(就像是類函數(shù)一樣)碉钠。
因此現(xiàn)在我們擁有了一個類函數(shù)纲缓,它將基于我們提供的id來創(chuàng)建一個新的Person
對象,并且每一個對象都可以自我更新》徘眨現(xiàn)在我們僅僅需要創(chuàng)建一個能夠使用它的service色徘。
當(dāng)每次我們調(diào)用personService.getById時(shí),我們都在創(chuàng)建一個新的Person對象操禀,因此你可以在不同的控制器中使用這個service褂策,即便當(dāng)factory是一個單體,它也能生成新的對象颓屑。
總結(jié)
Service是Angular中最酷的特性之一斤寂。我們可以使用很多方法來創(chuàng)造它們,我們僅僅需要找到符合我們需求的方法然后實(shí)現(xiàn)它揪惦。
原文:鏈接