açısal. servis vs açısal. fabrika


1065

Hem gördük angular.factory () ve angular.service () beyan hizmetlerine kullanılan; ancak resmi belgelerde hiçbir yer bulamıyorum angular.service .

İki yöntem arasındaki fark nedir?
Hangisi ne için kullanılmalıdır (farklı şeyler yaptıkları varsayılarak)?



4
"[Angularjs] hizmet fabrikası" nı aradım, ama bu konuda zaten bir soru olduğunu da hatırladım (çünkü bu / bu soruyu kendime bir noktada yazmayı düşündüm).
Mark Rajcok

2
Bir aramada, köşeli ayraçlar bir etiketi belirtir mi?
jacob

11
@Jocob Köşeli Parantez aramanızı daraltıyor. [angularjs] yönergeleri - angularjs ile etiketlenmiş sorular için 'direktifleri' arayacaktır.
Mahbub

1
@Mahbub Başka bir deyişle, "evet" :)
Brian

Yanıtlar:


1268
  angular.service('myService', myServiceFunction);
  angular.factory('myFactory', myFactoryFunction);

Kendime bu şekilde koyana kadar başımı bu konseptin etrafına sarmakta güçlük çektim:

Servis : yazdığınız fonksiyon yeni olacaktır :

  myInjectedService  <----  new myServiceFunction()

Fabrika : Yazdığınız işlev (kurucu) çağrılır :

  myInjectedFactory  <---  myFactoryFunction()

Bununla yaptığınız şey size kalmış, ancak bazı yararlı desenler var ...

Herkese açık bir API'yı ortaya çıkarmak için bir hizmet işlevi yazmak gibi :

function myServiceFunction() {
  this.awesomeApi = function(optional) {
    // calculate some stuff
    return awesomeListOfValues;
  }
}
---------------------------------------------------------------------------------
// Injected in your controller
$scope.awesome = myInjectedService.awesomeApi();

Veya herkese açık bir API'yı göstermek için fabrika işlevini kullanma :

function myFactoryFunction() {
  var aPrivateVariable = "yay";

  function hello() {
    return "hello mars " + aPrivateVariable;
  }

  // expose a public API
  return {
    hello: hello
  };
}
---------------------------------------------------------------------------------
// Injected in your controller
$scope.hello = myInjectedFactory.hello();

Veya bir kurucu döndürmek için fabrika işlevini kullanarak :

function myFactoryFunction() {
    return function() {
        var a = 2;
        this.a2 = function() {
            return a*2;
        };
    };
}
---------------------------------------------------------------------------------
// Injected in your controller
var myShinyNewObject = new myInjectedFactory();
$scope.four = myShinyNewObject.a2();

Hangisini kullanmalı? ...

Aynı şeyi her ikisiyle de yapabilirsiniz. Bununla birlikte, bazı durumlarda fabrika , daha basit bir sözdizimi ile enjekte edilebilir oluşturmak için size biraz daha esneklik sağlar. Çünkü myInjectedService her zaman bir nesne olsa da, myInjectedFactory bir nesne, bir işlev başvurusu veya herhangi bir değer olabilir. Örneğin, bir kurucu oluşturmak için bir hizmet yazdıysanız (yukarıdaki son örnekte olduğu gibi), bu şekilde başlatılması gerekir:

var myShinyNewObject = new myInjectedService.myFunction()

tartışmasız bundan daha az istenir:

var myShinyNewObject = new myInjectedFactory();

(Ancak, bu tür desenleri ilk etapta kullanma konusunda dikkatli olmalısınız çünkü kontrol cihazlarınızdaki yeni nesneler test için alay edilmesi zor olan zor izlenen bağımlılıklar yaratır. new()wily-nilly kullanmaktan daha iyidir .)


Bir şey daha, hepsi Singletons ...

Ayrıca, her iki durumda da, açısalın bir singletonu yönetmenize yardımcı olduğunu unutmayın. Hizmetinizi veya işlevinizi nereye veya kaç kez enjekte ederseniz edin, aynı nesneye veya işleve aynı başvuruyu alırsınız. (Bir fabrikanın sadece sayı veya dize gibi bir değer döndürmesi hariç. Bu durumda, her zaman aynı değeri alırsınız, ancak bir başvuru elde edemezsiniz.)


2
Nesne kurucu olarak adlandırmak Yenilebilir olmaktan daha iyi olur mu?
marksyzm

2
@Hugo, her ikisinde de aynı şeyi etkili bir şekilde başarabileceğinizi gösteriyordum, sadece sözdizimi farklı olacak.
Gil Birman

