AngularJS: Servis vs sağlayıcı vs fabrika


3319

Bir arasındaki farklar nelerdir Service, Providerve Factoryangularjs içinde?


244
Tüm Açısal terimlerin yeni başlayanlar için korkutucu olduğunu gördüm. Angular demisx.github.io/angularjs/2014/09/14/… 'ı öğrenirken programcılarımızın anlaması biraz daha kolay olan bu hile sayfasıyla başladık . Umarım bu da takımınıza yardımcı olur.
demisx

7
Bana göre, farkı anlamanın en iyi yolu Angular'ın kendi belgelerini kullanmaktır: docs.angularjs.org/guide/providers son derece iyi açıklanmıştır ve bunu anlamanıza yardımcı olacak tuhaf bir örnek kullanır.
Rafael Merlin

3
@Blaise Teşekkürler! Gönderideki yorumuma göre, kasten dışarıda bıraktım, çünkü deneyimimdeki kullanım vakalarının% 99'u başarıyla ele alınabilir service.factory. Bu konuyu daha da karmaşıklaştırmak istemiyordu.
16'da

3
Bu tartışmayı da çok faydalı buluyorum stackoverflow.com/questions/18939709/…
Anand Gupta

3
İşte bazı iyi cevaplar konusundaservices,factoriesveproviderseserleri.
Mistalis

Yanıtlar:


2866

AngularJS posta listesinden , fabrikaya karşı servis sağlayıcıya ve bunların enjeksiyon kullanımına ilişkin inanılmaz bir iş parçacığı aldım . Cevapların derlenmesi:

Hizmetler

Sözdizimi: module.service( 'serviceName', function );
Sonuç: serviceName öğesini enjekte edilebilir bir bağımsız değişken olarak bildirirken , işlevin bir örneğini alırsınız. Başka bir deyişle new FunctionYouPassedToService() .

Fabrikalar

Sözdizimi: module.factory( 'factoryName', function );
Sonuç: factoryName öğesini enjekte edilebilir bir bağımsız değişken olarak bildirirken, module.factory öğesine iletilen işlev başvurusunu çağırarak döndürülen değer size sağlanacaktır .

Sağlayıcıları

Sözdizimi: module.provider( 'providerName', function );
Sonuç: Sağlayıcı adını enjekte edilebilir bir argüman olarak bildirirken size sağlanacaktır (new ProviderFunction()).$get() . Yapıcı işlevi, $ get yöntemi çağrılmadan önce başlatılır - ProviderFunctionmodule.provider öğesine iletilen işlev başvurusudur.

Sağlayıcılar modül yapılandırma aşamasında yapılandırılabilme avantajına sahiptir.

Sağlanan kod için buraya bakın .

İşte Misko'nun daha fazla açıklaması:

provide.value('a', 123);

function Controller(a) {
  expect(a).toEqual(123);
}

Bu durumda, enjektör değeri olduğu gibi döndürür. Ama ya değeri hesaplamak istiyorsan? Sonra bir fabrika kullanın

provide.factory('b', function(a) {
  return a*2;
});

function Controller(b) {
  expect(b).toEqual(246);
}

Bu factory, değeri yaratmaktan sorumlu bir işlevdir. Fabrika fonksiyonunun diğer bağımlılıkları isteyebileceğine dikkat edin.

Peki ya daha çok OO olmak ve Greeter adında bir sınıfa sahip olmak istiyorsanız?

function Greeter(a) {
  this.greet = function() {
    return 'Hello ' + a;
  }
}

Daha sonra, yazmak için

provide.factory('greeter', function(a) {
  return new Greeter(a);
});

Sonra kontrolörde böyle 'selam' isteyebiliriz

function Controller(greeter) {
  expect(greeter instanceof Greeter).toBe(true);
  expect(greeter.greet()).toEqual('Hello 123');
}

Ama bu çok garip. Bunu yazmanın daha kısa bir yoluprovider.service('greeter', Greeter);

Peki ya Greeterenjeksiyondan önce sınıfı yapılandırmak isteseydik ? Sonra yazabiliriz

provide.provider('greeter2', function() {
  var salutation = 'Hello';
  this.setSalutation = function(s) {
    salutation = s;
  }

  function Greeter(a) {
    this.greet = function() {
      return salutation + ' ' + a;
    }
  }

  this.$get = function(a) {
    return new Greeter(a);
  };
});

Sonra bunu yapabiliriz:

angular.module('abc', []).config(function(greeter2Provider) {
  greeter2Provider.setSalutation('Halo');
});

function Controller(greeter2) {
  expect(greeter2.greet()).toEqual('Halo 123');
}

Bir not olarak, service, factoryve valueher sağlayıcıdan elde edilir.

provider.service = function(name, Class) {
  provider.provide(name, function() {
    this.$get = function($injector) {
      return $injector.instantiate(Class);
    };
  });
}

provider.factory = function(name, factory) {
  provider.provide(name, function() {
    this.$get = function($injector) {
      return $injector.invoke(factory);
    };
  });
}

provider.value = function(name, value) {
  provider.factory(name, function() {
    return value;
  });
};

58
Ayrıca , servis ve fabrika arasındaki farkları tartışan stackoverflow.com/a/13763886/215945 adresine bakın .
Mark Rajcok

3
611'de açısal sabitlerin ve değerlerin kullanımını ekledim. Diğerinin farklarını göstermek için zaten gösteriliyor. jsbin.com/ohamub/611/edit
Nick

17
Hizmet çağrılmasına rağmen işlevin bir örneği oluşturulur. Aslında her enjektör için sadece bir kez yaratılır, bu da onu singleton gibi yapar. docs.angularjs.org/guide/dev_guide.services.creating_services
angelokh

33
Bu örnek, açık bir pratik örnek kullansaydı inanılmaz olabilir. Şeylerin ne anlama geldiğini toEqualve ne olduğunu anlamaya çalışırken kayboluyorum greeter.Greet. Neden biraz daha gerçek ve ilişkilendirilebilir bir şey kullanmıyorsunuz?
Kyle Pennell

5
Wait () işlevini kullanmak, bir şeyi açıklamak için kötü bir seçimdir. Bir dahaki sefere gerçek dünya kodunu kullanın.
Craig

812

JS Fiddle Demosu

factory/ service/ İle "Merhaba dünya" örneği 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() {

    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 src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="MyCtrl">
    {{hellos}}
</div>
</body>


2
İşlevdeki thisbağlamı değiştirmez $getmi? - artık bu işlevdeki örnek sağlayıcıya başvurmuyorsunuz.
Nate-Wilkins

12
@Nate: thisaslında bağlamı değiştirmez, çünkü çağrılan şey new Provider(). $ Get (), burada Providerfonksiyonun geçildiği yerdir app.provider. Yani $get()bu inşa edilmiş bir yöntem olarak adlandırılmaktadır Provider, bu yüzden örnekte belirtildiği gibi thisatıfta bulunacaktır Provider.
Brandon

1
@Brandon Ohh tamam o zaman temiz. İlk bakışta kafa karıştırıcı - açıklama için teşekkürler!
Nate-Wilkins

3
Bunu Unknown provider: helloWorldProvider <- helloWorldyerel olarak çalıştırırken neden alıyorum ? Yorumlamak, diğer 2 örnek için aynı hata. Gizli sağlayıcı yapılandırması var mı? (Açısal 1.0.8) - Bulunan: stackoverflow.com/questions/12339272/…
Antoine

4
@Antoine'in "Bilinmeyen sağlama: helloWorldProvider" hatasını almasının nedeni, .config kodunuzda 'helloWorldProvider' kullanmanızdır, ancak sağlayıcıyı myApp.provider'da ('helloWorld', function ()) kullandığınızda, 'Selam Dünya'? Başka bir deyişle, yapılandırma kodunuzda açısal, helloWorld sağlayıcısına başvurduğunuzu nasıl bilir? Teşekkürler
jmtoung

645

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 kullanırken , AngularJS 'yeni' anahtar kelimesi ile bunları sahne arkasında 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;
  }
});



3) Sağlayıcılar .config () işlevinize iletebileceğiniz tek hizmettir. Hizmet nesneniz için kullanılabilir hale getirmeden önce modül çapında yapılandırma sağlamak istediğinizde bir sağlayıcı kullanın.

app.controller(‘myProvider’, function($scope, myProvider){
  $scope.artist = myProvider.getArtist();
  $scope.data.thingFromConfig = myProvider.thingOnConfig;
});

app.provider(‘myProvider’, function(){
 //Only the next two lines are available in the app.config()
 this._artist = ‘’;
 this.thingFromConfig = ‘’;
  this.$get = function(){
    var that = this;
    return {
      getArtist: function(){
        return that._artist;
      },
      thingOnConfig: that.thingFromConfig
    }
  }
});

app.config(function(myProviderProvider){
  myProviderProvider.thingFromConfig = This was set in config’;
});



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'u arayacağımız nihai ve tam olarak oluşturulmuş URL'dir
  • makeUrl, iTunes uyumlu URL'imizi yaratacak 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 doğrudan 'myFactory' geçmek hangi denetleyici içine kullanılabilir.

Sadece sanatçıyı döndüren veya ayarlayan setArtist ve getArtist yöntemlerini oluşturacağız. Ayrıca, oluşturulan URL'mizle iTunes API'sini çağıracak bir yöntem oluşturacağız. Bu yöntem, veriler iTunes API'sından geri geldiğinde yerine getirecek bir söz verecektir. AngularJS'de 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 sanatçıyı iade eder. callItunes , $ http isteğimizle kullanacağımız URL'yi oluşturmak için ö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' öğesinden gelen verilerle $ 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 (Bu iyi bir kodlama uygulamasıdır). 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 below line creates an object(obj) 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 'new' anahtar kelimesinin JavaScript'te gerçekte ne yaptığına dair bu bilgiye sahip olmak, AngularJS'de bir Hizmet oluşturmak daha kolay anlaşılmalı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 belirttiğim gibi, 'yeni'nin ne yaptığını gerçekten anladıktan sonra, Hizmetler AngularJS'deki fabrikalarla neredeyse aynıdır.

