Service vs Factory hakkında karışık


618

Anladığım kadarıyla, bir fabrika içinde bir denetleyiciye enjekte edilen bir nesneyi iade ediyorum. Bir hizmetin içinde nesneyi kullanarak thisve hiçbir şey döndürmeden ilgileniyorum .

Bir hizmetin her zaman tekil olduğu ve her denetleyiciye yeni bir fabrika nesnesinin enjekte edildiği varsayımı altındaydım . Ancak, ortaya çıktığı gibi, bir fabrika nesnesi de bir tekil mi?

Gösterilecek örnek kod:

var factories = angular.module('app.factories', []);
var app = angular.module('app',  ['ngResource', 'app.factories']);

factories.factory('User', function () {
  return {
    first: 'John',
    last: 'Doe'
  };
});

app.controller('ACtrl', function($scope, User) {
  $scope.user = User;
});

app.controller('BCtrl', function($scope, User) {
  $scope.user = User;
});

Değiştirirken user.firstde ACtrlbunun çıkıyor user.firstiçinde BCtrlörneğin da değiştirilir Userbir tekil mi?

Benim varsayımım, fabrikada bir kontrolöre yeni bir örnek enjekte edildiğiydi?


4
"Module.service" ve "module.factory" ifadelerinin yanında AngularJS'de hizmet oluşturmanın 2 yolu daha vardır. Daha fazla bilgi için blog yazısı ile kontrol edin: " AngularJS hizmetleri 4 farklı şekilde nasıl oluşturulur "
Emil van Galen

Yanıtlar:


600

Tüm açısal hizmetler tekil :

Dokümanlar (bkz . Tekton olarak Hizmetler ): https://docs.angularjs.org/guide/services

Son olarak, tüm Açısal hizmetlerin uygulama tekilleri olduğunu anlamak önemlidir. Bu, enjektör başına belirli bir hizmetin yalnızca bir örneğinin olduğu anlamına gelir.

Temel olarak hizmet ve fabrika arasındaki fark aşağıdaki gibidir:

app.service('myService', function() {

  // service is just a constructor function
  // that will be called with 'new'

  this.sayHello = function(name) {
     return "Hi " + name + "!";
  };
});

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

  // factory returns an object
  // you can run some code before

  return {
    sayHello : function(name) {
      return "Hi " + name + "!";
    }
  }
});

$ Offer hakkında bu sunuma göz atın: http://slides.wesalvaro.com/20121113/#/

Bu slaytlar AngularJs buluşmalarından birinde kullanıldı: http://blog.angularjs.org/2012/11/more-angularjs-meetup-videos.html


13
Ayrıca servis, fabrika ve tedarik arasındaki farkları tartışan stackoverflow.com/questions/15666048/… adresine bakın .
Mark Rajcok

31
Resmi doktor dolaylı olarak [sic! yeterli değil], hizmeti fabrika ile tanımlasanız bile, yalnızca bir kez oluşturulduğunu ima eder. Başka bir deyişle, referans olarak (enjeksiyon noktası) yeniden yaratılmaz. Her iki yol da enjektör başına tek bir kutu ile sonuçlanır.
honzajde

3
"Hizmet sadece 'yeni' ile çağrılacak bir kurucu işlevdir" diyorsunuz ama bence bu yanıltıcı. Ben sahnenin arkasında yeni denir sanmıyorum, ben geliştirici newonu çağırmaktan sorumlu olduğunu düşünüyorum .
Tim Kindberg

5
@nfiniteloop, 3574 satırının yanındaki kaynak kodunu kontrol edin. Fabrikalar bir sağlayıcının $ get yöntemidir ve hizmetler, sağlanan işlevde $ injector.instantiate öğesini çağıran ve daha sonra yeni çağıran bir yöntem kullanarak fabrikalar oluşturur. ( Bkz Dokümanlar )
citizenslave

14
Bir servisin referans alarak kullandığınız singleton olduğu izlenimindeydim. Ve bir fabrikanın her seferinde yeni bir nesne döndüren bir single olduğu. Yani, bir hizmet size bir "araba" verir ve projenizdeki her şey bu arabayı kullanır. Fabrikayı her başlattığınızda bir fabrika size yeni bir araba verirken. Biri bir singleton döndüren bir singleton ve bir tanesi bir nesneyi döndüren bir singleton idi. Birisi açıklayabilir mi? Her şeyi tek tek çağırmak yardımcı olmaz çünkü birden fazla şeye işaret edebilir.
user2483724 18:14

380

Benim için vahiy, hepsinin aynı şekilde çalıştığını fark ettiğimde geldi: bir şeyleri bir kez çalıştırarak , aldıkları değeri saklayarak ve Bağımlılık Enjeksiyonu ile referans verildiğinde aynı depolanmış değeri öksürdüler.

Diyelim ki:

app.factory('a', fn);
app.service('b', fn);
app.provider('c', fn);