105

10
Zaten "yeniye" demek için bir fiilimiz var, bu "anlık". Sadece referans için. :)
sscarduzio

7
Fabrikalar çağrılan işlevlerdir, böylece her şeyi döndürebilirler. Öte yandan, hizmetler açısal yoluyla başlatılır new fn(), bu nedenle bir örnek döndürmeleri gerekir.
Gil Birman

318

Basit ifadeyle ..

// Service
service = (a, b) => {
  a.lastName = b;
  return a;
};

// Factory
factory = (a, b) => Object.assign({}, a, { lastName: b });

const fullName = { firstName: 'john' };

// Service
const lastNameService = (a, b) => {
  a.lastName = b;
  return a;
};
console.log(lastNameService(fullName, 'doe'));

// Factory
const lastNameFactory = (a, b) => 
  Object.assign({}, a, { lastName: b })
console.log(lastNameFactory(fullName, 'doe'));


169
Dostum, teşekkürler. Diğer cevapların detaylarının geçerli olmadığını değil, ancak bazen 10 saniyelik sürüme ihtiyacınız var.
R Claven

4
Hizmet işlevinin hiçbir şey döndürmemesini sağlayın. This.name = ... o bir API açığa olduğunu göstermek için yeterlidir.
pixelbits

3
Ancak geri dönüp itiraz ederseniz, bunun yerine bunu kullanır. jsfiddle.net/Ne5P8/1221
MrB

@MrB, bu normal bir JavaScript özelliğidir, Angular veya bu sorunun bağlamına özgü değildir.
Om Shankar

@Om Shankar, Yukarıdaki cevap, farkın bunun döndürülen bir nesneye karşı kullanımı olduğunu gösteriyor. "BU" bir hizmet ile kullanılacak varsayılan değer olduğunu gösteriliyordu, ancak bir değer döndürürseniz neredeyse bir fabrika gibi davranacaktır. Bununla birlikte, kapak tarafında bir fabrika döndürülen bir değer gerektiriyor gibi görünüyor, başka bir hata oluşacak - (bu örnekte gösterilen - jsfiddle.net/hmoc0q3v/1 ).
MrB

247

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ğırmak için 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'i enjekte edilebilir bir argüman olarak bildirirken, iletilen işlev başvurusunu çağırarak döndürülen değer size sağlanacaktı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.

İşte hizmetler ve fabrika kullanarak örnek . Hakkında daha fazlasını okuyun Factory vs angularjs Servisi .

Ayrıca AngularJS belgelerini ve servisle fabrika arasındaki karışıklık gibi yığın akışı hakkında benzer soruları kontrol edebilirsiniz .


27
Örnek bir fabrika kullanımınıza katılmıyorum. Hem hizmetler hem de fabrikalar (bir fonksiyonun geri döndüğü varsayılarak. Sadece bir değer ya da nesne olabilir) yeni olabilir. Aslında bir işlev, size bir işlev örneği sağlandığından yenisi garanti edilen tek seçenektir. HİZMET üzerinde FABRİKA kullanmanın yararı, mülklere erişim üzerinde bir miktar kontrole izin vermesidir - özel ve kamuya açıkken, hizmetin tüm özellikleri doğaya açıktır. Ve bir sağlayıcıyı bir fabrikanın fabrikası olarak düşünüyorum - sadece yapılandırma zamanında enjekte edilebilir ve yapılandırılabilir.
Drew R

1
@DrewR Yorumunuz için teşekkür ederiz, bir Fabrika kullanarak genel ve özel yöntemlere iyi bir örnek buldum: stackoverflow.com/a/14904891/65025
edzillion

Aslında bu konuda @DrewR ile hemfikirim. Daha önce nesneleri iade etmek için fabrikaları kullandım, ama dürüst olmak gerekirse bu noktada $providersher zaman kullanmaya değer olabilir .
jedd.ahyoung

hizmet kurucuyu otomatik olarak başlatır, değil mi?
Martian2049

1
@DrewR - Anladığım kadarıyla, bir fabrikada olduğu gibi hizmetten aynı yeni 'efekti elde edebileceğiniz doğrudur, ancak bunun amacı yoktur. Temel amacı, sadece bir yardımcı program nesnesini döndürmek istediğinizde ve bunun için daha uygun bir sözdizimi sağlamasıdır - sadece this.myFunc = function(){}hizmetinize yazabilirsiniz (bir fabrikada yapmak zorunda olduğunuz nesneyi oluşturmak için kod yazmaktan sizi kurtarır) ).
BornToCode

