Angularjs 創建services的幾種方式

原文地址:http://www.cnblogs.com/whitewolf/p/angular-services.html

      Angular帶來了很多類型的services。每個都會它自己不同的使用場景。我們將在本節來闡述。

   首先我們必須記在心裏的是所有的services都是singleton(單例)的,這也是我們所希望得到的預期結果。

下面讓我開始今天的services之旅吧:

Constant

示例:

複製代碼
app.constant('fooConfig', {

config1: true,

config2: "Default config2"

});
複製代碼

 

     constant是個很有用的東東,我們經常會用於對directive之類的做配置信息。所以當你想創建一個directive,並且你希望能夠做一些配置信息,同時給些默認的配置,constant是個不錯的的選擇。

     constant可以譯作常量,因爲我們所設置的值value是不能被改變的。其可以接受基礎類型和object對象。

Value

示例:

複製代碼
app.value('fooConfig', {

config1: true,

config2: "Default config2 but it can changes"

});
複製代碼

      Value和上面的constant很相似,唯一是其在賦值後還可以被改變。它也被常用於directive配置信息。Value service只會保留values,我們不會在service中計算其值。


Factory

示例:

複製代碼
app.factory('foo', function() {

var thisIsPrivate = "Private";

function getPrivate() {

return thisIsPrivate;

}



return {

variable: "This is public",

getPrivate: getPrivate

};

});
複製代碼

 

     Factory是我們最常用的service。其很容易被理解。

     factory會返回一個object對象,至於你如何創建這個對象angular沒任何限制。在示例中我選擇了我喜歡的模式 Revealing module pattern,你可以選擇其他你所希望的方式。

   如我之前所說,所有的services都是singleton的,所以當我們修改foo.variable的時候,會影響到其他使用的地方。

Service

示例:

複製代碼
app.service('foo', function() {

var thisIsPrivate = "Private";

this.variable = "This is public";

this.getPrivate = function() {

return thisIsPrivate;

};

});
複製代碼

 

   Service servicefactory工作原理一樣,只是他service接收的是一個構造函數,當第一次使用service的時候,angularnew Foo() 來初始化這個對象。以後的時候返回的都是同一個對象。

  實際上,下面是factory等價的寫法:

複製代碼
app.factory('foo2', function() {

return new Foobar();

});

function Foobar() {

var thisIsPrivate = "Private";

this.variable = "This is public";

this.getPrivate = function() {

return thisIsPrivate;

};

}
複製代碼

 

    Foobar是一個class()factory中我們手動初始化它,在返回它。和service一樣Foobar class只在第一次初始化,並以後返回的都是同一個對象。

如果我們已經存在了一個class,那麼我可以直接使用:

app.service('foo3', Foobar);

 

Provider

     Provider angular中是個最終的高級選項,在上例factory中最後一個示例用provider將是如下:

複製代碼
app.provider('foo', function() {

return {

$get: function() {

var thisIsPrivate = "Private";

function getPrivate() {

return thisIsPrivate;

}

return {

variable: "This is public",

getPrivate: getPrivate

};

}

};

});
複製代碼

 

    provider帶有一個$get的函數,其返回值將會被注入其他應用組件。所以我們注入foocontroller,我們注入的是$get 函數。

爲什麼我們還需要providerfactory實現不是更簡單嗎?這是因爲我們能夠在config 函數中配置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函數,我們創建了一個setPrivate函數,使其能夠在config函數中修改thisIsPrivate變量。爲什麼我們需要這麼做?在factory中加入一個setter不就好了嗎?這是一個不同的意圖。

   我們希望注入的是一個object對象,但是我們也希望能夠提供一種方式去配置它。例如:一個包裝了jsonp的資源resourceservice,我們希望能夠配置是從那個url獲取資源,我們也將有個三方的消費者比如restangular允許我們去配置達到我們的目的。

   注意在config函數我們需要用nameProvider替代name,然而消費者只需要用name

   可以看見在在我們的應用程序中已經配置了一些services,比如$routeProvider,$locationProvider,配置我們的routeshtml5model 調整適應。


額外的福利:

福利1:裝潢器Decorator