Üçü arasındaki fark şudur:

  1. a'in depolanan değeri koşmaktan gelir, fnyani:fn()
  2. b'nin depolanmış değeri newing'den fn, yani:new fn()
  3. c'depolandığını değeri birinci alma örneğinden gelir newing fnbir ve sonra da çalışan $getörneğinin yöntemi

Bu, açısal içinde bir önbellek nesnesi gibi, her bir enjeksiyonun değeri sadece bir kez, ilk kez enjekte edildiğinde atanan ve nerede:

cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()

Bu yüzden thishizmetlerde kullanıyoruz ve this.$getsağlayıcılarda a tanımlıyoruz .

Bu yardımcı olur umarım.


54
nihayet aklı başında bir açıklama. Açısal çılgın ve acı çekecek kadar kötü.
osiris

8
Bu, NEDEN fabrikaların, hizmetlerin ve sağlayıcıların tekil değerler döndürdüğü sorusuna cevap verdiği için kabul edilen cevap olmalıdır. Diğer cevaplar, fabrikalar, hizmetler ve sağlayıcılar arasındaki farkı açıklar, ancak asla singleton yönüne değinmez.
wmock

3
Bunu beğendim ... Diğer blogcuların binlerce cümlesini okuduğumda .. sadece fabrikayı anlayabiliyorum. Ama bunu okudum ... anlıyorum 3.
tsohtan

@osiris katılıyorum. Sevmiyorum. Dişlerimi öğütmek için o kadar yakından bağlanmış hissediyor ki.
Thomas

2
sağlayıcıları kullanırken $ get bir uygulama sağlamak gerekir?
Victor

95

canlı örnek

"merhaba dünya" örneği

ile factory/ service/ provider:

var myApp = angular.module('myApp', []);

//service style, probably the simplest one
myApp.service('helloWorldFromService', function() {
    this.sayHello = function() {
        return "Hello, World!"
    };
});

//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() {
    return {
        sayHello: function() {
            return "Hello, World!"
        }
    };
});

//provider style, full blown, configurable version     
myApp.provider('helloWorld', function() {
    // In the provider function, you cannot inject any
    // service or factory. This can only be done at the
    // "$get" method.

    this.name = 'Default';

    this.$get = function() {
        var name = this.name;
        return {
            sayHello: function() {
                return "Hello, " + name + "!"
            }
        }
    };

    this.setName = function(name) {
        this.name = name;
    };
});

//hey, we can configure a provider!            
myApp.config(function(helloWorldProvider){
    helloWorldProvider.setName('World');
});


function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {

    $scope.hellos = [
        helloWorld.sayHello(),
        helloWorldFromFactory.sayHello(),
        helloWorldFromService.sayHello()];
}​

57

Eğer dönebilirsiniz böylece bir yapıcı işlevi dönmek için bir yol da vardır newable böyle, fabrikalarda sınıfları:

function MyObjectWithParam($rootScope, name) {
  this.$rootScope = $rootScope;
  this.name = name;
}
MyObjectWithParam.prototype.getText = function () {
  return this.name;
};

App.factory('MyObjectWithParam', function ($injector) {
  return function(name) { 
    return $injector.instantiate(MyObjectWithParam,{ name: name });
  };
}); 

Böylece bunu MyObjectWithParam kullanan bir denetleyicide yapabilirsiniz:

var obj = new MyObjectWithParam("hello"),

Tam örneğe bakın:
http://plnkr.co/edit/GKnhIN?p=preview

Ve burada tartışıldığı google grup sayfaları:
https://groups.google.com/forum/#!msg/angular/56sdORWEoqg/b8hdPskxZXsJ


Örneğinizi kullanarak küçültmeyle ilgili sorunlar yaşıyorum. Buna nasıl açıklama eklemem gerektiğini biliyor musun?
Pål

2
Evet, Angular için küçültülmüş bir gösterim var. Bunun gibi bir şey olmalı: App.factory('MyObjectWithParam', ['$injector', function ($injector) { return function(name) { return $injector.instantiate(MyObjectWithParam,{ name: name }); }; }]); Daha fazla bilgiyi buradan edinebilirsiniz: docs.angularjs.org/tutorial/step_05
JustGoscha

4
.servicebunun yerine neden bunu yapmak istiyorsun ?
Flup

@flup ile aynı düşünceye sahiptim. @justgoscha, aksine kullanmanın faydası ( algılanıyor mu? ) var mı? .factory.service
21'de xandercocode

5
Bence bir hizmet bir singleton . Burada inşa ettiğim temelde yeni olan bir sınıf . Sonra bir araba servisi fabrika gibi bir şey var ve bu yüzden yapmak new Car('BMW')ve new Car('Ford')onlar aynı değişkenleri ve her şeyi paylaşmıyoruz.
JustGoscha

51

Temel farklar şunlardır:

Hizmetler

Sözdizimi: module.service( 'serviceName', function );

Sonuç: serviceName'i enjekte edilebilir bir argüman olarak bildirirken, size iletilen bir işlev örneği verilir module.service.

Kullanım: Enjekte edilen işlev referansına () eklenerek çağırılması yararlı olan yardımcı program işlevlerini paylaşmak için yararlı olabilir. Ayrıca injectedArg.call( this )veya benzeri ile çalıştırılabilir .