137

TL; DR

1) Bir Fabrika kullanırken bir nesne yaratırsınız, ona özellikler ekler ve sonra aynı nesneyi döndürürsünüz. Bu fabrikayı denetleyicinize ilettiğinizde, nesne üzerindeki bu özellikler artık o denetleyicide fabrikanız aracılığıyla kullanılabilir.

app.controller('myFactoryCtrl', function($scope, myFactory){
  $scope.artist = myFactory.getArtist();
});

app.factory('myFactory', function(){
  var _artist = 'Shakira';
  var service = {};

  service.getArtist = function(){
    return _artist;
  }

  return service;
});


2) Hizmet'i kullandığınızda , Angular 'yeni' anahtar kelimesi ile sahne arkasını başlatır. Bu nedenle, 'this' öğesine özellikler eklersiniz ve hizmet 'this' öğesini döndürür. Hizmeti denetleyicinize ilettiğinizde, 'bu' öğesindeki özellikler artık hizmetiniz üzerinden bu denetleyicide kullanılabilir.

app.controller('myServiceCtrl', function($scope, myService){
  $scope.artist = myService.getArtist();
});

app.service('myService', function(){
  var _artist = 'Nelly';
  this.getArtist = function(){
    return _artist;
  }
});



TL olmayan; DR

1) Fabrika
Fabrikaları bir hizmet oluşturmak ve yapılandırmak için en popüler yoldur. TL'nin söylediğinden çok daha fazlası yok; DR. Sadece bir nesne yaratırsınız, ona bir özellik eklersiniz, sonra aynı nesneyi döndürürsünüz. Ardından fabrikayı denetleyicinize ilettiğinizde, nesne üzerindeki bu özellikler artık o denetleyicide fabrikanız aracılığıyla kullanılabilir olacaktır. Daha kapsamlı bir örnek aşağıdadır.

app.factory('myFactory', function(){
  var service = {};
  return service;
});

Artık 'myFactory' ürününü denetleyicimize ilettiğimizde, 'servise' eklediğimiz özellikleri kullanabiliriz.

Şimdi geri arama fonksiyonumuza bazı 'özel' değişkenler ekleyelim. Bunlara kontrolörden doğrudan erişilemez, ancak sonunda bu 'özel' değişkenleri gerektiğinde değiştirebilmek için 'hizmet' üzerine bazı alıcı / ayarlayıcı yöntemleri kuracağız.

app.factory('myFactory', function($http, $q){
  var service = {};
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
   _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK';
    return _finalUrl
  }

  return service;
});

Burada bu değişkenleri / işlevi 'servise' eklemediğimizi göreceksiniz. Daha sonra kullanmak veya değiştirmek için bunları oluşturuyoruz.

  • baseUrl, iTunes API'nın gerektirdiği temel URL'dir
  • _artist aramak istediğimiz sanatçı
  • _finalUrl, iTunes'a çağrı yapacağımız nihai ve tam olarak oluşturulmuş URL'dir makeUrl, iTunes dostu URL'imizi oluşturacak ve geri gönderecek bir işlevdir.

Artık yardımcı / özel değişkenlerimiz ve işlevimiz yerinde olduğuna göre, 'service' nesnesine bazı özellikler ekleyelim. Ne 'hizmet' koymak ne olursa olsun, 'myFactory' hangi denetleyici geçerse doğrudan kullanabilirsiniz.

Sadece sanatçıyı döndüren veya ayarlayan setArtist ve getArtist yöntemlerini oluşturacağız. Oluşturulan URL'mizle iTunes API'sini çağıracak bir yöntem de oluşturacağız. Bu yöntem, veriler iTunes API'sından geri geldiğinde yerine getirecek bir söz verecektir. Angular'da vaatler kullanma konusunda fazla deneyiminiz yoksa, onlara derin bir dalış yapmanızı şiddetle tavsiye ederim.

Aşağıda setArtist bir sanatçı kabul eder ve izin verir sen sanatçı ayarlamak için. getArtist , $ http isteğimizle kullanacağımız URL'yi oluşturmak için sanatçı callItunes ilk önce makeUrl () öğesini çağırır. Daha sonra bir söz nesnesi kurar, nihai URL'mizle $ http isteği yapar, daha sonra $ http bir söz verdiğinden, isteğimizden sonra .success veya .error öğesini çağırabiliriz. Daha sonra iTunes verileriyle olan sözümüzü çözüyoruz veya 'Bir hata oluştu' mesajını reddediyoruz.