如果你覺得我給你的foo service缺少了你所需要的greet方法,你需要改變API嗎?不,你可以用更好的方法裝潢:

複製代碼
app.config(function($provide) {

$provide.decorator('foo', function($delegate) {

$delegate.greet = function() {

return "Hello, I am a new function of 'foo'";

};


return $delegate;

});

});
複製代碼

 

    上例中$provideangular內部用於創建我們所有serviceservice。如果我們希望在我們的應用程序中使用,我們可以手動的使用它(我們可以用$provide去裝潢)$provide有一個decorator的裝潢函數,允許我們裝潢我們的services,它接受我們所需要裝潢的servicename和一個接受$delegate的回調函數,$delegate代表我們的原來的service實例。

   在這裏我們可以裝潢我們的service。在本例中我們在原來的service實例上增加了一個greet函數,在返回修改過後的service當我們消費這個service的時候,它將會包含一個greet的函數,你可以在下面的try it中看見。

   對於使用來自第三方的service,當我們期望對其接口做一些擴展的時候,我們不需要copy它的代碼到我們的項目來修改它,我們可以手動方便的使用裝潢器去實現我們所想要的。

   注意:上文中說的常量constant是不可以被裝潢的。

福利2:創建非單例對象

    如我們所知所有的service都是單例的,但是我們仍然可以創建一個非單例的對象。在我們深入之前,我們必須認識到大多數場景我們都會期望是個單例的service,我們也不會去改變這種機制。換句話在很少的場景中我們需要每次生成一個新的object對象。如下:

複製代碼
// Our class

function Person( json ) {

angular.extend(this, json);

}



Person.prototype = {

update: function() {

// Update it (With real code :P)

this.name = "Dave";

this.country = "Canada";

}

};



Person.getById = function( id ) {

// Do something to fetch a Person by the id

return new Person({

name: "Jesus",

country: "Spain"

});

};



// Our factory

app.factory('personService', function() {

return {

getById: Person.getById

};

});
複製代碼

 

     在這裏我們創建了一個Person對象,它幾首一些json對象來初始化對象。接下來我們在prototype中創建了一個函數(可以從面嚮對象語言理解爲實例方法),在我們直接在Person類上加了一個方法(可以理解爲類方法,靜態方法)

   所以我們有一個類方法將根據我們提供的id創建一個新的person對象,並每隔實例可以更新自己。接下來我們只需要創建一個service去消費它。

   在任何時候我們調用personService.getByID,我們都會創建一個新的person對象,所以在不同的controller中你可以使用一份新的person對象,即使factory是單例的,但是它生產返回的卻是新的object

福利3CoffeeScript

   CoffeeScrip能夠方便優雅的處理service,提供的優雅的方式去創建class。下面是福利2的示例用CoffeeScript改變後的:

複製代碼
app.controller 'MainCtrl', ($scope, personService) ->

$scope.aPerson = personService.getById(1)



app.controller 'SecondCtrl', ($scope, personService) ->

$scope.aPerson = personService.getById(2)

$scope.updateIt = () ->

$scope.aPerson.update()



class Person



constructor: (json) ->

angular.extend @, json



update: () ->

@name = "Dave"

@country = "Canada"



@getById: (id) ->

new Person

name: "Jesus"

country: "Spain"



app.factory 'personService', () ->

{

getById: Person.getById

}
複製代碼

 

     譯者注:本人一直在思考一篇《爲什麼需要在你的項目中嘗試CoffeeScript.CoffeeScript不僅僅優美語法,如果只是這樣的話,充其量這也只是一些可有可無的語法糖而已,我們認爲更重要的是它爲我們寫javascript帶來了一些好的實踐,規避了javascript的“坑”.但是也不得不考慮項目成員學習成本,如果你項目成員很多具有函數式編程的經歷,javascript能力也不錯,你完全可以去嘗試。注:寫CoffeeScript並不是說你不再需要javascript學習。

總結:

    serviceangularjs另一個非常酷的features。我們有許多方式去創建service,我們需要根據我們的應用場景選擇正確的方式去實現它。譯者注:這就好比我們常掛在嘴邊的設計模式,重要的是正確的場景使用正確的模式。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章