Fabrikalar

Sözdizimi: module.factory( 'factoryName', function );

Sonuç: factoryName öğesini enjekte edilebilir bir argüman olarak bildirirken, iletilen işlev başvurusunu çağırarak size döndürülen değer sağlanır module.factory.

Kullanım: Örnekler oluşturmak için yeni olabilecek bir 'sınıf' işlevini döndürmek için yararlı olabilir.

Ayrıca servis vs fabrika karışık yığını üzerinde AngularJS belgelerini ve benzer soruyu kontrol edin .

İşte hizmetler ve fabrika kullanarak örnek . AngularJS servisi vs fabrika hakkında daha fazla bilgi edinin .


6
Bu bana mantıklı geliyor. Fabrika yeni nesneler yaratmak için planı geri döndürüyor.

27

İlk yanıta ek olarak, sanırım .service () kodlarını daha nesne yönelimli bir tarzda (C # / Java) yazmış olan insanlar içindir (bu anahtar kelimeyi kullanarak ve prototip / Oluşturucu işlevi aracılığıyla nesneyi başlatır).

Fabrika, javascript / fonksiyonel kodlama stili için daha doğal olan kod yazan geliştiriciler içindir.

Angular.js içindeki .service ve .factory yönteminin kaynak koduna bir göz atın - dahili olarak hepsi çağrı sağlayıcı yöntemi:

  function provider(name, provider_) {
    if (isFunction(provider_)) {
      provider_ = providerInjector.instantiate(provider_);
    }
    if (!provider_.$get) {
      throw Error('Provider ' + name + ' must define $get factory method.');
    }
    return providerCache[name + providerSuffix] = provider_;
  }

  function factory(name, factoryFn) { \
    return provider(name, { $get: factoryFn }); 
  }

  function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
      return $injector.instantiate(constructor);
    }]);
  }

25

Çok basit:

.service - kayıtlı işlev yapıcı olarak çağrılır (diğer adıyla 'newed')

.factory - kayıtlı işlev basit bir işlev olarak çağrılır

Her ikisi de bir kez çağrılır ve uygulamanızın diğer bileşenlerine enjekte edilen tek bir nesneye neden olur.


6
Evet. işleri gerçekten olduğundan daha karmaşık hale getirmeyelim
flup

20

Tüm sağlayıcılar aynı şekilde çalışır. Farklı yöntemler service, factory, providersadece daha az kod aynı şeyi gerçekleştirmek edelim.

PS Orada valueve constant.

Zincirden başlayıp providerbiten her özel durumun valueek bir sınırlaması vardır. Bu nedenle, aralarında karar vermek için kendinize, daha az kodla ne istediğinizi başaracağınızı sormanız gerekir.

İşte size ne demek istediğimi gösteren bir resim:

resim açıklamasını buraya girin

Bu yazıyı aldığım blog gönderisinde bir arıza ve başvuru kılavuzu yapabilirsiniz:

http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/


Hizmetler singleton olduğu söylenir, ancak her enjekte ettiğimde yeni bir örnek oluşturuluyorsa nasıl olur?
Ankur Marwaha

1
@AnkurMarwaha Her seferinde yeni bir örnek oluşturulmaz, yalnızca bir kez oluşturulur ve AngularJS tarafından önbelleğe alınır. İster bir sağlayıcı, fabrika, hizmet vb. console.log()Kullanın, bu durum birden fazla denetleyiciyi kullanarak ve enjekte ederek onaylayabilirsiniz .
Luis Perez

Luis, Yorumunuz kabul edilen cevapla söylediği gibi çelişiyor - Son olarak, tüm Açısal hizmetlerin uygulama tekilleri olduğunu anlamak önemlidir. Bu, enjektör başına belirli bir hizmetin yalnızca bir örneğinin olduğu anlamına gelir.
Ankur Marwaha

@AnkurMarwaha belki bir şeyi yanlış anlıyorum. "Tüm Açısal hizmetlerin uygulama tekilleri olduğunu anlamak önemlidir" - tekton olmaları, yalnızca bir kez oluşturuldukları anlamına gelir. Ne dediğimi hangisi "Yeni bir örneği değil her zaman oluşturulan, sadece bir defa oluşturulan ve önbelleğe oluyor ...". Çatışmayı nerede gördüğünüzü daha ayrıntılı olarak anlatabilir misiniz?
Luis Perez

1
Ah, karışıklığı görüyorum. "Enjektör" açısal bir nesnedir. "Enjeksiyon" yapmaktan sorumlu. Örneğin, kontrolör ilk çalıştırıldığında "enjektör" parametrelere bakar ve her birini enjekte eder. Tüm uygulamanız için sadece bir "enjektör" vardır. Enjektör belirli bir fabrika veya hizmeti oluşturduktan sonra, bunun bir örneğini tutar ve yeniden kullanır - dolayısıyla singleton. Dolayısıyla, uygulama başına yalnızca bir enjektör ve enjektör başına belirli bir hizmetin yalnızca bir örneği vardır. Çoğu Açısal uygulama sadece bir uygulama, bu nedenle bir enjektör, bu nedenle herhangi bir hizmet, denetleyici, vb bir örneği vardır
Luis Perez