app.factory('myFactory', function($http, $q){
  var service = {};
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  service.setArtist = function(artist){
    _artist = artist;
  }

  service.getArtist = function(){
    return _artist;
  }

  service.callItunes = function(){
    makeUrl();
    var deferred = $q.defer();
    $http({
      method: 'JSONP',
      url: _finalUrl
    }).success(function(data){
      deferred.resolve(data);
    }).error(function(){
      deferred.reject('There was an error')
    })
    return deferred.promise;
  }

  return service;
});

Şimdi fabrikamız tamamlandı. Artık herhangi bir denetleyiciye 'myFactory' enjekte edebiliyoruz ve daha sonra hizmet neslimize (setArtist, getArtist ve callItunes) eklediğimiz yöntemlerimizi çağırabiliyoruz.

app.controller('myFactoryCtrl', function($scope, myFactory){
  $scope.data = {};
  $scope.updateArtist = function(){
    myFactory.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myFactory.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }
});

Yukarıdaki kontrolörde 'myFactory' servisine enjekte ediyoruz. Daha sonra 'myFactory' verilerinden gelen $ scope nesnemizdeki özellikleri ayarlıyoruz. Yukarıdaki tek zor kod, daha önce hiç söz vermediyseniz. CallItunes bir söz veriyorsa, .then () yöntemini kullanabiliriz ve sözümüzü iTunes verileriyle yerine getirdikten sonra yalnızca $ scope.data.artistData ayarlayabiliriz. Denetleyicimizin çok 'ince' olduğunu fark edeceksiniz. Tüm mantık ve kalıcı verilerimiz denetleyicimizde değil, hizmetimizde bulunmaktadır.

2) Hizmet
Bir Hizmet oluştururken bilinmesi gereken en büyük şey, "yeni" anahtar kelimeyle somutlaştırılmasıdır. Sizin için JavaScript guruları, bu size kodun doğası hakkında büyük bir ipucu vermelidir. JavaScript'te sınırlı bir arka plana sahip olanlar veya 'yeni' anahtar kelimenin gerçekte ne yaptığına aşina olmayanlar için, sonunda bir Hizmetin doğasını anlamamıza yardımcı olacak bazı JavaScript temellerini inceleyelim.

'Yeni' anahtar kelimeyle bir işlevi çağırdığınızda meydana gelen değişiklikleri gerçekten görmek için, bir işlev oluşturalım ve onu 'yeni' anahtar kelimeyle çağıralım, ardından yorumlayıcının 'yeni' anahtar kelimeyi gördüğünde ne yaptığını gösterelim. Sonuçların her ikisi de aynı olacaktır.

Önce Yapımcımızı yaratalım.

var Person = function(name, age){
  this.name = name;
  this.age = age;
}

Bu tipik bir JavaScript yapıcı işlevidir. Şimdi "yeni" anahtar kelimesini kullanarak Kişi işlevini her çağırdığımızda, "bu" yeni oluşturulan nesneye bağlanır.

Şimdi Kişimizin prototipine bir yöntem ekleyelim, böylece Kişinin 'sınıfının' her örneğinde kullanılabilir.

Person.prototype.sayName = function(){
  alert('My name is ' + this.name);
}

Şimdi, sayName işlevini prototipe koyduğumuz için, Person'in her örneği, söz konusu adın adını uyarmak için sayName işlevini çağırabilecektir.

Şimdi kendi prototip üzerinde Kişi yapıcı fonksiyonumuza ve sayName fonksiyonumuza sahip olduğumuza göre, aslında bir Person örneği oluşturalım ve sonra sayName fonksiyonunu çağıralım.

var tyler = new Person('Tyler', 23);
tyler.sayName(); //alerts 'My name is Tyler'

Yani hep birlikte, bir Kişi yapıcısı oluşturma, prototipine bir işlev ekleme, bir Person örneği oluşturma ve daha sonra işlevi kendi prototipinde çağırmanın kodu şuna benzer.

var Person = function(name, age){
  this.name = name;
  this.age = age;
}
Person.prototype.sayName = function(){
  alert('My name is ' + this.name);
}
var tyler = new Person('Tyler', 23);
tyler.sayName(); //alerts 'My name is Tyler'