3) Sağlayıcı

Sağlayıcılar hakkında hatırlanması gereken en büyük şey, uygulamanızın app.config bölümüne geçirebileceğiniz tek hizmet olmasıdır. Hizmet nesnenizin bir kısmını, uygulamanızın başka her yerinde kullanılabilir duruma getirmeden değiştirmeniz gerekiyorsa, bu çok önemlidir. Hizmetlere / Fabrikalara çok benzemesine rağmen, tartışacağımız birkaç farklılık var.

Öncelikle, Hizmet ve Fabrikamızda yaptığımız şekilde Sağlayıcımızı kurduk. Aşağıdaki değişkenler bizim 'özel' ve yardımcı fonksiyonumuzdur.

app.provider('myProvider', function(){
   var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  //Going to set this property on the config function below.
  this.thingFromConfig = ‘’;

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

* Yine yukarıdaki kodun herhangi bir kısmı kafa karıştırıcıysa, hepsinin daha fazla ayrıntı yaptığını açıkladığım Fabrika bölümüne bakın.

Sağlayıcıları üç bölüme sahip olarak düşünebilirsiniz. İlk bölüm, daha sonra değiştirilecek / ayarlanacak (yukarıda gösterilen) 'özel' değişkenler / işlevlerdir. İkinci bölüm, app.config işlevinizde kullanılabilecek olan değişkenler / işlevlerdir ve bu nedenle başka bir yerde kullanılabilir olmadan önce değiştirilebilecekler (yukarıda da gösterilmiştir). Bu değişkenlerin 'this' anahtar kelimesine iliştirilmesi gerektiğine dikkat etmek önemlidir. Örneğimizde, app.config dosyasında yalnızca 'thingFromConfig' seçeneği kullanılabilir. Üçüncü bölüm (aşağıda gösterilmiştir) 'myProvider' hizmetini belirli bir denetleyiciye aktardığınızda denetleyicinizde kullanılabilecek tüm değişkenler / işlevlerdir.

Sağlayıcı ile bir hizmet oluştururken, denetleyicinizde kullanılabilecek tek özellik / yöntem, $ get () işlevinden döndürülen özellikler / yöntemlerdir. Aşağıdaki kod $ get 'this' değerini koyar (bu fonksiyonun sonunda geri döndürüleceğini biliyoruz). Şimdi, $ get işlevi denetleyicide kullanılabilir olmasını istediğimiz tüm yöntemleri / özellikleri döndürür. İşte bir kod örneği.

this.$get = function($http, $q){
    return {
      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;
      },
      setArtist: function(artist){
        _artist = artist;
      },
      getArtist: function(){
        return _artist;
      },
      thingOnConfig: this.thingFromConfig
    }
  }

Şimdi tam Sağlayıcı kodu şuna benziyor

app.provider('myProvider', function(){
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  //Going to set this property on the config function below
  this.thingFromConfig = '';

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

  this.$get = function($http, $q){
    return {
      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;
      },
      setArtist: function(artist){
        _artist = artist;
      },
      getArtist: function(){
        return _artist;
      },
      thingOnConfig: this.thingFromConfig
    }
  }
});

Şimdi tıpkı fabrikamızda ve Servisimizde olduğu gibi, setArtist, getArtist ve callItunes, myProvider'ı hangi denetleyiciden geçirdiğimizde kullanılabilir. İşte myProvider denetleyicisi (fabrika / Hizmet denetleyicimizle neredeyse aynı).

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

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

  $scope.data.thingFromConfig = myProvider.thingOnConfig;
});

Daha önce de belirtildiği gibi, Sağlayıcı ile bir hizmet oluşturmanın tüm amacı, son nesne uygulamanın geri kalanına geçirilmeden önce app.config işlevi aracılığıyla bazı değişkenleri değiştirebilmektir. Bunun bir örneğini görelim.

app.config(function(myProviderProvider){
  //Providers are the only service you can pass into app.config
  myProviderProvider.thingFromConfig = 'This sentence was set in app.config. Providers are the only service that can be passed into config. Check out the code to see how it works';
});

Şimdi 'thingFromConfig' öğesinin sağlayıcımızda nasıl boş bir dize olduğunu görebilirsiniz, ancak bu DOM'da göründüğünde 'Bu cümle ayarlandı…' olacaktır.


11
Bu mükemmel yazımda eksik olan tek parça, hizmeti bir fabrikada kullanmanın göreceli avantajlarıdır; Lior tarafından kabul edilen cevapta açıkça açıklanmıştır
sonsuzluk

2
FWIW (belki çok değil), burada açısal meselesini ele alır bir blogcu olduğunu ve providerProvider sevmez codeofrob.com/entries/you-have-ruined-javascript.html
barlop

3
'JavaScript guru' delme çizgisi kurnazdı. : Bu cevabın işleri çok temizlediğini düşünüyorum. Mükemmel yazılmış.
amarmishra

4
TLDR'nizin bir TLDR'ye ihtiyacı var.
JensB

3
@JensB tl; dr - Reaksiyonu Öğrenin.
Tyler McGinnis

512

Tüm Hizmetler tekil ; uygulama başına bir kez örneklenirler. Bunlar olabilir herhangi bir tür ilkel bir nesne gerçek, fonksiyon ya da özel bir türü, hatta bir örneği olsun.

value, factory, service, constant, Ve provideryöntemleri tüm sağlayıcılar vardır. Enjektöre Hizmetleri nasıl somutlaştıracaklarını öğretirler.

En ayrıntılı, aynı zamanda en kapsamlı olanı bir Sağlayıcı tarifi. Kalan dört tarifi türleri - Değer, Fabrika, Hizmet ve Sabit - Bir sağlayıcı tarifi üstünde bir sözdizim güzelliğidir .

  • Değer Tarif Eğer servis uygula kendinizi örneğini ve sağlamak en basit durumda, bir örneklenmiş değeri enjektöre.
  • Fabrika tarifi bu hizmeti örneğini gerektiğinde o çağıran Enjektör fabrika fonksiyonunu verir. Çağrıldığında, fabrika işlevi hizmet örneğini oluşturur ve döndürür. Hizmetin bağımlılıkları işlevlerin argümanları olarak enjekte edilir. Bu tarifi kullanmak aşağıdaki yetenekleri ekler:
    • Diğer hizmetleri kullanabilme (bağımlılıkları olan)
    • Hizmet başlatma
    • Gecikmeli / tembel başlatma
  • Servis tarifi neredeyse Fabrika tarifi aynıdır, ama burada Enjektör bir çağıran yapıcısı yeni operatör yerine bir fabrika fonksiyonu ile.
  • Sağlayıcı tarifi genellikle overkill . Fabrikanın oluşturulmasını yapılandırmanıza izin vererek bir dolaylı katman daha ekler.

    Sağlayıcı tarifini yalnızca, uygulama başlamadan önce yapılması gereken uygulama genelinde yapılandırma için bir API'yi ortaya çıkarmak istediğinizde kullanmalısınız. Bu, genellikle davranışları uygulamalar arasında biraz değişmesi gerekebilecek yeniden kullanılabilir hizmetler için ilginçtir.

  • Sabit tarifi sadece sen bulunan servislere tanımlamanızı sağlar haricinde Değer tarifi gibidir yapılandırma safhasında. Değer tarifi kullanılarak oluşturulan hizmetlerden daha erken. Değerlerin aksine, kullanılarak dekore edilemezler decorator.
Sağlayıcı belgelerine bakın .


2
Peki hizmet ve fabrika aslında aynı mı? Diğerlerinden birini kullanmak alternatif sözdiziminden başka bir şey sağlamaz mı?
Matt

2
@Matt, evet, hizmet olarak açığa çıkarmak istediğiniz kendi işleviniz zaten olduğunda hizmet özlü bir yoldur. Dokümanlardan: myApp.factory ('unicornLauncher', ["apiToken", işlev (apiToken) {yeni UnicornLauncher (apiToken);}]); vs: myApp.service ('unicornLauncher', ["apiToken", UnicornLauncher]);
Janek

5
@joshperry Bir acemi olarak, bir süredir hizmet ve fabrika arasındaki farkı araştırdım. Bunun en iyi cevap olduğunu kabul ediyorum! Bazı özel özelliklere sahip bir hizmet sınıfı (örn. Kodlayıcı / kod çözücü sınıfı) olarak hizmet anladım. Ve fabrika bir dizi durumsuz yardımcı yöntem sağlar.
stanleyxu2005

3
Yukarıdaki diğer cevaplardaki Yaa örnekleri, bu tariflerin başlatıldığı sırada enjekte edilen temel s / b hizmetleri ve sağlayıcıları arasındaki farkı çok açık bir şekilde açıklayamamaktadır.
Ashish Singh

223

AngularJS Fabrikasını, Hizmetini ve Sağlayıcısını Anlama

Bunların hepsi yeniden kullanılabilir tekli nesneleri paylaşmak için kullanılır. Yeniden kullanılabilir kodu uygulamanızda / çeşitli bileşenlerde / modüllerde paylaşmanıza yardımcı olur.

Dokümanlar Hizmetinden / Fabrikadan :

  • Tembel olarak başlatılmış - Açısal yalnızca bir hizmet bileşeni / fabrika, bir uygulama bileşeni buna bağlı olduğunda başlatır.
  • Tek Tonlar - Bir hizmete bağımlı her bileşen, hizmet fabrikası tarafından oluşturulan tek örneğe başvuru alır.

Fabrika

Fabrika, bir nesne oluşturmadan önce mantığı değiştirebileceğiniz / ekleyebileceğiniz bir işlevdir, daha sonra yeni oluşturulan nesne döndürülür.

app.factory('MyFactory', function() {
    var serviceObj = {};
    //creating an object with methods/functions or variables
    serviceObj.myFunction = function() {
        //TO DO:
    };
    //return that object
    return serviceObj;
});

kullanım