13

İşte fabrikalar ve fabrikalar arasındaki farkı, bunlar arasındaki farkı görmede yararlı olabilecek bazı örnekler. Temel olarak, bir hizmetin üzerinde "yeni ..." vardır, zaten somutlaştırılmıştır. Bir fabrika otomatik olarak başlatılmaz.

Temel Örnekler

Tek bir yöntemi olan bir sınıf nesnesi döndürme

İşte tek bir yöntemi olan bir hizmet:

angular.service('Hello', function () {
  this.sayHello = function () { /* ... */ };
});

İşte bir yöntemle bir nesne döndüren bir fabrika:

angular.factory('ClassFactory', function () {
  return {
    sayHello: function () { /* ... */ }
  };
});

Bir değer döndürme

Bir sayı listesi döndüren bir fabrika:

angular.factory('NumberListFactory', function () {
  return [1, 2, 3, 4, 5];
});

console.log(NumberListFactory);

Bir sayı listesi döndüren bir hizmet:

angular.service('NumberLister', function () {
  this.numbers = [1, 2, 3, 4, 5];
});

console.log(NumberLister.numbers);

Her iki durumda da çıktı aynı, sayı listesi.

Gelişmiş Örnekler

Fabrikaları kullanarak "Sınıf" değişkenleri

Bu örnekte bir CounterFactory tanımlarız, bir sayacı artırır veya azaltır ve geçerli sayımı alabilir veya kaç CounterFactory nesnesi oluşturulduğunu elde edebilirsiniz:

angular.factory('CounterFactory', function () {
  var number_of_counter_factories = 0; // class variable

  return function () {
    var count = 0; // instance variable
    number_of_counter_factories += 1; // increment the class variable

    // this method accesses the class variable
    this.getNumberOfCounterFactories = function () {
      return number_of_counter_factories;
    };

    this.inc = function () {
      count += 1;
    };
    this.dec = function () {
      count -= 1;
    };
    this.getCount = function () {
      return count;
    };
  }

})

Biz kullanmak CounterFactorybirden sayaçlarını oluşturun. Kaç sayacın oluşturulduğunu görmek için sınıf değişkenine erişebiliriz:

var people_counter;
var places_counter;

people_counter = new CounterFactory();
console.log('people', people_counter.getCount());
people_counter.inc();
console.log('people', people_counter.getCount());

console.log('counters', people_counter.getNumberOfCounterFactories());

places_counter = new CounterFactory();
console.log('places', places_counter.getCount());

console.log('counters', people_counter.getNumberOfCounterFactories());
console.log('counters', places_counter.getNumberOfCounterFactories());

Bu kodun çıktısı:

people 0
people 1
counters 1
places 0
counters 2
counters 2

yararlı bir örnek, number_of_counter_factories CounterFactory sınıfının meta bir öznitelikine benziyor, değil mi?
geoom

Yararlı bir örnek! Yani bu temelde bir fabrikada bir servise girmeyecek ekstra soyutlama katmanına sahip olabileceğiniz anlamına gelir. Yine de döndürülecek her neyse, 'yeni' kullanıldığında yeni bir örneği döndürülecektir. Dönüş bloğunda bildirilmeyen değişkenler tekil olacaktır. Doğru anladım mı?
Swanidhi

@Swanidhi temel olarak evet, fabrikada tekton olan değişkenleri bildirebilirsiniz. Bu yüzden onlara "sınıf" değişkenleri adını verdim.

13

“Fabrika” ve “Hizmet”, DI (Bağımlılık enjeksiyonu) açısal olarak farklı şekillerde yapılır.

Bu nedenle DI'yi aşağıdaki kodda gösterildiği gibi “service” kullanarak tanımladığımızda. Bu, “Logger” nesnesinin yeni bir GLOBAL örneğini oluşturur ve onu işleve enjekte eder.

app.service("Logger", Logger); // Injects a global object

DI'yi bir “fabrika” kullanarak tanımladığınızda örnek oluşturmaz. Sadece yöntemi geçer ve daha sonra tüketici dahili olarak nesne örnekleri için fabrikaya çağrı yapmak zorundadır.

app.factory("Customerfactory", CreateCustomer);

Aşağıda, “Hizmet” için DI sürecinin “Fabrika” dan nasıl farklı olduğunu görsel olarak gösteren basit bir görüntü bulunmaktadır.

resim açıklamasını buraya girin

Fabrika kullanılmalıdır Senaryolara bağlı olarak farklı nesne türleri yaratmak istediğimizde. Örneğin, senaryoya bağlı olarak basit bir "Müşteri" nesnesi veya "Adres" nesnesi ile "Müşteri" veya "Telefon" nesnesi ile "Müşteri" oluşturmak istiyoruz. İşte bu paragrafın ayrıntılı bir açıklaması