Şimdi JavaScript'te 'yeni' anahtar kelimeyi kullandığınızda gerçekte neler olduğuna bakalım. Dikkat etmemiz gereken ilk şey, örneğimizde 'new' kullandıktan sonra, tıpkı bir nesne gibi sanki 'tyler' üzerinde bir yöntemi (sayName) çağırabileceğimizdir - çünkü. İlk olarak, Kişi kurucumuzun bunu kodda görsün veya görmesek de bir nesneyi döndürdüğünü biliyoruz. İkincisi, sayName işlevimizin doğrudan Person örneğinde değil, prototip üzerinde yer alması nedeniyle, Person işlevinin döndürdüğü nesnenin başarısız aramalardaki prototipine temsilci olması gerektiğini biliyoruz. Daha basit bir ifadeyle, tyler.sayName () öğesini çağırdığımızda yorumlayıcı “Tamam, az önce oluşturduğumuz 'tyler' nesnesine bakacağım, sayName işlevini bulup onu çağıracağım. Bir dakika, burada görmüyorum - tek gördüğüm isim ve yaş, prototipi kontrol edeyim. Yup, prototipte gibi görünüyor, bırak diyeyim. ”.

Aşağıda, 'yeni' anahtar kelimenin JavaScript'te gerçekte ne yaptığını nasıl düşünebileceğinize ilişkin kod bulunmaktadır. Temel olarak yukarıdaki paragrafın bir kod örneğidir. 'Tercüman görünümünü' veya tercümanın notları içindeki kodu görme şeklini koydum.

var Person = function(name, age){
  //The line below this creates an obj object that will delegate to the person's prototype on failed lookups.
  //var obj = Object.create(Person.prototype);

  //The line directly below this sets 'this' to the newly created object
  //this = obj;

  this.name = name;
  this.age = age;

  //return this;
}

Şimdi 'yeni' anahtar kelimenin JavaScript'te gerçekte ne yaptığına dair bu bilgiye sahipken, Açısal bir Hizmet oluşturmak daha kolay olmalıdır.

Hizmet oluştururken anlamanız gereken en büyük şey, Hizmetlerin 'yeni' anahtar kelimesiyle somutlaştırıldığını bilmektir. Bu bilgiyi yukarıdaki örneklerimizle birleştirdiğinizde, şimdi özelliklerinizi ve yöntemlerinizi doğrudan 'bu' hizmete ekleyeceğinizi fark etmelisiniz ki bu daha sonra Hizmet'in kendisinden döndürülecektir. Buna eylemde bir göz atalım.

Başlangıçta Fabrika örneğiyle yaptığımızın aksine, bir nesne oluşturmamıza ve o nesneyi döndürmemize gerek yoktur, çünkü daha önce birçok kez belirtildiği gibi, 'yeni' anahtar kelimesini kullandık, böylece yorumlayıcı bu nesneyi oluşturacak, temsilci olsun bu prototip, o zaman biz işi yapmadan bizim için iade et.

İlk önce 'özel' ve yardımcı fonksiyonumuzu oluşturalım. Fabrikamızla aynı şeyi yaptığımız için bu çok tanıdık görünmelidir. Burada her satırın ne yaptığını açıklamayacağım çünkü fabrika örneğinde bunu yaptım, kafanız karıştıysa fabrika örneğini tekrar okuyun.

app.service('myService', function($http, $q){
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }
});

Şimdi, kontrol cihazımızda mevcut olacak tüm yöntemlerimizi 'buna' ekleyeceğiz.

app.service('myService', function($http, $q){
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  this.setArtist = function(artist){
    _artist = artist;
  }

  this.getArtist = function(){
    return _artist;
  }

  this.callItunes = function(){
    makeUrl();
    var deferred = $q.defer();
    $http({
      method: 'JSONP',
      url: _finalUrl
    }).success(function(data){
      deferred.resolve(data);
    }).error(function(){
      deferred.reject('There was an error')
    })
    return deferred.promise;
  }

});

Şimdi tıpkı fabrikamızda olduğu gibi, setArtist, getArtist ve callItunes, myService'i hangi denetleyiciye iletirsek kontrol edebiliriz. İşte myService denetleyicisi (neredeyse fabrika denetleyicimizle aynıdır).

app.controller('myServiceCtrl', function($scope, myService){
  $scope.data = {};
  $scope.updateArtist = function(){
    myService.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myService.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }
});

Daha önce de bahsettiğim gibi, 'yeni'nin ne yaptığını gerçekten anladıktan sonra, Hizmetler Angular'daki fabrikalarla neredeyse aynı.


12
Doğrudan blogunuza bir bağlantı sağlamak isteyebilirsiniz. tylermcginnis.com/angularjs-factory-vs-service-vs-provider Okumayı biraz daha kolay buldum.
Tyler Collier