Sadece bir sınıf gibi bir işlevler topluluğu olabilir. Bu nedenle, kontrolörünüze / fabrika / yönerge işlevlerinize enjekte ettiğinizde farklı kontrolörlerde başlatılabilir. Uygulama başına yalnızca bir kez başlatılır.

Hizmet

Sadece hizmetlere bakarken dizi prototipi hakkında düşünün. Hizmet, 'yeni' anahtar kelimeyi kullanarak yeni bir nesneyi başlatan bir işlevdir. thisAnahtar kelimeyi kullanarak bir hizmet nesnesine özellikler ve işlevler ekleyebilirsiniz . Bir fabrikadan farklı olarak, hiçbir şey döndürmez (yöntemler / özellikler içeren bir nesne döndürür).

app.service('MyService', function() {
    //directly binding events to this context
    this.myServiceFunction = function() {
        //TO DO:
    };
});

kullanım

Uygulama boyunca tek bir nesneyi paylaşmanız gerektiğinde kullanın. Örneğin, kimliği doğrulanmış kullanıcı ayrıntıları, paylaşılabilir yöntemler / veriler, Yardımcı İşlevler vb.

Sağlayıcı

Bir sağlayıcı yapılandırılabilir bir hizmet nesnesi oluşturmak için kullanılır. Servis ayarını yapılandırma işlevinden yapılandırabilirsiniz. $get()İşlevi kullanarak bir değer döndürür . $getİşlev açısal olarak çalıştırma faz üzerinde çalıştırılmaktadır.

app.provider('configurableService', function() {
    var name = '';
    //this method can be be available at configuration time inside app.config.
    this.setName = function(newName) {
        name = newName;
    };
    this.$get = function() {
        var getName = function() {
             return name;
        };
        return {
            getName: getName //exposed object to where it gets injected.
        };
    };
});

kullanım

Hizmet nesnenizi kullanılabilir hale getirmeden önce modül açısından yapılandırma sağlamanız gerektiğinde, ör. Eğer sevdiği Çevre temelinde API URL'sini ayarlamak istediğiniz varsayalım dev, stageyaprod

NOT

Hizmet ve fabrika mevcut değilken, açısal yapılandırma aşamasında yalnızca sağlayıcı kullanılabilir.

Umarım bu, Fabrika, Hizmet ve Sağlayıcı hakkındaki anlayışınızı ortadan kaldırmıştır .


1
Belirli bir arabirime sahip bir hizmete sahip olmak, ancak iki farklı uygulamaya sahip olmak ve her birini bir denetleyiciye enjekte etmek, ancak ui-yönlendirici kullanarak farklı durumlara bağlı olmak istersem ne yapardım? örneğin bir durumda uzaktan arama yapın, ancak başka bir durumda yerel depolama alanına yazın. Sağlayıcı dokümanlar kullanmayı söylüyor only when you want to expose an API for application-wide configuration that must be made before the application starts. This is usually interesting only for reusable services whose behavior might need to vary slightly between applications, bu yüzden kulağa mümkün değil, değil mi?
qix

191

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 sonra 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'nin kayıtlı değeri koşmaktan gelir fn.
  2. bdepolanan değeri newing fn.
  3. c'depolandığını değeri, ilk olarak, bir örneği alma gelen newing fnve çalışan bir $getörneğinin yöntemi.

Bu, AngularJS içinde her enjeksiyonun değeri yalnızca bir kez, ilk kez enjekte edildiğinde ve bir kez atandığında önbellek nesnesi gibi bir şey olduğu anlamına gelir:

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 .


2
Ben de bu cevabı en çok seviyorum. Hepsinin amacı DI üzerinden ihtiyaç duyulduğunda bir nesneye erişim sağlamaktır. Normalde factorys ile iyi gidiyorsun . Var olmasının tek nedeni serviceCoffeeScript, TypeScript, ES6 vb. Dillerdir, böylece sınıf sözdizimlerini kullanabilirsiniz. İhtiyacınız providerModülünüzün kullanarak farklı ayarlara sahip çeşitli uygulamalarda kullanılan yalnızca s app.config(). Hizmetiniz saf bir singletonsa veya bir şeyin örneklerini oluşturabiliyorsa, yalnızca uygulamanıza bağlıdır.
Andreas Linnert

137

Servis vs sağlayıcı vs fabrika:

Basit tutmaya çalışıyorum. Her şey temel JavaScript konseptiyle ilgilidir.

Her şeyden önce, AngularJS'deki hizmetler hakkında konuşalım !

Hizmet Nedir: AngularJS'de Hizmetbazı yararlı yöntemleri veya özellikleri depolayabilen tek bir JavaScript nesnesinden başka bir şey değildir. Bu singleton nesnesi ngApp (Angular app) esasına göre oluşturulur ve mevcut uygulama içindeki tüm kontrolörler arasında paylaşılır. Angularjs bir hizmet nesnesini başlatırken, bu hizmet nesnesini benzersiz bir hizmet adıyla kaydeder. Hizmet örneğine her ihtiyaç duyduğumuzda, Açısal kayıt defterinde bu hizmet adı için arama yapar ve başvuruyu hizmet nesnesine döndürür. Servis nesnesi üzerinde yöntem, erişim özellikleri vb. Denetleyicilerin kapsam nesnesine özellikler, yöntemler de ekleyip ekleyemeyeceğinizle ilgili sorularınız olabilir! Peki neden servis nesnesine ihtiyacınız var? Cevaplar: hizmetler çoklu denetleyici kapsamı arasında paylaşılır. Bazı özellikleri / yöntemleri bir denetleyicinin kapsam nesnesine koyarsanız, yalnızca geçerli kapsamda kullanılabilir.

Üç denetleyici kapsamı varsa, denetleyiciA, denetleyiciB ve denetleyiciC olsun, hepsi aynı hizmet örneğini paylaşacaktır.

<div ng-controller='controllerA'>
    <!-- controllerA scope -->
</div>
<div ng-controller='controllerB'>
    <!-- controllerB scope -->
</div>
<div ng-controller='controllerC'>
    <!-- controllerC scope -->
</div>

Hizmet nasıl oluşturulur?

AngularJS bir servisi kaydetmek için farklı yöntemler sunar. Burada fabrika (..), servis (..), sağlayıcı (..);

Kod başvurusu için bu bağlantıyı kullanın

Fabrika fonksiyonu:

Bir fabrika fonksiyonunu aşağıdaki gibi tanımlayabiliriz.

factory('serviceName',function fnFactory(){ return serviceInstance;})

AngularJS , serviceName ve JavaScript işlevi olmak üzere iki parametre alan 'factory (' serviceName ', fnFactory)' yöntemini sağlar. Açısal, aşağıdaki gibi fnFactory () işlevini çağırarak hizmet örneği oluşturur .

var serviceInstace = fnFactory();

Aktarılan işlev bir nesneyi tanımlayabilir ve o nesneyi döndürebilir. AngularJS basitçe bu nesne başvurusunu ilk argüman olarak iletilen bir değişkene depolar. FnFactory'den döndürülen her şey serviceInstance öğesine bağlı olacaktır. Nesne döndürmek yerine, işlev, değerler vb.

Misal:

var app= angular.module('myApp', []);
//creating service using factory method
app.factory('factoryPattern',function(){
  var data={
    'firstName':'Tom',
    'lastName':' Cruise',
    greet: function(){
      console.log('hello!' + this.firstName + this.lastName);
    }
  };

  //Now all the properties and methods of data object will be available in our service object
  return data;
});

Hizmet Fonksiyonu:

service('serviceName',function fnServiceConstructor(){})

Başka bir yol, bir hizmet kaydedebiliriz. Tek fark AngularJS'nin hizmet nesnesini somutlaştırmaya çalışmasıdır. Bu kez açısal 'new' anahtar sözcüğünü kullanır ve yapıcı işlevine aşağıdaki gibi bir şey çağırır.

var serviceInstance = new fnServiceConstructor();

Yapıcı işlevinde, hizmet nesnesine özellikler / yöntemler eklemek için 'this' anahtar sözcüğünü kullanabiliriz. misal:

//Creating a service using the service method
var app= angular.module('myApp', []);
app.service('servicePattern',function(){
  this.firstName ='James';
  this.lastName =' Bond';
  this.greet = function(){
    console.log('My Name is '+ this.firstName + this.lastName);
  };
});

Sağlayıcı işlevi:

Sağlayıcı () işlevi, hizmet oluşturmanın başka bir yoludur. Kullanıcıya karşılama mesajı görüntüleyen bir hizmet oluşturmakla ilgilenelim. Ancak, kullanıcının kendi karşılama iletisini ayarlayabileceği bir işlev de sunmak istiyoruz. Teknik açıdan yapılandırılabilir hizmetler oluşturmak istiyoruz. Bunu nasıl yapabiliriz? Uygulamanın özel karşılama mesajlarını geçebilmesi için bir yol olmalı ve Angularjs bunu hizmetler örneğimizi oluşturan fabrika / kurucu işlevi için kullanılabilir hale getirecektir. Böyle bir durumda sağlayıcı () işlevi işi yapar. sağlayıcı () işlevini kullanarak yapılandırılabilir hizmetler oluşturabiliriz.

Aşağıda verilen sağlayıcı sözdizimini kullanarak yapılandırılabilir hizmetler oluşturabiliriz.

/*step1:define a service */
app.provider('service',function serviceProviderConstructor(){});

/*step2:configure the service */
app.config(function configureService(serviceProvider){});

Sağlayıcı sözdizimi dahili olarak nasıl çalışır?

1.Provider nesnesi, sağlayıcı işlevimizde tanımladığımız yapıcı işlevi kullanılarak oluşturulur.

var serviceProvider = new serviceProviderConstructor();

2. app.config () 'de geçirdiğimiz işlev yürütülür. Buna config aşaması denir ve burada hizmetimizi özelleştirme şansımız vardır.

configureService(serviceProvider);

3. son olarak hizmet örneği $ get serviceProvider yöntemi çağrılarak oluşturulur.