Hizmet kullanılmalıdır. Yardımcı Program, Kaydedici, Hata işleyici vb. Gibi enjekte edilecek yardımcı program veya paylaşılan işlevler olduğunda.


Bu soru ve benzerleri üzerinde gördüğüm her cevap, mekanik ve sözdizimindeki farkı belirtiyor. Bu cevap, birini diğerinin üzerinde seçmenizin gerçek bir nedenini verir. Bir anlambilim meselesi ve isme, hizmete veya fabrikaya bakmak, amaçlarını ve nasıl kullanıldıklarını anlatmak.
Joe Mayo

8

Hizmet tarzı: ( muhtemelen en basit olanı ) gerçek işlevi döndürür: Enjekte edilen işlev referansına () eklenerek çağırılması yararlı olan yardımcı program işlevlerini paylaşmak için kullanışlıdır.

AngularJS'deki bir hizmet, bir dizi işlev içeren tek bir JavaScript nesnesidir

var myModule = angular.module("myModule", []);

myModule.value  ("myValue"  , "12345");

function MyService(myValue) {
    this.doIt = function() {
        console.log("done: " + myValue;
    }
}

myModule.service("myService", MyService);
myModule.controller("MyController", function($scope, myService) {

    myService.doIt();

});

Fabrika stili: ( daha karmaşık ancak daha karmaşık ) işlevin dönüş değerini döndürür: java'da new Object () gibi bir nesneyi başlatın.

Fabrika, değerler yaratan bir işlevdir. Bir servis, kontrolör vb. Bir fabrikadan enjekte edilen bir değere ihtiyaç duyduğunda, fabrika talep üzerine değeri yaratır. Oluşturulduktan sonra, değer enjekte edilmesi gereken tüm hizmetler, kontrolörler vb. İçin yeniden kullanılır.

var myModule = angular.module("myModule", []);

myModule.value("numberValue", 999);

myModule.factory("myFactory", function(numberValue) {
    return "a value: " + numberValue;
})  
myModule.controller("MyController", function($scope, myFactory) {

    console.log(myFactory);

});

Sağlayıcı stili: ( tam gelişmiş, yapılandırılabilir sürüm ), işlevin $ get işlevinin çıktısını döndürür: Yapılandırılabilir.

AngularJS'deki sağlayıcılar, oluşturabileceğiniz en esnek fabrika şeklidir. Bunun yerine, sağlayıcı () işlevini kullanmanız dışında, bir hizmeti veya fabrikada yaptığınız gibi bir modülle sağlayıcı kaydedersiniz.

var myModule = angular.module("myModule", []);

myModule.provider("mySecondService", function() {
    var provider = {};
    var config   = { configParam : "default" };

    provider.doConfig = function(configParam) {
        config.configParam = configParam;
    }

    provider.$get = function() {
        var service = {};

        service.doService = function() {
            console.log("mySecondService: " + config.configParam);
        }

        return service;
    }

    return provider;
});

myModule.config( function( mySecondServiceProvider ) {
    mySecondServiceProvider.doConfig("new config param");
});

myModule.controller("MyController", function($scope, mySecondService) {

    $scope.whenButtonClicked = function() {
        mySecondService.doIt();
    }

});

src jenkov

<!DOCTYPE html>
    <html ng-app="app">
    <head>
    	<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js"></script>
    	<meta charset=utf-8 />
    	<title>JS Bin</title>
    </head>
    <body ng-controller="MyCtrl">
    	{{serviceOutput}}
    	<br/><br/>
    	{{factoryOutput}}
    	<br/><br/>
    	{{providerOutput}}
    
    	<script>
    
    		var app = angular.module( 'app', [] );
    
    		var MyFunc = function() {
    
    			this.name = "default name";
    
    			this.$get = function() {
    				this.name = "new name"
    				return "Hello from MyFunc.$get(). this.name = " + this.name;
    			};
    
    			return "Hello from MyFunc(). this.name = " + this.name;
    		};
    
    		// returns the actual function
    		app.service( 'myService', MyFunc );
    
    		// returns the function's return value
    		app.factory( 'myFactory', MyFunc );
    
    		// returns the output of the function's $get function
    		app.provider( 'myProv', MyFunc );
    
    		function MyCtrl( $scope, myService, myFactory, myProv ) {
    
    			$scope.serviceOutput = "myService = " + myService;
    			$scope.factoryOutput = "myFactory = " + myFactory;
    			$scope.providerOutput = "myProvider = " + myProv;
    
    		}
    
    	</script>
    
    </body>
    </html>

jsbin

<!DOCTYPE html>
<html ng-app="myApp">
<head>
	<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js"></script>
	<meta charset=utf-8 />
	<title>JS Bin</title>
</head>
<body>
<div ng-controller="MyCtrl">
    {{hellos}}
</div>
	<script>

	var myApp = angular.module('myApp', []);

//service style, probably the simplest one
myApp.service('helloWorldFromService', function() {
    this.sayHello = function() {
        return "Hello, World!"
    };
});

//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() {
    return {
        sayHello: function() {
            return "Hello, World!"
        }
    };
});
    