3
Blogunuzu burada tekrarlamakla ilgili yanlış bir şey yok, ancak bunun bir greta blog yazısı olduğunu kabul ediyorum.
R Claven

5
Her birinin kaputun altında ne yaptığının iyi bir açıklaması, ancak birisinin bir Fabrikada bir Hizmeti kullanmayı neden ve ne zaman seçeceğini hala net değil. Başka bir deyişle, fabrika tarafından döndürülen nesneye karşı yeni bir nesneye sahip olmayı ne zaman tercih edeceğim. Bence bu en büyük karışıklık.
demisx

2
Temel olarak, sabit bir bağlantı (örn. Bağlantı durumu, arama geçmişi, veri depolama) ile örnekte belirtilen iTunes API gibi uzak bir hizmete kalıcı bir bağlantı oluşturmak istiyorsanız, Factory ile devam edebilirsiniz. Bir Hizmet olarak uygularsanız, API'dan her şey istediğinizde bağlantıyı yeniden oluşturursunuz ve içinde hiçbir şey depolayamazsınız. Çünkü hizmeti her yeniden oluşturduğunuzda boş / varsayılan bir nesne alırsınız.
Meki

4
Bunun doğru olduğunu düşünmüyorum, @Aznim. Diğerlerinin söylediği gibi, her ikisi de singleton sağlar.
Cryptovirus

35

İpucu adında

Hizmetler ve fabrikalar birbirine benzer. Her ikisi de diğer nesnelere enjekte edilebilen tek bir nesne verecektir ve bu yüzden genellikle birbirlerinin yerine kullanılabilir.

Farklı tasarım desenlerini uygulamak için anlamsal olarak kullanılmak üzere tasarlanmıştır.

Hizmetler, bir servis kalıbı uygulamak içindir

Hizmet kalıbı, uygulamanızın mantıksal olarak tutarlı işlevsellik birimlerine bölündüğü modeldir. Bir API erişimcisi veya bir iş mantığı kümesi buna örnek olarak verilebilir.

Bu, Açısal'da özellikle önemlidir, çünkü Açısal modeller genellikle bir sunucudan alınan JSON nesneleridir ve bu nedenle iş mantığımızı koymak için bir yere ihtiyacımız vardır.

Örneğin bir Github servisi. Github ile nasıl konuşulacağını biliyor. URL'leri ve yöntemleri bilir. Bir denetleyiciye enjekte edebiliriz ve bir söz üretecek ve geri verecektir.