serviceInstance = serviceProvider.$get()

Sağlama sözdizimini kullanarak hizmet oluşturmak için örnek kod:

var app= angular.module('myApp', []);
app.provider('providerPattern',function providerConstructor(){
  //this function works as constructor function for provider
  this.firstName = 'Arnold ';
  this.lastName = ' Schwarzenegger' ;
  this.greetMessage = ' Welcome, This is default Greeting Message' ;
  //adding some method which we can call in app.config() function
  this.setGreetMsg = function(msg){
    if(msg){
      this.greetMessage =  msg ;
    }
  };

  //We can also add a method which can change firstName and lastName
  this.$get = function(){
    var firstName = this.firstName;
    var lastName = this.lastName ;
    var greetMessage = this.greetMessage;
    var data={
       greet: function(){
         console.log('hello, ' + firstName + lastName+'! '+ greetMessage);
       }
    };
    return data ;
  };
});

app.config(
  function(providerPatternProvider){
    providerPatternProvider.setGreetMsg(' How do you do ?');
  }
);

Çalışma Demosu

Özet:


Fabrika ayarı, bir servis örneği döndüren bir fabrika işlevi kullanır. serviceInstance = fnFactory ();

Hizmet bir yapıcı işlevi kullanır ve Angular, hizmet örneğini oluşturmak için 'new' anahtar sözcüğünü kullanarak bu yapıcı işlevini çağırır. serviceInstance = new fnServiceConstructor ();

Sağlayıcı bir providConstructor işlevi tanımlar, bu sağlayıcıConstructor işlevi $ get fabrika işlevini tanımlar . Açısal hizmet nesnesi oluşturmak için $ get () işlevini çağırır. Sağlayıcı sözdiziminin, hizmet nesnesini somutlaştırılmadan önce yapılandırma avantajı vardır. serviceInstance = $ get ();



63

Fabrika

AngularJS'ye bir işlev verirsiniz, fabrika istendiğinde AngularJS önbelleğe alır ve dönüş değerini enjekte eder.

Misal:

app.factory('factory', function() {
    var name = '';
    // Return value **is** the object that will be injected
    return {
        name: name;
    }
})

Kullanımı:

app.controller('ctrl', function($scope, factory) {
     $scope.name = factory.name;
});

Hizmet

Sen angularjs bir işlev vermek, angularjs arayacak yeni bir örneğini oluşturmaya. AngularJS'nin hizmet istendiğinde önbelleğe alınacak ve enjekte edilecek örneğidir. Yana yeni hizmet örneğini kullanıldı, keyword bu geçerlidir ve örneğine karşılık gelir.

Misal:

app.service('service', function() {
     var name = '';
     this.setName = function(newName) {
         name = newName;
     }
     this.getName = function() {
         return name;
     }
});

Kullanımı:

app.controller('ctrl', function($scope, service) {
   $scope.name = service.getName();
});

Sağlayıcı

AngularJS'ye bir işlev verirsiniz ve AngularJS $getişlevini çağırır . $getHizmet istendiğinde önbelleğe alınacak ve enjekte edilecek olan işlevin dönüş değeridir .

Sağlayıcılar, AngularJS enjekte edilemeyen yöntemi çağırmadan önce sağlayıcıyı yapılandırmanıza izin verir $get.

Misal:

app.provider('provider', function() {
     var name = '';
     this.setName = function(newName) {
          name = newName;
     }
     this.$get = function() {
         return {
            name: name
         }
     }
})

Kullanım (kontrolörde enjekte edilebilir olarak)

app.controller('ctrl', function($scope, provider) {
    $scope.name = provider.name;
});

Kullanım ( $getenjektabl oluşturmak için sağlayıcıyı önceden yapılandırmak için çağrılır)

app.config(function(providerProvider) {
    providerProvider.setName('John');
});

56

Sağlayıcılarla oynarken ilginç bir şey fark ettim.

Enjektablların görünürlüğü, sağlayıcılar için servisler ve fabrikalardan farklıdır. Bir AngularJS "sabiti" (örneğin myApp.constant('a', 'Robert');) bildirirseniz , bunu hizmetlere, fabrikalara ve sağlayıcılara enjekte edebilirsiniz.

Ancak bir AngularJS "değeri" (örneğin. myApp.value('b', {name: 'Jones'});) Bildirirseniz, bunu hizmetlere ve fabrikalara enjekte edebilirsiniz, ancak sağlayıcı oluşturma işlevine DEĞİL. Bununla birlikte, bunu $getsağlayıcınız için tanımladığınız işleve enjekte edebilirsiniz . Bu AngularJS belgelerinde belirtilmiştir, ancak kaçırılması kolaydır. Değer ve sabit yöntemlerle ilgili bölümlerde bunu% sağlama sayfasında bulabilirsiniz.

http://jsfiddle.net/R2Frv/1/

<div ng-app="MyAppName">
    <div ng-controller="MyCtrl">
        <p>from Service: {{servGreet}}</p>
        <p>from Provider: {{provGreet}}</p>
    </div>
</div>
<script>
    var myApp = angular.module('MyAppName', []);

    myApp.constant('a', 'Robert');
    myApp.value('b', {name: 'Jones'});

    myApp.service('greetService', function(a,b) {
        this.greeter = 'Hi there, ' + a + ' ' + b.name;
    });

    myApp.provider('greetProvider', function(a) {
        this.firstName = a;
        this.$get = function(b) {
            this.lastName = b.name;
            this.fullName = this.firstName + ' ' + this.lastName;
            return this;
        };
    });

    function MyCtrl($scope, greetService, greetProvider) {
        $scope.servGreet = greetService.greeter;
        $scope.provGreet = greetProvider.fullName;
    }
</script>

45

Bu acemi için çok kafa karıştırıcı bir parçası ve kolay kelimelerle açıklığa kavuşturmaya çalıştım

AngularJS Hizmeti: yardımcı program işlevlerini denetleyicideki hizmet başvurusuyla paylaşmak için kullanılır. Hizmet tekil niteliktedir, bu nedenle bir hizmet için tarayıcıda yalnızca bir örnek oluşturulur ve sayfa boyunca aynı başvuru kullanılır.

Hizmette, işlev adlarını bu nesne ile özellik olarak oluştururuz .

AngularJS Fabrikası: Fabrikanın amacı Hizmet ile aynıdır, ancak bu durumda yeni bir nesne oluşturur ve bu nesnenin özellikleri olarak işlevler ekleriz ve sonunda bu nesneyi döndürürüz.

AngularJS Sağlayıcısı: bunun amacı yine aynıdır, ancak Sağlayıcı $ get işlevinin çıktısını verir.

Hizmet, Fabrika ve Sağlayıcının tanımlanması ve kullanılması http://www.dotnetfunda.com/articles/show/3156/difference-between-angularjs-service-factory-and-provider adresinde açıklanmaktadır.


2
Fabrika ve sağlayıcılar da singleton nesnesidir? Fabrikaların hizmetlere göre önerildiği herhangi bir skandal var mı?
Sunil Garg

34

Benim için farkı anlamanın en iyi ve en basit yolu:

var service, factory;
service = factory = function(injection) {}

AngularJS belirli bileşenleri nasıl başlatır (basitleştirilmiş):

// service
var angularService = new service(injection);

// factory
var angularFactory = factory(injection);

Bu nedenle, hizmet için AngularJS bileşeni, sınıfın hizmet bildirme işlevi tarafından temsil edilen nesne örneğidir. Fabrika için, fabrika bildirim işlevinden döndürülen sonuçtur. Fabrika, servisle aynı şekilde davranabilir:

var factoryAsService = function(injection) {
  return new function(injection) {
    // Service content
  }
}

En basit düşünme şekli şudur:

  • Hizmet tek bir nesne örneğidir. Kodunuz için tek bir nesne sağlamak istiyorsanız hizmetleri kullanın.
  • Fabrika bir sınıftır. Kodunuz için özel sınıflar sağlamak istiyorsanız fabrikaları kullanın (önceden oluşturulmuş oldukları için hizmetlerle yapılamaz).

Fabrika 'sınıf' örneği, etrafındaki yorumlarda ve sağlayıcı farkında verilmiştir.


bir hizmet her kullanıldığında nasıl somutlaştırılırsa nasıl tekil olabilir? kafamı bulabilirim ...
joe

Servis bağımlılık çözme sırasında yalnızca bir kez başlatılır ve daha sonra enjektörden servis istediğinizde daima aynı örneği alırsınız. Kolayca buradan kontrol edilebilir: jsfiddle.net/l0co/sovtu55t/1 , lütfen konsol ile çalıştırın. Konsol, hizmetin yalnızca bir kez başlatıldığını gösterir.
Lukasz Frankowski

Ah anlıyorum. tam anlamıyla new MyService()falan mümkün olacağını bekliyordum :)
joe

33

Bu konuda açıklamam:

Temel olarak, bahsedilen tüm türler (servis, fabrika, sağlayıcı, vb.) Sadece eski moda küresel değişkenler gibi küresel değişkenler (tabii ki tüm uygulama için küresel olan) oluşturuyor ve yapılandırıyorlar.

Global değişkenler önerilmese de, bu global değişkenlerin gerçek kullanımı , değişkeni ilgili denetleyiciye geçirerek bağımlılık enjeksiyonu sağlamaktır .