//provider style, full blown, configurable version     
myApp.provider('helloWorld', function() {

    this.name = 'Default';

    this.$get = function() {
        var name = this.name;
        return {
            sayHello: function() {
                return "Hello, " + name + "!"
            }
        }
    };

    this.setName = function(name) {
        this.name = name;
    };
});

//hey, we can configure a provider!            
myApp.config(function(helloWorldProvider){
    helloWorldProvider.setName('World');
});
        

function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {
    
    $scope.hellos = [
        helloWorld.sayHello(),
        helloWorldFromFactory.sayHello(),
        helloWorldFromService.sayHello()];
}
	</script>

</body>
</html>

jsfiddle


2

Temel fark, sağlayıcının fabrikada bildirilen değişkene ilkel (nesne olmayan), dizi veya geri çağırma işlevi değerlerini ayarlamasına izin vermesidir ve bu nedenle bir nesneyi döndürürse açıkça bildirilmeli ve döndürülmelidir.

Öte yandan, bir hizmet yalnızca hizmet bildirilen değişkeni bir nesneye ayarlamak için kullanılabilir, bu nedenle nesnelerin açıkça oluşturulmasını ve geri dönmesini engelleyebiliriz, diğer yandan bu anahtar kelimenin kullanılmasına izin verir .

Veya kısaca, " hizmet yalnızca nesnelerle sınırlıyken sağlayıcı daha genel bir formdur ".


2

Tasarım modelleri açısından aralarındaki farkı şu şekilde anladım:

Hizmet : Bu türde bir nesne oluşturmak için yeni bir tür döndürün. Java benzetmesi kullanılıyorsa, Hizmet bir Java Sınıfı tanımı döndürür .

Fabrika : Hemen kullanılabilecek somut bir nesne döndürür. Java Analogy uygulamasında bir Fabrika bir Java Nesnesi döndürür .

İnsanları (kendim dahil) sık sık karıştıran kısım, kodunuza bir Hizmet veya Fabrika enjekte ettiğinizde aynı şekilde kullanılabilmeleridir, her iki durumda da kodunuzda aldığınız şey, hemen çağırabileceğiniz somut bir nesnedir. Bu, Hizmet durumunda, sizin adınıza hizmet beyanında açısal olarak "yeni" olarak adlandırılır. Bunun kıvrımlı bir kavram olduğunu düşünüyorum.


1

Bu, Servis Vs Fabrika Vs Sağlayıcı anlamak için en iyi ve kısa cevap olacaktır

Kaynak : https://groups.google.com/forum/#!msg/angular/56sdORWEoqg/HuZsOsMvKv4J

İşte ben bir demo ile ne diyor http://jsbin.com/ohamub/1/edit?html,output

"Kodda birincil farklılıkları gösteren yorumlar var, ancak burada biraz daha genişleyeceğim. Bir not olarak, sadece başımın etrafında dönüyorum, bu yüzden yanlış bir şey söylersem lütfen bana bildirin.

Hizmetler

Sözdizimi : module.service ('serviceName', işlev);

Sonuç : serviceName öğesini enjekte edilebilir bir argüman olarak bildirirken, module.service öğesine iletilen gerçek işlev başvurusu size sağlanacaktır.

Kullanım : Enjekte edilen işlev referansına () eklenerek çağırılması yararlı olan yardımcı program işlevlerini paylaşmak için yararlı olabilir. Ayrıca injectedArg.call (bu) veya benzeri ile de çalıştırılabilir.

Fabrikalar

Sözdizimi : module.factory ('fabrikaAdı', işlev);

Sonuç : factoryName öğesini enjekte edilebilir bir argüman olarak bildirirken, module.factory öğesine iletilen işlev başvurusunu çağırarak size döndürülen değeri sağlarsınız.

Kullanım : Örnekler oluşturmak için yeni olabilecek bir 'sınıf' işlevini döndürmek için yararlı olabilir.

Sağlayıcıları

Sözdizimi : module.provider ('sağlayıcıAdı', işlev);

Sonuç : vendorName öğesini enjekte edilebilir bir argüman olarak bildirirken, module.provider öğesine iletilen işlev başvurusunun $ get yönteminin çağrılmasıyla döndürülen değer size sağlanacaktır.

Kullanım : Örnek oluşturmak için daha sonra yeni olabilecek ancak enjekte edilmeden önce bir tür yapılandırma gerektiren bir 'sınıf' işlevi döndürmek için yararlı olabilir. Belki projeler arasında yeniden kullanılabilir sınıflar için yararlı? Bu konuda hala biraz puslu. "Ben


1

Bir süre bu karışıklığı yaşadım ve burada basit bir açıklama yapmak için elimden geleni yapıyorum. Umarım bu yardımcı olur!

angular .factoryve angular .serviceher ikisi de bir hizmeti başlatmak ve aynı şekilde çalışmak için kullanılır.

Tek fark, hizmetinizi nasıl başlatmak istediğinizdir.

Her ikisi de Singletons