(function() {
  var base = "https://api.github.com";

  angular.module('github', [])
    .service('githubService', function( $http ) {
      this.getEvents: function() {
        var url = [
          base,
          '/events',
          '?callback=JSON_CALLBACK'
        ].join('');
        return $http.jsonp(url);
      }
    });
  )();

Fabrikalar fabrika modelini uygular

Fabrikalar ise bir fabrika modeli uygulamaya yöneliktir. Bir nesne oluşturmak için fabrika işlevini kullandığımız bir fabrika deseni. Tipik olarak bunu model oluşturmak için kullanabiliriz. İşte bir Yazar yapıcı döndüren bir fabrika:

angular.module('user', [])
  .factory('User', function($resource) {
    var url = 'http://simple-api.herokuapp.com/api/v1/authors/:id'
    return $resource(url);
  })

Bunu şöyle kullanırız:

angular.module('app', ['user'])
  .controller('authorController', function($scope, User) {
    $scope.user = new User();
  })

Fabrikaların da tek ton döndürdüğünü unutmayın.

Fabrikalar bir kurucu iade edebilir

Bir fabrika yalnızca bir nesneyi döndürdüğü için, yukarıda gördüğümüz gibi, bir yapıcı işlevi de dahil olmak üzere istediğiniz herhangi bir nesne türünü döndürebilir.

Fabrikalar bir nesneyi döndürür; hizmetler yenidir

Diğer bir teknik fark, hizmetlerin ve fabrikaların oluşturulma şeklidir. Nesneyi oluşturmak için bir hizmet işlevi yeniden eklenecektir. Bir fabrika işlevi çağrılır ve nesneyi döndürür.

  • Hizmetler yeni kuruculardır.
  • Fabrikalar basitçe çağrılır ve bir nesne döndürür.

Bu, bir hizmette, bir kurucu bağlamında yapım aşamasında nesneyi gösterecek olan "buna" eklediğimiz anlamına gelir.

Bunu göstermek için, bir hizmet ve fabrika kullanılarak oluşturulan aynı basit nesne:

angular.module('app', [])
  .service('helloService', function() {
    this.sayHello = function() {
      return "Hello!";
    }
  })
  .factory('helloFactory', function() {
    return {
      sayHello: function() {
        return "Hello!";
      }
    }
  });

2
büyük açıklama, teşekkür ederim! Ayrıca enjektör parametresinin olması gereken Fabrikalar örnek kodunda bir tür vardır . AuthorPerson
mikhail-t

Teşekkürler @ mik-T, yazım hatalarını düzelttim.
superluminary

1
Hizmet desenini kullanımınız yanlış - bu bir fabrika olmalıdır. .Service () yerine .factory () öğesini çağırırsanız, bunun tam olarak aynı şekilde çalıştığını görürsünüz. Hizmet kalıbı, yeni bir nesne döndüren bir işlevle değil, bir yapıcı işleviyle sağlanmalıdır. Açısal (etkin) yapıcı işlevinizde "yeni" olarak adlandırır. Hizmetinizin çalışmasının tek nedeni, bir nesneyi döndüren bir yapıcı işlevinde "yeni" olarak adlandırılırsanız, aslında inşa edilmiş olandan ziyade döndürülen nesneyi geri almanızdır. Ve fabrikalar sadece modeller değil, istediğiniz her şeyi yaratmak için kullanılabilir.
Dan King

27

Buradaki tüm cevaplar hizmet ve fabrika etrafında görünüyor ve bu sorulan sorudan beri geçerli. Ama orada da dahil olmak üzere diğer bazı kişilerin olduğunu akılda tutmak da önemlidir provider(), value()ve constant().

Hatırlanması gereken anahtar, her birinin diğerinin özel bir durumu olduğudur. Her özel durum zincirle aynı şeyi daha az kodla yapmanızı sağlar. Her birinin ayrıca bazı ek sınırlamaları vardır.

Hangisini ne zaman kullanacağınıza karar vermek için hangisini daha az kodla istediğinizi yapmanıza izin verir. İşte ne kadar benzer olduklarını gösteren bir resim:

resim açıklamasını buraya girin

Adım adım dökümü ve ne zaman kullanılacağına dair hızlı başvuru için bu resmi aldığım blog gönderisini ziyaret edebilirsiniz:

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


3
@jacob belki de, ama bence her birinin ne zaman kullanılacağına dair genel bir kavram değil, hepsinin aslında aynı şeyin varyasyonları olduğu önemli.
Luis Perez

1
@LuisPerez Blogunuza ve videonun farkını açıklayan linke gerçekten harika. Videodan bu örneklerle anlaşılması daha kolay :)
Alin Ciocan

24

app.factory ('fn', fn) ile app.service ('fn', fn) karşılaştırması

İnşaat

Fabrikalarda Angular, sonucu almak için işlevi çağıracaktır. Önbelleğe alınan ve enjekte edilen sonuçtur.

 //factory
 var obj = fn();
 return obj;

Angular, hizmetler ile yeni arayarak yapıcı işlevini çağırır . Yapılan işlev önbelleğe alınır ve enjekte edilir.

  //service
  var obj = new fn();
  return obj;

uygulama

Fabrikalar genellikle bir nesne değişmez değeri döndürür , çünkü dönüş değeri denetleyicilere, çalışma bloklarına, yönergelere vb.

  app.factory('fn', function(){
         var foo = 0;
         var bar = 0;
         function setFoo(val) {
               foo = val;
         }
         function setBar (val){
               bar = val;
         }
         return {
                setFoo: setFoo,
                serBar: setBar
         }
  });

Servis fonksiyonları genellikle hiçbir şey döndürmez. Bunun yerine, başlatma ve açma işlevleri gerçekleştirirler. İşlevler ayrıca 'yeni' kullanılarak oluşturulduğundan 'buna' başvurabilir.

app.service('fn', function () {
         var foo = 0;
         var bar = 0;
         this.setFoo = function (val) {
               foo = val;
         }
         this.setBar = function (val){
               bar = val;
         }
});

Sonuç

Fabrikaları veya hizmetleri kullanmak söz konusu olduğunda, her ikisi de çok benzer. Bir denetleyiciye, direktiflere, çalışma bloğuna vb. Enjekte edilirler ve istemci kodunda hemen hemen aynı şekilde kullanılırlar. İkisi de tekil - yani aynı örnek servis / fabrikaya enjekte edilen tüm yerler arasında paylaşılıyor.