"Global değişkenler" için değer yaratmanın birçok seviyesi vardır:

  1. Sabit
    Bu, tıpkı diğer dillerdeki sabitler gibi (JavaScript'in eksik olduğu bir şey) tüm uygulama sırasında değiştirilmemesi gereken gerçek bir sabiti tanımlar.
  2. Değer
    Bu değiştirilebilir bir değer veya nesnedir ve başka hizmetler veya fabrikalar oluştururken bile enjekte edilebilecek bazı global değişkenler olarak işlev görür (bunlar hakkında daha fazla bilgi edinin). Bununla birlikte, " gerçek değer " olmalıdır, yani gerçek değeri yazmak zorundadır ve herhangi bir hesaplama veya programlama mantığı kullanamazsınız (başka bir deyişle 39 veya myText veya {prop: "value"} tamam, ancak 2 +2 değildir).
  3. Fabrika
    Daha genel bir değer, bu hemen hesaplanabilir. Değeri hesaplamak için gereken mantıkla AngularJS'ye bir işlev ileterek çalışır ve AngularJS bunu yürütür ve döndürülen değeri adlandırılan değişkene kaydeder.
    Bir nesneyi (bu durumda bir hizmete benzer şekilde işlev görür ) veya bir işlevi (değişkene geri çağrı işlevi olarak kaydedilecek) döndürmenin mümkün olduğunu unutmayın .
  4. Hizmet
    Hizmet, yalnızca değer bir nesne olduğunda geçerli olan daha fabrika çıkışlı bir sürümdür ve herhangi bir mantığı doğrudan işlevde (bir kurucu gibi) yazmanın yanı sıra bildirme ve erişime izin verir bu anahtar kelimeyi kullanarak nesne özellikleri .
  5. Sağlayıcı Fabrikanın
    basitleştirilmiş bir sürümü olan bir hizmetin aksine , bir sağlayıcı "global" değişkenleri başlatmanın daha karmaşık, ancak daha esnek bir yoludur, en büyük esneklik app.config'den değerleri ayarlama seçeneğidir. Bu anahtar kelime kullanılarak bildirilen özelliklere sahip bir işleve iletilerek, üzerinden kullanılabilen bir hizmet ve sağlayıcı kombinasyonu kullanmak gibi çalışır . Sonra yukarıdaki özellikleri dosya üzerinden ayarladıktan sonra AngularJS tarafından yürütülen ayrı bir $ .get işlevi olması gerekir ve bu $ .get işlevi tıpkı fabrika gibi davranır
    app.config
    app.config dönüş değeri "global" değişkenleri başlatmak için kullanılır.

26

Aşağıda benim anlayışım çok basit.

Fabrika: Fabrika içinde bir nesne oluşturup iade edersiniz.

Hizmet:

Bir işlevi tanımlamak için bu anahtar sözcüğü kullanan standart bir işleve sahipsiniz.

Sağlayıcı:

$getTanımladığınız bir nesne var ve veri döndüren nesneyi almak için kullanılabilir.


Fabrika ve Hizmeti karıştırmadınız mı? Hizmetler, fabrikanın geri döndüğü yerde oluşturur.
Flavien Volken

Hizmet adını enjekte edilebilir bir argüman olarak bildirdiğinizde, size işlevin bir örneği verilir. Başka bir deyişle yeni FunctionYouPassedToService (). Bu nesne örneği, AngularJS'nin gerektiğinde daha sonra diğer hizmetlere / denetleyicilere kaydettiği ve enjekte ettiği hizmet nesnesi olur. // factory 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ğer verilir.
sajan

Tamam ... açısal fabrika bir olan tekil "hizmet" bir aslında bir olduğunu fabrika (ortak tasarım desenleri açısından)
Flavien Volken

25

Açısal dokümanlardan özet :

  • Nesnelerin nasıl oluşturulacağını tanımlayan beş tarif türü vardır: Değer , Fabrika , Hizmet , Sağlayıcı ve Sabit .
  • Fabrika ve Servis en çok kullanılan tariflerdir. Aralarındaki tek fark, Servis reçetesinin özel tipteki nesneler için daha iyi çalışması, Fabrika ise JavaScript ilkelerini ve işlevlerini üretebilmesidir.
  • Sağlayıcı tarifi çekirdek tarifi türüdür ve tüm diğer olanları üzerinde bir sözdizim güzelliğidir.
  • Sağlayıcı en karmaşık reçete türüdür. Genel yapılandırmaya ihtiyaç duyan yeniden kullanılabilir bir kod parçası oluşturmadığınız sürece buna ihtiyacınız yoktur.

resim açıklamasını buraya girin


SO'dan en iyi yanıtlar:

https://stackoverflow.com/a/26924234/165673 (<- İYİ) https://stackoverflow.com/a/27263882/165673
https://stackoverflow.com/a/16566144/165673


20

Tüm iyi cevaplar zaten. Hizmet ve Fabrika'ya birkaç nokta daha eklemek istiyorum . Hizmet / fabrika arasındaki fark ile birlikte. Ve ayrıca şöyle sorular da olabilir:

  1. Servis veya fabrika kullanmalı mıyım? Fark ne?
  2. Aynı mı yoksa aynı davranışa mı sahipler?

Hizmet ve fabrika arasındaki farkla başlayalım:

  1. Her ikisi de Singletons : Açısal bunları ilk kez bağımlılık olarak bulduğunda, tek bir hizmet / fabrika örneği oluşturur. Örnek oluşturulduktan sonra, aynı örnek sonsuza kadar kullanılır.

  2. Davranışla bir nesneyi modellemek için kullanılabilir : Her ikisinin de yöntemleri, iç durum değişkenleri vb. Olabilir . Bu kodu yazma şekliniz farklı olsa da.

Hizmetler:

Hizmet yapıcı bir işlevdir ve Angular yeni çağrı ile hizmeti başlatır yourServiceName(). Bu birkaç şey demektir.

  1. Fonksiyonlar ve örnek değişkenlerin özellikleri olacaktır this.
  2. Bir değer döndürmeniz gerekmez. Açısal çağrılar new yourServiceName(), thisnesneyi üzerine koyduğunuz tüm özelliklere sahip olur.

Örnek Örnek:

angular.service('MyService', function() {
  this.aServiceVariable = "Ved Prakash"
  this.aServiceMethod = function() {
    return //code
  };
});

Angular bu MyServicehizmeti ona bağlı bir denetleyiciye enjekte ettiğinde, o denetleyici MyServiceişlevlerini çağırabileceği bir denetime sahip olur , örneğin MyService.aServiceMethod ().

Dikkatli olunthis :

Oluşturulan hizmet bir nesne olduğundan, içindeki yöntemler çağrıldığında buna başvurabilir:

angular.service('ScoreKeeper', function($http) {
  this.score = 0;

  this.getScore = function() {
    return this.score;
  };

  this.setScore = function(newScore) {
    this.score = newScore;
  };

  this.addOne = function() {
    this.score++;
  };
});

Sen aramak için cazip olabilir ScoreKeeper.setScoresunucudan onu kapma tarafından skoru başlatıldı eğer örneğin bir söz zincirinde: $http.get('/score').then(ScoreKeeper.setScore).Bu noktadaki sorunsa yani ScoreKeeper.setScoreanılmaktadır thisbağlı nullve hatalarla elde edersiniz. Daha iyi bir yol olurdu $http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper)). Bunu hizmet yöntemlerinizde kullanmayı tercih edip etmediğinizi, nasıl aradığınıza dikkat edin.

A değerinden bir değer döndürmeService :

JavaScript kurucularının çalışma şekli nedeniyle (i.e., an Object), bir constructorişlevden karmaşık bir değer döndürürseniz , arayan bu örnek yerine bu Nesneyi alır.

Temelde, aşağıdan fabrika örneğini kopyalayıp yapıştırmak yerine geçebileceğini Bu araçlar factoryile serviceve bu ödeme şekli:

angular.service('MyService', function($http) {
  var api = {};

  api.aServiceMethod= function() {
    return $http.get('/users');
  };
  return api;
});

Böylece Angular hizmetinizi yeni MyService () ile oluşturduğunda, MyService örneği yerine o api nesnesini alır.

Bu, herhangi bir karmaşık değerin (nesneler, işlevler) davranışıdır, ancak ilkel türler için değildir.

Fabrikalar:

Fabrika, bir değer döndüren eski bir işlevdir. Dönüş değeri, fabrikaya bağlı olan şeylere enjekte edilen değerdir. Açısal'daki tipik bir fabrika deseni, şu özelliklere sahip işlevlere sahip bir nesneyi döndürmektir:

angular.factory('MyFactory', function($http) {
  var api = {};

  api.aFactoryMethod= function() {
    return $http.get('/users');
  };

  return api;
});

Fabrika bağımlılığı için enjekte edilen değer fabrikanın dönüş değeridir ve bir nesne olması gerekmez. Bir işlev olabilir

Yukarıdaki 1 ve 2 sorularının cevapları:

Çoğunlukla, her şey için fabrikaları kullanmaya devam edin. Davranışlarını anlamak daha kolaydır. Bir değer döndürüp döndürmeyeceğine dair bir seçenek yoktur ve ayrıca yanlış bir şey yaparsanız tanıtılacak hiçbir hata yoktur.

Yine de bağımlılık olarak enjekte etmekten bahsettiğimde hala onlara “hizmet” diyorum.

Hizmet / Fabrika davranışı çok benzer ve bazı insanlar her ikisinin de iyi olduğunu söyleyecektir. Bu biraz doğru, ama John Papa'nın stil rehberinin tavsiyelerini takip etmeyi ve sadece fabrikalara bağlı kalmayı daha kolay buluyorum. **


16

Ek bir açıklama, fabrikaların hizmetler / ilkeller oluşturabilmesine karşın, hizmetler yapamaz. Epokk'in temel aldığı bu jsFiddle'a göz atın: http://jsfiddle.net/skeller88/PxdSP/1351/ .

Fabrika, çağrılabilecek bir işlev döndürür:

myApp.factory('helloWorldFromFactory', function() {
  return function() {
    return "Hello, World!";
  };
});

Fabrika ayrıca çağrılabilecek bir yöntemle bir nesneyi döndürebilir:

myApp.factory('helloWorldFromFactory', function() {
  return {
    sayHello: function() {
      return "Hello, World!";
    }
  };
});

Hizmet, çağrılabilecek bir yönteme sahip bir nesne döndürür:

myApp.service('helloWorldFromService', function() {
  this.sayHello = function() {
     return "Hello, World!";
  };
});

Daha fazla ayrıntı için, fark hakkında yazdığım bir gönderiye bakın: http://www.shanemkeller.com/tldr-services-vs-factories-in-angular/