var app = angular.module('app', []);


Fabrika

app.factory ( <service name>, <function with a return value>)

Hizmetinizi bir dönüş değeri olan bir işlevden başlatmak istiyorsanız, bu factoryyöntemi kullanmanız gerekir .

Örneğin

function myService() {
  //return what you want
  var service = {
    myfunc: function (param) { /* do stuff */ }
  }
  return service;
}

app.factory('myService', myService);

Bu servisi enjekte ederken (örn. Kumandanıza):

  • Açısal , nesneyi döndürmek için verilen işlevi (as ) çağırırmyService()
  • Singleton - aynı nesneyi yalnızca bir kez çağırır , depolar ve iletir.


Hizmet

app.service ( <service name>, <constructor function>)

Hizmetinizi bir yapıcı işlevinden ( thisanahtar kelime kullanarak ) başlatmak istiyorsanız, bu serviceyöntemi kullanmanız gerekir .

Örneğin

function myService() {
  this.myfunc: function (param) { /* do stuff */ }
}

app.service('myService', myService);

Bu servisi enjekte ederken (örn. Kumandanıza):

  • Açısal, newverilen işlevi (as new myService()) nesneyi döndürmek için kullanır
  • Singleton - aynı nesneyi yalnızca bir kez çağırır , depolar ve iletir.


Not: kullanıyorsanız factoryile <constructor function>veya servicebirlikte <function with a return value>, bu işe yaramaz.


Örnekler - DEMO'lar


1

Pascal Precht'in bir blog yazısı sayesinde farkı anlamama yardımcı olan şey buydu.

Hizmet, modülü tanımlayan, adı tanımlayan ve işlevi tanımlayan bir işlevdir. Söz konusu hizmeti denetleyiciler, yönergeler ve filtreler gibi diğer bileşenlere enjekte edebilir ve kullanabilirsiniz. Fabrika, bir modül üzerindeki bir yöntemdir ve aynı zamanda fabrikayı tanımlayan bir isim ve fonksiyon alır. Ayrıca, bunu servisle yaptığımız şekilde enjekte edebilir ve kullanabiliriz.

Yeni ile oluşturulan nesneler kendi prototipi olarak onların yapıcı işlevinin prototip özelliğinin değerini kullanın, bu yüzden ben nesne oluşturulduğunda hizmet yapıcı işlevi olduğuna inanıyorum Object.create () çağıran Açısal kodu buldum. Bununla birlikte, bir fabrika işlevi gerçekten sadece çağrılan bir işlevdir, bu yüzden fabrika için bir nesneyi döndürmek zorundayız.

İşte fabrika için bulduğum açısal 1.5 kodu:

var needsRecurse = false;
    var destination = copyType(source);

    if (destination === undefined) {
      destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
      needsRecurse = true;
    }

Factory () işlevi için açısal kaynak kod snippet'i:

 function factory(name, factoryFn, enforce) {
    return provider(name, {
      $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
    });
  }

Geçilen adı ve fabrika işlevini alır ve aynı ada sahip, fabrika işlevimiz olan $ get yöntemine sahip bir sağlayıcı döndürür. Enjektörden belirli bir bağımlılık istediğinizde, temel olarak ilgili sağlayıcıdan $ get () yöntemini çağırarak o hizmetin bir örneğini ister. Bu yüzden sağlayıcılar oluştururken $ get () gereklidir.

İşte hizmet için açısal 1.5 kodu.

function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
      return $injector.instantiate(constructor);
    }]);
  }

Service () öğesini çağırdığımızda, aslında factory () öğesini çağırdığı ortaya çıkıyor! Ancak, sadece servis yapıcı fonksiyonumuzu fabrikaya olduğu gibi aktarmakla kalmıyor. Ayrıca enjektörden belirli bir kurucu tarafından bir nesneyi başlatmasını isteyen bir işlevi de geçer.

Başka bir deyişle, MyService'i bir yere enjekte edersek, kodda ne olur:

MyServiceProvider.$get(); // return the instance of the service

Yeniden başlatmak için, bir hizmet ilgili fabrikadaki $ get () yöntemi olan bir fabrikayı çağırır. Ayrıca, $ injector.instantiate (), nihai olarak yapıcı işleviyle Object.create () yöntemini çağıran yöntemdir. Bu yüzden hizmetlerde "bunu" kullanıyoruz.

ES5 için hangisini kullandığımız önemli değil: service () veya factory (), her zaman servisimiz için bir sağlayıcı oluşturan denilen bir fabrika.

Aynı şeyi hizmetlerle de yapabilirsiniz. Hizmet, yapıcı işlevidir, ancak nesne değişmezlerini döndürmemizi engellemez. Böylece servis kodumuzu alıp temelde fabrikamızla aynı şeyi yapacak şekilde yazabiliriz veya başka bir deyişle, bir nesneyi döndürmek için fabrika olarak bir hizmet yazabilirsiniz.

Neden çoğu insan fabrikaları servisler üzerinde kullanmanızı önerir? Bu, Pawel Kozlowski'nin AngularJS ile Web Uygulaması Geliştirmede Mastering adlı kitabından gelen en iyi cevap.