Peki hangisini tercih etmelisiniz? İkisinden biri - farklılıklar önemsiz olacak kadar benzerler. Birini diğerinden seçerseniz, nasıl inşa edildiğinin farkında olun, böylece onları düzgün bir şekilde uygulayabilirsiniz.


Hizmet işlevleri "hiçbir şey döndürmez", kendi dönüş deyiminizi belirtmezseniz (bu durumda, döndürdüğünüz nesne bir fabrikaya benzer şekilde oluşturulacak ve önbelleğe alınacak olan) oluşturulmuş nesneyi dolaylı olarak döndürür.
Cryptovirus

Sanırım yanlış yorumluyorsun ... Dönüş
dediğimde

fabrika da tek kasaba olduğundan emin misin?
Martian2049

5

Farkı anlamaya çalışmak için biraz zaman harcadım.

Ve ben fabrika fonksiyonu modül desen ve servis fonksiyonu standart java script yapıcı desen kullanır düşünüyorum.


2

Fabrika modeli, nesnelerin yanı sıra işlevleri ve değerleri döndürebileceğinden daha esnektir.

IMHO hizmet modelinde çok fazla bir nokta yok, yaptığı her şey bir fabrika ile kolayca yapabilirsiniz. İstisnalar şunlar olabilir:

  • Herhangi bir nedenden dolayı başlatılan hizmetinizin bildirilen türünü önemsiyorsanız - hizmet desenini kullanırsanız, kurucunuz yeni hizmetin türü olacaktır.
  • Başka bir yerde kullandığınız bir kurucu işleviniz varsa, hizmet olarak kullanmak istediğiniz de (buna bir şey enjekte etmek istiyorsanız muhtemelen çok fazla kullanılmaz!).

Muhtemelen, hizmet deseni sözdizimi açısından yeni bir nesne oluşturmak için biraz daha güzel bir yoldur, ancak aynı zamanda örneklemek daha pahalıdır. Diğerleri açısal hizmet oluşturmak için "yeni" kullandığını, ancak bu tam olarak doğru değildir - bunu yapamaz çünkü her hizmet kurucu farklı sayıda parametre var. Aslında açısal, yapıcı işlevinizi sarmak için fabrika modelini dahili olarak kullanmaktır. Daha sonra, javascript'in "yeni" operatörünü simüle etmek , kurucunuzu değişken sayıda enjekte edilebilir argümanla çağırmak için bazı akıllı jiggery pokery yapar - ancak sadece fabrika modelini doğrudan kullanırsanız, bu nedenle kodu.


Fabrikalar nispeten pahalı kapamalar kullandığından ve hizmetler (sınıflar) prototipten yararlanabileceğinden, hizmetler fabrikalardan daha etkilidir.
jacob

@jacob Kapaklar hakkında ne demek istediğinizden emin değil misiniz? Fabrika sadece bir nesneyi döndüren bir fonksiyondur. Bir kapatma işlemini yalnızca döndürülen nesneniz "özel" durum gerektiriyorsa kullanmanız gerekir. Bir yapıcı (hizmet) kullandıysanız da aynı şeyi yapmanız gerekir. Yine de prototip konusundaki fikrinizi anlıyorum - isterseniz bunu bir fabrikada da yapabilirsiniz.
Dan King

function MyFactory(dep1) { var $$foo = 'bar', factory = {}; Object.defineProperties(factory.prototype, { foo: { value: $$foo } }); return factory; } function MyService(dep1) { var $$foo = 'bar'; Object.defineProperties(MyService.prototype, { foo: { value: $$foo } }); } Hem MyFactory hem de MyService prototip kullanırken, MyFactory yine de döndürülen nesneyi oluşturmak için bir performans isabeti alıyor. Her iki örnekte de ayrıcalıkları vardır, ancak MyService'te nispeten hiçbir performans farkı yoktur.
jacob

1
Benim için fark, fabrikayı doğrudan bir yöntem olmadan kullanmak isteyip istemediğim: MyFactory(someArgument)(örn. $http()). Yani yapıcı referans olurdu gibi bir hizmet ile mümkün değildir: MyService(someArgument).
jacob

Nesne yapım zamanında, gerçekten fabrika = {} bir performans hit olduğunu görmüyorum, javascript kurucu çağırdığında sizin için "bu" initialis daha fazla? Ve bence daha büyük performans, kurucunuzu bir fabrikaya sardığında ve sonra "yeni" yi simüle etmek için çemberlerden atlamak zorunda kalıyor, böylece bağımlılıklarınızı enjekte edebilir.
Dan King
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.