16

Zaten iyi cevaplar var, ama sadece bunu paylaşmak istiyorum.

Her şeyden önce: Sağlayıcı , service$ enjektör tarafından enjekte edilmesi gereken bir (singleton nesnesi) yaratmanın yolu / reçetesidir (AngulaJS, IoC paterninden nasıl geçer).

Ve Değer, Fabrika, Hizmet ve Sabit (4 yol) - Sağlayıcı yolu / alıcı üzerinde sözdizimsel şeker .

Ele alınan Service vs Factorykısım var: https://www.youtube.com/watch?v=BLzNCkPn3ao

Hizmetnew aslında bildiğimiz gibi 4 şey yapar anahtar kelime hakkında :

  1. yepyeni bir nesne yaratır
  2. prototypenesnesine bağlar
  3. bağlandığı contextiçinthis
  4. ve geri dönüyor this

Ve Fabrika tamamen Fabrika Kalıbı ile ilgilidir - bu Hizmet gibi Nesneleri döndüren işlevler içerir.

  1. diğer hizmetleri kullanma yeteneği (bağımlılıkları vardır)
  2. hizmet başlatma
  3. gecikmeli / tembel başlatma

Ve bu basit / kısa video: ayrıca Sağlayıcıyı da kapsar : https://www.youtube.com/watch?v=HvTZbQ_hUZY (orada fabrikadan sağlayıcıya nasıl geçtiklerini görebilirsiniz)

Sağlayıcı tarifi, uygulama tamamen başlatılmadan / başlatılmadan önce çoğunlukla uygulama yapılandırmasında kullanılır.


14

Tüm bu yazıyı okuduktan sonra benim için daha fazla kafa karıştırdı .. Ama yine de hepsi değerli bilgiler .. sonunda basit karşılaştırma ile bilgi verecek aşağıdaki tabloyu buldum

  • Enjektör iki tür nesne oluşturmak için tarifler kullanır: hizmetler ve özel amaçlı nesneler
  • Nesnelerin nasıl oluşturulacağını tanımlayan beş tarif türü vardır: Değer, Fabrika, Hizmet, Sağlayıcı ve Sabit.
  • Fabrika ve Servis en çok kullanılan tariflerdir. Aralarındaki tek fark, Servis reçetesinin özel tipteki nesneler için daha iyi çalışması, Fabrika ise JavaScript ilkelerini ve işlevlerini üretebilmesidir.
  • Sağlayıcı tarifi temel reçete türüdür ve diğer tüm reçeteler sadece sözdizimsel şekerlerdir.
  • Sağlayıcı en karmaşık reçete türüdür. Genel yapılandırmaya ihtiyaç duyan yeniden kullanılabilir bir kod parçası oluşturmadığınız sürece buna ihtiyacınız yoktur.
  • Denetleyici dışındaki tüm özel amaçlı nesneler Fabrika tarifleri ile tanımlanır.

resim açıklamasını buraya girin

Ve yeni başlayanlar için: - Bu kullanım durumunu düzeltemeyebilir, ancak yüksek düzeyde bu üçü için kullanım alanı budur.

  1. Açısal modülde kullanmak istiyorsanız yapılandırma fonksiyonu sağlayıcı olarak oluşturulmalıdır

angular.module('myApp').config(function($testProvider){
$testProvider.someFunction();
})

  1. Ajax araması veya üçüncü taraf entegrasyonlarının hizmette olması gerekir .
  2. Veri manipülasyonları için bunu fabrika olarak oluşturun

Temel senaryolar için fabrika ve Servis aynı şekilde davranır.


13

İşte AngularjS'de nesne fabrikası için bir kod şablonu olarak bulduğum bazı broilerplate kodu. Örnek olarak bir Car / CarFactory kullandım. Denetleyicide basit uygulama kodunu yapar.

     <script>
        angular.module('app', [])
            .factory('CarFactory', function() {

                /**
                 * BroilerPlate Object Instance Factory Definition / Example
                 */
                this.Car = function() {

                    // initialize instance properties
                    angular.extend(this, {
                        color           : null,
                        numberOfDoors   : null,
                        hasFancyRadio   : null,
                        hasLeatherSeats : null
                    });

                    // generic setter (with optional default value)
                    this.set = function(key, value, defaultValue, allowUndefined) {

                        // by default,
                        if (typeof allowUndefined === 'undefined') {
                            // we don't allow setter to accept "undefined" as a value
                            allowUndefined = false;
                        }
                        // if we do not allow undefined values, and..
                        if (!allowUndefined) {
                            // if an undefined value was passed in
                            if (value === undefined) {
                                // and a default value was specified
                                if (defaultValue !== undefined) {
                                    // use the specified default value
                                    value = defaultValue;
                                } else {
                                    // otherwise use the class.prototype.defaults value
                                    value = this.defaults[key];
                                } // end if/else
                            } // end if
                        } // end if

                        // update 
                        this[key] = value;

                        // return reference to this object (fluent)
                        return this;

                    }; // end this.set()

                }; // end this.Car class definition

                // instance properties default values
                this.Car.prototype.defaults = {
                    color: 'yellow',
                    numberOfDoors: 2,
                    hasLeatherSeats: null,
                    hasFancyRadio: false
                };

                // instance factory method / constructor
                this.Car.prototype.instance = function(params) {
                    return new 
                        this.constructor()
                                .set('color',           params.color)
                                .set('numberOfDoors',   params.numberOfDoors)
                                .set('hasFancyRadio',   params.hasFancyRadio)
                                .set('hasLeatherSeats', params.hasLeatherSeats)
                    ;
                };

                return new this.Car();

            }) // end Factory Definition
            .controller('testCtrl', function($scope, CarFactory) {

                window.testCtrl = $scope;

                // first car, is red, uses class default for:
                // numberOfDoors, and hasLeatherSeats
                $scope.car1     = CarFactory
                                    .instance({
                                        color: 'red'
                                    })
                                ;

                // second car, is blue, has 3 doors, 
                // uses class default for hasLeatherSeats
                $scope.car2     = CarFactory
                                    .instance({
                                        color: 'blue',
                                        numberOfDoors: 3
                                    })
                                ;
                // third car, has 4 doors, uses class default for 
                // color and hasLeatherSeats
                $scope.car3     = CarFactory
                                    .instance({
                                        numberOfDoors: 4
                                    })
                                ;
                // sets an undefined variable for 'hasFancyRadio',
                // explicitly defines "true" as default when value is undefined
                $scope.hasFancyRadio = undefined;
                $scope.car3.set('hasFancyRadio', $scope.hasFancyRadio, true);

                // fourth car, purple, 4 doors,
                // uses class default for hasLeatherSeats
                $scope.car4     = CarFactory
                                    .instance({
                                        color: 'purple',
                                        numberOfDoors: 4
                                    });
                // and then explicitly sets hasLeatherSeats to undefined
                $scope.hasLeatherSeats = undefined;
                $scope.car4.set('hasLeatherSeats', $scope.hasLeatherSeats, undefined, true);

                // in console, type window.testCtrl to see the resulting objects

            });
    </script>

İşte daha basit bir örnek. Enlem ve boylam, ancak farklı nesne özellikleri açığa "Pozisyon" bir nesne bekliyoruz birkaç üçüncü taraf kitaplıkları kullanıyorum. Satıcı kodunu kesmek istemedim, bu yüzden etrafta dolaştığım "Konum" nesnelerini ayarladım.

    angular.module('app')
.factory('PositionFactory', function() {

    /**
     * BroilerPlate Object Instance Factory Definition / Example
     */
    this.Position = function() {

        // initialize instance properties 
        // (multiple properties to satisfy multiple external interface contracts)
        angular.extend(this, {
            lat         : null,
            lon         : null,
            latitude    : null,
            longitude   : null,
            coords: {
                latitude: null,
                longitude: null
            }
        });

        this.setLatitude = function(latitude) {
            this.latitude           = latitude;
            this.lat                = latitude;
            this.coords.latitude    = latitude;
            return this;
        };
        this.setLongitude = function(longitude) {
            this.longitude          = longitude;
            this.lon                = longitude;
            this.coords.longitude   = longitude;
            return this;
        };

    }; // end class definition

    // instance factory method / constructor
    this.Position.prototype.instance = function(params) {
        return new 
            this.constructor()
                    .setLatitude(params.latitude)
                    .setLongitude(params.longitude)
        ;
    };

    return new this.Position();

}) // end Factory Definition

.controller('testCtrl', function($scope, PositionFactory) {
    $scope.position1 = PositionFactory.instance({latitude: 39, longitude: 42.3123});
    $scope.position2 = PositionFactory.instance({latitude: 39, longitude: 42.3333});
}) // end controller

;


12

Bu sayfaya ve belgelere referans olarak kullanma (son baktığımdan beri büyük ölçüde iyileşmiş gibi görünüyor) , sağlayıcının 5 lezzetinden 4'ünü kullanan aşağıdaki gerçek (-ish) dünya demosunu bir araya getirdim; Değer, Sabit, Fabrika ve tam gelişmiş Sağlayıcı.

HTML:

<div ng-controller="mainCtrl as main">
    <h1>{{main.title}}*</h1>
    <h2>{{main.strapline}}</h2>
    <p>Earn {{main.earn}} per click</p>
    <p>You've earned {{main.earned}} by clicking!</p>
    <button ng-click="main.handleClick()">Click me to earn</button>
    <small>* Not actual money</small>
</div>

Uygulamanın

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

// A CONSTANT is not going to change
app.constant('range', 100);

// A VALUE could change, but probably / typically doesn't
app.value('title', 'Earn money by clicking');
app.value('strapline', 'Adventures in ng Providers');

// A simple FACTORY allows us to compute a value @ runtime.
// Furthermore, it can have other dependencies injected into it such
// as our range constant.
app.factory('random', function randomFactory(range) {
    // Get a random number within the range defined in our CONSTANT
    return Math.random() * range;
});