Fabrika yöntemi, nesneleri AngularJS bağımlılık enjeksiyon sistemine sokmanın en yaygın yoludur. Çok esnektir ve gelişmiş yaratım mantığı içerebilir. Fabrikalar düzenli işlevler olduğundan, "özel" değişkenleri simüle etmek için yeni bir sözlüksel kapsamdan da yararlanabiliriz. Bu, belirli bir hizmetin uygulama ayrıntılarını gizleyebildiğimiz için çok yararlı. "


1
  • İle fabrikanın aslında bir oluşturmak nesne içini fabrikasında ve geri.
  • Hizmet ile sadece fonksiyonu this tanımlamak için anahtar kelimeyi kullanan standart bir fonksiyon var .
  • Sağlayıcı ile $gettanımladığınız bir veri vardır ve veriyi döndüren nesneyi almak için kullanılabilir .

1

AngularJS'de iş mantığını ele almanın üç yolu vardır: ( Yaakov'un Coursera AngularJS kursundan esinlenilmiştir ):

  1. Hizmet
  2. Fabrika
  3. Sağlayıcı

Burada sadece Service vs Factory hakkında konuşacağız

HİZMET :

Sözdizimi:

app.js

 var app = angular.module('ServiceExample',[]);
 var serviceExampleController =
              app.controller('ServiceExampleController', ServiceExampleController);
 var serviceExample = app.service('NameOfTheService', NameOfTheService);

 ServiceExampleController.$inject = ['NameOfTheService'] //very important as this protects from minification of js files

function ServiceExampleController(NameOfTheService){
     serviceExampleController = this;
     serviceExampleController.data = NameOfTheService.getSomeData();
 }

function NameOfTheService(){
     nameOfTheService = this;
     nameOfTheService.data = "Some Data";
     nameOfTheService.getSomeData = function(){
           return nameOfTheService.data;
     }     
}

index.html

<div ng-controller = "ServiceExampleController as serviceExample">
   {{serviceExample.data}}
</div>

Hizmetin ana özellikleri:

  1. Tembel Örnekleme : Hizmet enjekte edilmezse, hiçbir zaman örneklendirilmez. Bu yüzden onu kullanmak için bir modüle enjekte etmeniz gerekecek.

  2. Singleton : Birden fazla modüle enjekte edilirse, hepsinin yalnızca belirli bir örneğe erişimi olacaktır. Bu nedenle, farklı denetleyiciler arasında veri paylaşmak çok uygundur.

FABRİKA

Şimdi AngularJS'deki Fabrika hakkında konuşalım

Önce sözdizimine bir göz atalım :

app.js :

var app = angular.module('FactoryExample',[]);
var factoryController = app.controller('FactoryController', FactoryController);
var factoryExampleOne = app.factory('NameOfTheFactoryOne', NameOfTheFactoryOne);
var factoryExampleTwo = app.factory('NameOfTheFactoryTwo', NameOfTheFactoryTwo);

//first implementation where it returns a function
function NameOfTheFactoryOne(){
   var factory = function(){
      return new SomeService();
    }
   return factory;
}

//second implementation where an object literal would be returned
function NameOfTheFactoryTwo(){
   var factory = {
      getSomeService : function(){
          return new SomeService();
       }
    };
   return factory;
}

Şimdi denetleyicide yukarıdaki ikisini kullanarak:

 var factoryOne = NameOfTheFactoryOne() //since it returns a function
 factoryOne.someMethod();

 var factoryTwo = NameOfTheFactoryTwo.getSomeService(); //accessing the object
 factoryTwo.someMethod();

Fabrika Özellikleri:

  1. Bu tür hizmetler fabrika tasarım modelini takip eder . Fabrika, yeni nesneler veya yöntemler yaratan merkezi bir yer olarak düşünülebilir.

  2. Bu sadece singleton değil, aynı zamanda özelleştirilebilir hizmetler de üretir.

  3. .service()Yöntem olduğu fabrika her zaman tekil olan hizmetin aynı tür oluşturur. Davranışını yapılandırmanın kolay bir yolu yoktur. Bu .service()yöntem genellikle herhangi bir yapılandırma gerektirmeyen bir şey için kısayol olarak kullanılır.



0

Bu benzetme ile farkı anlayabilirsiniz - Bazı değer döndürecek normal bir işlev ile yeni anahtar kelime kullanılarak örneklenecek yapıcı işlevi arasındaki farkı düşünün.Bu yüzden fabrika oluşturmak, bazı değerleri (ilkel veya hizmet oluşturmak, yeni anahtar kelime kullanarak örnek oluşturabileceğimiz yapıcı işlevi (OO sınıfı) oluşturmak gibidir. Dikkat edilmesi gereken tek şey, hizmet oluşturmak için Hizmet yöntemini kullandığımızda, AngularJS tarafından desteklenen bağımlılık enjeksiyon mekanizması kullanarak otomatik olarak bunun örneğini oluşturacağıdır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.