// A PROVIDER, must return a custom type which implements the functionality 
// provided by our service (see what I did there?).
// Here we define the constructor for the custom type the PROVIDER below will 
// instantiate and return.
var Money = function(locale) {

    // Depending on locale string set during config phase, we'll
    // use different symbols and positioning for any values we 
    // need to display as currency
    this.settings = {
        uk: {
            front: true,
            currency: '£',
            thousand: ',',
            decimal: '.'
        },
        eu: {
            front: false,
            currency: '€',
            thousand: '.',
            decimal: ','
        }
    };

    this.locale = locale;
};

// Return a monetary value with currency symbol and placement, and decimal 
// and thousand delimiters according to the locale set in the config phase.
Money.prototype.convertValue = function(value) {

    var settings = this.settings[this.locale],
        decimalIndex, converted;

    converted = this.addThousandSeparator(value.toFixed(2), settings.thousand);

    decimalIndex = converted.length - 3;

    converted = converted.substr(0, decimalIndex) +
        settings.decimal +
        converted.substr(decimalIndex + 1);    

    converted = settings.front ?
            settings.currency + converted : 
            converted + settings.currency; 

    return converted;   
};

// Add supplied thousand separator to supplied value
Money.prototype.addThousandSeparator = function(value, symbol) {
   return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, symbol);
};

// PROVIDER is the core recipe type - VALUE, CONSTANT, SERVICE & FACTORY
// are all effectively syntactic sugar built on top of the PROVIDER construct
// One of the advantages of the PROVIDER is that we can configure it before the
// application starts (see config below).
app.provider('money', function MoneyProvider() {

    var locale;

    // Function called by the config to set up the provider
    this.setLocale = function(value) {
        locale = value;   
    };

    // All providers need to implement a $get method which returns
    // an instance of the custom class which constitutes the service
    this.$get = function moneyFactory() {
        return new Money(locale);
    };
});

// We can configure a PROVIDER on application initialisation.
app.config(['moneyProvider', function(moneyProvider) {
    moneyProvider.setLocale('uk');
    //moneyProvider.setLocale('eu'); 
}]);

// The ubiquitous controller
app.controller('mainCtrl', function($scope, title, strapline, random, money) {

    // Plain old VALUE(s)
    this.title = title;
    this.strapline = strapline;

    this.count = 0;

    // Compute values using our money provider    
    this.earn = money.convertValue(random); // random is computed @ runtime
    this.earned = money.convertValue(0);

    this.handleClick = function() { 
        this.count ++;
        this.earned = money.convertValue(random * this.count);
    };
});

Çalışma demosu .


12

Bu cevap konuyu / soruyu ele alıyor

Fabrika, Hizmet ve Sabit - sadece bir sağlayıcı tarifinin üstünde sözdizimsel şeker nedir?

VEYA

fabrika, servis ve sağlayıcılar nasıl dahili olarak simailar

temelde ne olur

Bir yaptığınızda factory()size ayarlar functionsağlayıcısının ikinci argüman sağlanan $getve onu (dönüş provider(name, {$get:factoryFn })) ama elde ettiğin providerancak başka hiçbir özellik / yöntem yoktur$get Bunun provider(bu yapılandıramazsınız yollarla)

Fabrika kaynak kodu

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

Bunu yaparken, service()(fabrikada hizmetinizde verdiğiniz yapıcı örneğini döndüren) functionenjekte eden bir fabrika ( constructor) sağlar ve iade eder

Kaynak hizmet kodu

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

Temel olarak her iki durumda da sonunda bir sağlayıcıya sağladığınız işlevinize $ set alırsınız, ancak yapılandırma bloğu için orijinal olarak sağlayıcıda () sağlayabileceğiniz gibi $ get dışında bir şey verebilirsiniz.


11

Ben çok mükemmel bir cevap biliyorum ama varsayılan
1 serviceçoğu durumda 1. kullanma deneyimimi paylaşmak zorunda
2. factorybelirli bir örnek hizmet oluşturmak için kullanılır

// factory.js ////////////////////////////
(function() {
'use strict';
angular
    .module('myApp.services')
    .factory('xFactory', xFactoryImp);
xFactoryImp.$inject = ['$http'];

function xFactoryImp($http) {
    var fac = function (params) {
        this._params = params; // used for query params
    };

    fac.prototype.nextPage = function () {
        var url = "/_prc";

        $http.get(url, {params: this._params}).success(function(data){ ...
    }
    return fac;
}
})();

// service.js //////////////////////////
(function() {
'use strict';
angular
    .module('myApp.services')
    .service('xService', xServiceImp);
xServiceImp.$inject = ['$http'];

function xServiceImp($http) {  
    this._params = {'model': 'account','mode': 'list'};

    this.nextPage = function () {
        var url = "/_prc";

        $http.get(url, {params: this._params}).success(function(data){ ...
    }       
}
})();

ve kullanma:

controller: ['xFactory', 'xService', function(xFactory, xService){

        // books = new instance of xFactory for query 'book' model
        var books = new xFactory({'model': 'book', 'mode': 'list'});

        // accounts = new instance of xFactory for query 'accounts' model
        var accounts = new xFactory({'model': 'account', 'mode': 'list'});

        // accounts2 = accounts variable
        var accounts2 = xService;
... 

10

Partiye biraz geç. Ama bunun fabrika, hizmet ve sağlayıcı metodolojilerini kullanarak Angular JS Custom Services geliştirmeyi öğrenmek (veya netleştirmek) isteyenler için daha yararlı olduğunu düşündüm.

AngularJS Özel Hizmetlerini geliştirmek için fabrika, hizmet ve sağlayıcı yöntemleri hakkında net bir açıklama yapan bu videoyla karşılaştım:

https://www.youtube.com/watch?v=oUXku28ex-M

Kaynak Kodu: http://www.techcbt.com/Post/353/Angular-JS-basics/how-to-develop-angularjs-custom-service

Burada yayınlanan kod, okuyucuların yararlanması için doğrudan yukarıdaki kaynaktan kopyalanır.

"Fabrika" tabanlı özel hizmet kodu aşağıdaki gibidir (hem senkronizasyon hem de zaman uyumsuz sürümlerle birlikte http hizmetini çağırır):

var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcFactory',
  function($scope, calcFactory) {
    $scope.a = 10;
    $scope.b = 20;

    $scope.doSum = function() {
      //$scope.sum = calcFactory.getSum($scope.a, $scope.b); //synchronous
      calcFactory.getSum($scope.a, $scope.b, function(r) { //aynchronous
        $scope.sum = r;
      });
    };

  }
]);

app.factory('calcFactory', ['$http', '$log',
  function($http, $log) {
    $log.log("instantiating calcFactory..");
    var oCalcService = {};

    //oCalcService.getSum = function(a,b){
    //	return parseInt(a) + parseInt(b);
    //};

    //oCalcService.getSum = function(a, b, cb){
    //	var s = parseInt(a) + parseInt(b);
    //	cb(s);
    //};

    oCalcService.getSum = function(a, b, cb) { //using http service

      $http({
        url: 'http://localhost:4467/Sum?a=' + a + '&b=' + b,
        method: 'GET'
      }).then(function(resp) {
        $log.log(resp.data);
        cb(resp.data);
      }, function(resp) {
        $log.error("ERROR occurred");
      });
    };

    return oCalcService;
  }
]);

Özel Hizmetler için "hizmet" metodolojisi kodu (bu, 'fabrika'ya oldukça benzer, ancak sözdizimi açısından farklıdır):

var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcService', function($scope, calcService){
	$scope.a = 10;
	$scope.b = 20;

	$scope.doSum = function(){
		//$scope.sum = calcService.getSum($scope.a, $scope.b);
		
		calcService.getSum($scope.a, $scope.b, function(r){
			$scope.sum = r;
		});		
	};

}]);

app.service('calcService', ['$http', '$log', function($http, $log){
	$log.log("instantiating calcService..");
	
	//this.getSum = function(a,b){
	//	return parseInt(a) + parseInt(b);
	//};

	//this.getSum = function(a, b, cb){
	//	var s = parseInt(a) + parseInt(b);
	//	cb(s);
	//};

	this.getSum = function(a, b, cb){
		$http({
			url: 'http://localhost:4467/Sum?a=' + a + '&b=' + b,
			method: 'GET'
		}).then(function(resp){
			$log.log(resp.data);
			cb(resp.data);
		},function(resp){
			$log.error("ERROR occurred");
		});
	};

}]);

Özel Hizmetler için "sağlayıcı" metodolojisi kodu (bu, yapılandırılabilecek bir hizmet geliştirmek istiyorsanız gereklidir):

var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcService', function($scope, calcService){
	$scope.a = 10;
	$scope.b = 20;

	$scope.doSum = function(){
		//$scope.sum = calcService.getSum($scope.a, $scope.b);
		
		calcService.getSum($scope.a, $scope.b, function(r){
			$scope.sum = r;
		});		
	};

}]);

app.provider('calcService', function(){

	var baseUrl = '';

	this.config = function(url){
		baseUrl = url;
	};

	this.$get = ['$log', '$http', function($log, $http){
		$log.log("instantiating calcService...")
		var oCalcService = {};

		//oCalcService.getSum = function(a,b){
		//	return parseInt(a) + parseInt(b);
		//};

		//oCalcService.getSum = function(a, b, cb){
		//	var s = parseInt(a) + parseInt(b);
		//	cb(s);	
		//};

		oCalcService.getSum = function(a, b, cb){

			$http({
				url: baseUrl + '/Sum?a=' + a + '&b=' + b,
				method: 'GET'
			}).then(function(resp){
				$log.log(resp.data);
				cb(resp.data);
			},function(resp){
				$log.error("ERROR occurred");
			});
		};		

		return oCalcService;
	}];

});

app.config(['calcServiceProvider', function(calcServiceProvider){
	calcServiceProvider.config("http://localhost:4467");
}]);

Son olarak, yukarıdaki hizmetlerden herhangi biriyle çalışan kullanıcı arayüzü:

<html>
<head>
	<title></title>
	<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js" ></script>
	<script type="text/javascript" src="t03.js"></script>
</head>
<body ng-app="app">
	<div ng-controller="emp">
		<div>
			Value of a is {{a}},
			but you can change
			<input type=text ng-model="a" /> <br>

			Value of b is {{b}},
			but you can change
			<input type=text ng-model="b" /> <br>

		</div>
		Sum = {{sum}}<br>
		<button ng-click="doSum()">Calculate</button>
	</div>
</body>
</html>


10

AngularJS kaynağından bir şeyi açıklığa kavuşturmak için, bir hizmetin fabrika işlevini çağırdığını ve bunun karşılığında sağlayıcı işlevini çağırdığını görebilirsiniz:

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

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

9

AngularJS'de iş mantığını ele almanın üç yolunu basit bir şekilde tartışalım: ( Yaakov'un Coursera AngularJS kursundan esinlenildi )

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'] //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>

Hizmet Özellikleri:

  1. Tembel Örnekleme : Enjekte edilmezse, hiçbir zaman örneklenmez. Bu yüzden kullanmak için bir modüle enjekte etmek zorunda kalacak.
  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 uygun.

FABRİKA

Ö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. Fabrika tasarım desenini takip eder. Fabrika, yeni nesneler veya işlevler üreten merkezi bir yerdir.
  2. 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, üretir ve 's davranışını yapılandırmak için herhangi bir kolay yolu olmadan. Bu .service()yöntem genellikle herhangi bir yapılandırma gerektirmeyen bir şey için kısayol olarak kullanılır.

SAĞLAYICI

İlk önce sözdizimine bir göz atalım:

angular.module('ProviderModule', [])
.controller('ProviderModuleController', ProviderModuleController)
.provider('ServiceProvider', ServiceProvider)
.config(Config); //optional

Config.$inject = ['ServiceProvider'];
function Config(ServiceProvider) {
  ServiceProvider.defaults.maxItems = 10; //some default value
}


ProviderModuleController.$inject = ['ServiceProvider'];
function ProviderModuleController(ServiceProvider) {
  //some methods
}

function ServiceProvider() {
  var provider = this;

  provider.defaults = {
    maxItems: 10
  };

  provider.$get = function () {
    var someList = new someListService(provider.defaults.maxItems);

    return someList;
  };
}

}

Sağlayıcının Özellikleri:

  1. Sağlayıcı, Angular'da hizmet oluşturmanın en esnek yöntemidir.
  2. Sadece dinamik olarak yapılandırılabilen bir fabrika yaratabiliyoruz, aynı zamanda fabrikayı kullanırken, sağlayıcı yöntemiyle, tüm uygulamamızın önyüklemesinde fabrikayı yalnızca bir kez özelleştirebiliriz.
  3. Fabrika daha sonra özel ayarlarla uygulama boyunca kullanılabilir. Başka bir deyişle, uygulama başlamadan önce bu fabrikayı yapılandırabiliriz. Aslında açısal dokümantasyonda, hizmetlerimizi bir yöntemle .serviceveya .factoryyöntemle yapılandırdığımızda, sağlayıcı yönteminin perde arkasında yürütülen şey olduğu belirtilmektedir .
  4. Bu $get, doğrudan sağlayıcı örneğine eklenmiş bir işlevdir. Bu işlev fabrika işlevidir. Başka bir deyişle, bu yöntemi sağlamak için kullandığımız gibi .factory. Bu fonksiyonda kendi servisimizi yaratıyoruz. Bu $getözellik, bu bir işlev, sağlayıcıyı sağlayıcı yapan şeydir . AngularJS, sağlayıcının değeri Angular'ın fabrika işlevi olarak değerlendireceği bir işlev olan bir $ get özelliğine sahip olmasını bekler. Ancak bu tüm sağlayıcı kurulumunu çok özel kılan şey config, servis sağlayıcısının içinde bir nesne sağlayabilmemiz ve genellikle adımda, tüm uygulamayı yapılandırabileceğimiz varsayılanların üzerine gelebilmemizdir.

7

Fabrika: Fabrika içinde bir nesne oluşturduğunuz ve iade ettiğiniz fabrika.
service: Hizmet, işlevi tanımlamak için bu anahtar sözcüğü kullanan standart bir işleve sahiptir.
sağlayıcı: Sağlayıcı sizin tanımladığınız bir $ var ve veriyi döndüren nesneyi almak için kullanılabilir.


7

Temel olarak, Sağlayıcı, Fabrika ve Hizmetin tümü Servis'tir. Tek ihtiyacınız olan bir $ get () işlevi olduğunda, daha az kodla yazmanıza olanak tanıyan bir Fabrika, Hizmetin özel bir halidir.

Hizmetler, Fabrikalar ve Sağlayıcılar arasındaki en büyük fark karmaşıklıklarıdır. Hizmetler en basit biçimdir, Fabrikalar biraz daha sağlamdır ve Sağlayıcılar çalışma zamanında yapılandırılabilir.

Her birinin ne zaman kullanılacağına dair bir özet:

Fabrika : Verdiğiniz değerin diğer verilere göre hesaplanması gerekir.

Hizmet : Bir nesneyi yöntemlerle döndürüyorsunuz.

Sağlayıcı : Yapılandırma aşamasında oluşturulacak nesneyi oluşturulmadan önce yapılandırabilirsiniz. Uygulama tamamen başlatılmadan önce Sağlayıcıyı çoğunlukla uygulama yapılandırmasında kullanın.


eee. Değer, Fabrika, Hizmet ve Sabit - sadece bir sağlayıcı tarifinin üstünde sözdizimsel şekerdir. Angularjs docs - sağlayıcılar
Sudarshan_SMD

evet katılıyorum, şimdi açısal 4 ile artık bu baş
ağrımız yok

4

1.Servisler, gerektiğinde oluşturulan ve uygulama yaşam döngüsünün sonuna kadar (tarayıcı kapatıldığında) asla temizlenmeyen tekli nesnelerdir. Kontrolörler artık ihtiyaç duyulmadığında yok edilir ve temizlenir.

2.Hizmet oluşturmanın en kolay yolu factory () yöntemini kullanmaktır. Factory () yöntemi, hizmet işlevlerini ve hizmet verilerini içeren bir nesneyi döndürerek bir hizmeti tanımlamamıza olanak tanır. Hizmet tanımı işlevi, $ http ve $ q gibi enjekte edilebilir hizmetlerimizi yerleştirdiğimiz yerdir. Ör:

angular.module('myApp.services')
.factory('User', function($http) { // injectables go here
var backendUrl = "http://localhost:3000"; var service = {
    // our factory definition
user: {},
setName: function(newName) {
      service.user['name'] = newName;
    },
setEmail: function(newEmail) { service.user['email'] = newEmail;
},
save: function() {
return $http.post(backendUrl + '/users', { user: service.user
}); }
};
return service; });

Bizim app fabrika () kullanma

Uygulamamızda fabrikayı kullanmak kolaydır, çünkü çalışma zamanında ihtiyacımız olan yere enjekte edebiliriz.

angular.module('myApp')
.controller('MainController', function($scope, User) {
  $scope.saveUser = User.save;
});
  1. Diğer yandan service () yöntemi, yapıcı işlevini tanımlayarak bir hizmet oluşturmamızı sağlar. Ham javascript nesnesi yerine hizmetimizi tanımlamak için prototip bir nesne kullanabiliriz. Factory () yöntemine benzer şekilde, işlev tanımındaki enjektablları da ayarlayacağız.
  2. Hizmet oluşturmanın en düşük yolu, () yöntemini kullanmaktır. Bu, .config () işlevini kullanarak yapılandırabileceğimiz bir hizmet oluşturmanın tek yoludur. Önceki yöntemlerden farklı olarak, enjekte edilebilirleri tanımlanmış bu. $ Get () fonksiyon tanımında ayarlayacağız.

-3

Sözdizimsel Şeker farktır . Yalnızca sağlayıcı gereklidir. Ya da başka bir deyişle, sadece sağlayıcı gerçek açısaldır, diğer tüm kodlar türetilir (kodu azaltmak için). Ayrıca, yalnızca değer döndüren, hesaplama veya işlev döndürmeyen Value () adlı basit bir sürüm de vardır. Hatta Değer sağlayıcıdan türetilir!

Peki neden bu tür komplikasyonlar, neden sadece sağlayıcıyı kullanamıyoruz ve diğer her şeyi unutamıyoruz? Kolayca kod yazmamıza ve daha iyi iletişim kurmamıza yardımcı olması gerekiyor. Ve yanaktan yana cevap, bir çerçevenin satışını ne kadar karmaşık hale getirirse o kadar karmaşık olur.


  • Değer döndüren bir sağlayıcı = Değer
  • Sadece başlatabilen ve döndürebilen bir sağlayıcı = Fabrika (+ Değer)
  • Bir şeyi somutlaştırabilen + yapabilen bir sağlayıcı = Hizmet (+ Fabrika, + Değer)
  • Sağlayıcı = $ get (+ Fabrika, + Hizmet, + Değer) adlı bir özellik içermelidir

Açısal enjeksiyon bize bu sonuca varmada ilk ipucunu veriyor.

"$ injector, fabrika tarafından değil, hizmet sağlayıcı tarafından değil, hizmet sağlayıcı tarafından tanımlanan nesne örneklerini almak için kullanılır .

Ve daha iyi bir cevap şöyle olur: "Açısal bir hizmet, bir servis fabrikası tarafından oluşturulur. Bu hizmet fabrikaları, bir servis sağlayıcı tarafından oluşturulan işlevlerdir. Servis sağlayıcıları yapıcı işlevleridir. $ get adlı, hizmet fabrikası işlevini tutar. "

Yani ana sağlayıcı ve enjektör ve hepsi yerinde düşecek :). IServiceProvider'dan devralınarak $ get'in bir sağlayıcıda uygulanabilmesi, Typescript'te ilginç hale geliyor.

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.