angular.service vs angular.factory


1065

Saya telah melihat angular.factory () dan angular.service () digunakan untuk mendeklarasikan layanan; Namun, saya tidak dapat menemukan angular.service di mana pun dalam dokumentasi resmi.

Apa perbedaan antara kedua metode ini?
Yang harus digunakan untuk apa (dengan asumsi mereka melakukan hal yang berbeda)?



4
Saya mencari "pabrik servis [[angular]]", tetapi saya juga ingat bahwa sudah ada pertanyaan tentang itu (karena saya berpikir untuk menulis itu / pertanyaan ini sendiri pada satu titik).
Mark Rajcok

2
Dalam pencarian, apakah tanda kurung menandakan sebuah tag?
jacob

11
@Jacob Square Kurung mempersempit pencarian Anda. Arahan [angularjs] - akan mencari 'arahan' untuk pertanyaan yang sudah ditandai dengan angularjs.
Mahbub

1
@ Mahbub Dengan kata lain, "ya" :)
Brian

Jawaban:


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

Saya mengalami kesulitan membungkus kepala saya di sekitar konsep ini sampai saya menempatkannya pada diri saya seperti ini:

Layanan : fungsi yang Anda tulis akan baru :

  myInjectedService  <----  new myServiceFunction()

Pabrik : fungsi (konstruktor) yang Anda tulis akan dipanggil :

  myInjectedFactory  <---  myFactoryFunction()

Apa yang Anda lakukan dengan itu terserah Anda, tetapi ada beberapa pola yang berguna ...

Seperti menulis fungsi layanan untuk mengekspos API publik:

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

Atau menggunakan fungsi pabrik untuk mengekspos API publik:

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();

Atau menggunakan fungsi pabrik untuk mengembalikan konstruktor:

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();

Yang mana yang akan digunakan? ...

Anda dapat mencapai hal yang sama dengan keduanya. Namun, dalam beberapa kasus, pabrik memberi Anda sedikit lebih banyak fleksibilitas untuk membuat suntikan dengan sintaksis yang lebih sederhana. Itu karena sementara myInjectedService harus selalu menjadi objek, myInjectedFactory dapat berupa objek, referensi fungsi, atau nilai apa pun. Misalnya, jika Anda menulis layanan untuk membuat konstruktor (seperti pada contoh terakhir di atas), itu harus dibuat seperti ini:

var myShinyNewObject = new myInjectedService.myFunction()

yang bisa dibilang kurang diinginkan dari ini:

var myShinyNewObject = new myInjectedFactory();

(Tapi Anda harus waspada tentang penggunaan pola jenis ini di tempat pertama karena objek yang baru di controller Anda menciptakan dependensi sulit dilacak yang sulit untuk dipermainkan untuk pengujian. Lebih baik memiliki layanan mengelola koleksi objek untuk Anda daripada menggunakan dengan new()cerdik.)


Satu hal lagi, mereka semua lajang ...

Juga perlu diingat bahwa dalam kedua kasus, sudut membantu Anda mengelola tunggal. Terlepas dari di mana atau berapa kali Anda menyuntikkan layanan atau fungsi Anda, Anda akan mendapatkan referensi yang sama ke objek atau fungsi yang sama. (Dengan pengecualian ketika pabrik hanya mengembalikan nilai seperti angka atau string. Dalam hal ini, Anda akan selalu mendapatkan nilai yang sama, tetapi bukan referensi.)


2
Apakah lebih baik menyebutnya sebagai konstruktor objek daripada yang Baru?
markyzm

2
@Hugo, saya menunjukkan bahwa Anda dapat secara efektif menyelesaikan hal yang sama dengan keduanya, hanya saja sintaksnya akan berbeda.
Gil Birman

105
Saya tidak yakin berapa kali saya harus membaca tentang perbedaan antara layanan dan pabrik sebelum saya yakin keduanya diperlukan
DMac the Destroyer

10
Kami sudah memiliki kata kerja untuk mengatakan "to new", ini "instantiate". Hanya untuk referensi. :)
sscarduzio

7
Pabrik adalah fungsi yang dipanggil, sehingga mereka dapat mengembalikan apa pun. Di sisi lain, layanan adalah instantiated oleh angular via new fn(), jadi mereka harus mengembalikan instance.
Gil Birman

318

Sederhananya ..

// 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
Bung, terima kasih. Bukan berarti rincian jawaban lain tidak valid, tetapi beberapa kali Anda memerlukan versi 10 detik.
R Claven

4
Hanya saja fungsi layanan tidak mengembalikan apa pun. The this.name = ... sudah cukup untuk menunjukkan bahwa itu mengekspos API.
pixelbits

3
Namun jika Anda benar-benar kembali dan keberatan, ia akan menggunakannya sebagai ganti ini. jsfiddle.net/Ne5P8/1221
MrB

@ MR, itu adalah fitur JavaScript normal, tidak spesifik untuk sudut atau konteks pertanyaan ini.
Om Shankar

@Om Shankar, Jawaban di atas menunjukkan bahwa perbedaannya adalah penggunaan ini vs objek yang dikembalikan. Saya menunjukkan bahwa "INI" adalah nilai default yang akan digunakan dengan layanan namun jika Anda mengembalikan nilai itu akan bertindak hampir persis seperti pabrik. Namun di sisi lain sebuah pabrik tampaknya membutuhkan nilai yang dikembalikan jika kesalahan terjadi - (ditunjukkan dalam contoh ini - jsfiddle.net/hmoc0q3v/1 ).
MrB

247

Inilah perbedaan utamanya:

Jasa

Sintaksis: module.service( 'serviceName', function );

Hasil: Saat mendeklarasikan serviceName sebagai argumen yang dapat disuntikkan, Anda akan diberikan instance fungsi yang diteruskan ke module.service.

Penggunaan: Dapat bermanfaat untuk berbagi fungsi utilitas yang berguna untuk dipanggil hanya dengan menambahkan ( )referensi fungsi yang disuntikkan. Bisa juga dijalankan denganinjectedArg.call( this ) atau serupa.

Pabrik

Sintaksis: module.factory( 'factoryName', function );

Hasil: Saat mendeklarasikan factoryName sebagai argumen injeksi, Anda akan diberikan nilai yang dikembalikan dengan menggunakan referensi fungsi yang diteruskan kemodule.factory .

Penggunaan: Dapat bermanfaat untuk mengembalikan 'kelas' yang kemudian dapat digunakan untuk membuat instance.

Berikut ini adalah contoh menggunakan layanan dan pabrik . Baca lebih lanjut tentang Layanan AngularJS vs Pabrik .

Anda juga dapat memeriksa dokumentasi AngularJS dan pertanyaan serupa tentang stackoverflow yang bingung tentang layanan vs pabrik .


27
Saya tidak setuju dengan contoh penggunaan pabrik Anda. Baik layanan maupun pabrik (dengan asumsi suatu fungsi dikembalikan. Bisa saja berupa nilai atau objek) dapat menjadi baru. Bahkan layanan adalah satu-satunya pilihan yang dijamin baru karena Anda diberikan contoh fungsi. Saya akan mengatakan manfaat dari menggunakan PABRIK di atas LAYANAN adalah bahwa hal itu memungkinkan beberapa kontrol atas akses ke properti - swasta & publik per se sedangkan semua sifat dari layanan secara alami terbuka. Dan saya menganggap penyedia sebagai pabrik dari pabrik - hanya saja itu dapat disuntikkan dan dapat dikonfigurasi pada waktu konfigurasi.
Drew R

1
@DrewR Terima kasih atas komentar Anda, saya menemukan contoh yang baik dari metode publik dan pribadi menggunakan Factory: stackoverflow.com/a/14904891/65025
edzillion

Sebenarnya saya harus setuju dengan @DrewR. Saya telah menggunakan pabrik untuk mengembalikan benda sebelumnya, tetapi jujur ​​pada titik ini mungkin layak untuk hanya menggunakan $providerswaktu.
jedd.ahyoung

layanan otomatis instantiating konstruktor, kan?
Martian2049

1
@DrewR - Dari pemahaman saya, memang benar bahwa Anda dapat mencapai efek baru yang sama dari layanan seperti yang Anda dapat dengan pabrik, tetapi bukan itu yang dimaksudkan untuk itu. Tujuan utamanya adalah ketika Anda hanya ingin mengembalikan beberapa objek utilitas dan untuk itu menyediakan sintaksis yang lebih cocok - Anda dapat menulis this.myFunc = function(){}di layanan Anda (menyelamatkan Anda dari menulis kode untuk membuat objek seperti yang harus Anda lakukan dengan pabrik) ).
BornToCode

137

TL; DR

1) Saat Anda menggunakan Pabrik, Anda membuat objek, menambahkan properti ke sana, lalu mengembalikan objek yang sama. Ketika Anda melewati pabrik ini ke controller Anda, properti-properti pada objek sekarang akan tersedia di controller melalui pabrik Anda.

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) Saat Anda menggunakan Layanan , Angular membuat instance di belakang layar dengan kata kunci 'baru'. Karena itu, Anda akan menambahkan properti ke 'ini' dan layanan akan mengembalikan 'ini'. Ketika Anda melewati layanan ke controller Anda, properti-properti di 'ini' sekarang akan tersedia pada controller itu melalui layanan Anda.

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

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



Non TL; DR

1) Pabrik
Pabrik adalah cara paling populer untuk membuat dan mengonfigurasi layanan. Benar-benar tidak lebih dari apa yang dikatakan TL; DR. Anda cukup membuat objek, menambahkan properti ke sana, lalu mengembalikan objek yang sama. Kemudian ketika Anda melewati pabrik ke controller Anda, properti-properti pada objek sekarang akan tersedia di controller melalui pabrik Anda. Contoh yang lebih luas ada di bawah ini.

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

Sekarang properti apa pun yang kita lampirkan ke 'layanan' akan tersedia untuk kita ketika kita melewati 'myFactory' ke controller kita.

Sekarang mari kita tambahkan beberapa variabel 'pribadi' ke fungsi panggilan balik kita. Ini tidak akan dapat diakses langsung dari controller, tetapi kami akhirnya akan menyiapkan beberapa metode pengambil / penyetel pada 'layanan' untuk dapat mengubah variabel 'pribadi' ini ketika diperlukan.

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;
});

Di sini Anda akan melihat kami tidak melampirkan variabel / fungsi itu ke 'layanan'. Kami hanya membuatnya untuk menggunakan atau memodifikasinya nanti.

  • baseUrl adalah URL dasar yang dibutuhkan oleh iTunes API
  • _artist adalah artis yang ingin kita cari
  • _finalUrl adalah URL final dan sepenuhnya dibangun yang akan kami panggil ke iTunes makeUrl adalah fungsi yang akan membuat dan mengembalikan URL ramah iTunes kami.

Sekarang, ketika variabel pembantu dan fungsi dan fungsi kami sudah ada, mari kita tambahkan beberapa properti ke objek 'layanan'. Apa pun yang kita pakai pada 'layanan' kita akan dapat langsung menggunakan pengontrol mana pun yang kita lewati 'myFactory'.

Kita akan membuat metode setArtist dan getArtist yang hanya mengembalikan atau mengatur artis. Kami juga akan membuat metode yang akan memanggil iTunes API dengan URL yang kami buat. Metode ini akan mengembalikan janji yang akan dipenuhi setelah data telah kembali dari iTunes API. Jika Anda belum memiliki banyak pengalaman menggunakan janji-janji di Angular, saya sangat merekomendasikan melakukan penyelaman mendalam pada mereka.

Di bawah setArtist menerima artis dan memungkinkan Anda untuk mengatur artis. getArtist mengembalikan artist callItunes panggilan pertama makeUrl () untuk membangun URL yang akan kami gunakan dengan permintaan $ http kami. Kemudian ia membuat objek janji, membuat permintaan $ http dengan url akhir kami, lalu karena $ http mengembalikan janji, kami dapat memanggil .success atau .error setelah permintaan kami. Kami kemudian menyelesaikan janji kami dengan data iTunes, atau kami menolaknya dengan pesan yang mengatakan 'Ada kesalahan'.

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;
});

Sekarang pabrik kami selesai. Kami sekarang dapat menyuntikkan 'myFactory' ke dalam pengontrol apa pun dan kami kemudian dapat memanggil metode kami yang kami lampirkan ke objek layanan kami (setArtist, getArtist, dan callItunes).

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);
      })
  }
});

Pada controller di atas kami menyuntikkan layanan 'myFactory'. Kami kemudian mengatur properti pada objek $ scope kami yang berasal dari data dari 'myFactory'. Satu-satunya kode rumit di atas adalah jika Anda belum pernah berurusan dengan janji sebelumnya. Karena callItunes mengembalikan janji, kita dapat menggunakan metode .then () dan hanya menetapkan $ scope.data.artistData setelah janji kita dipenuhi dengan data iTunes. Anda akan melihat pengontrol kami sangat 'tipis'. Semua logika dan data persisten kami terletak di layanan kami, bukan di controller kami.

2) Layanan
Mungkin hal terbesar yang perlu diketahui ketika berhadapan dengan menciptakan Layanan adalah bahwa itu dipakai dengan kata kunci 'baru'. Bagi Anda guru JavaScript ini harus memberi Anda petunjuk besar tentang sifat kode. Bagi Anda yang memiliki latar belakang terbatas dalam JavaScript atau bagi mereka yang tidak terlalu mengenal apa kata kunci 'baru' sebenarnya, mari kita tinjau beberapa dasar-dasar JavaScript yang pada akhirnya akan membantu kita dalam memahami sifat dari suatu Layanan.

Untuk benar-benar melihat perubahan yang terjadi ketika Anda menjalankan fungsi dengan kata kunci 'baru', mari kita membuat fungsi dan memohonnya dengan kata kunci 'baru', lalu mari kita tunjukkan apa yang dilakukan penerjemah ketika melihat kata kunci 'baru'. Hasil akhirnya akan sama.

Pertama mari kita buat konstruktor kita.

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

Ini adalah fungsi konstruktor JavaScript yang khas. Sekarang setiap kali kita memanggil fungsi Person menggunakan kata kunci 'baru', 'ini' akan terikat ke objek yang baru dibuat.

Sekarang mari kita tambahkan metode ke prototipe Person kita sehingga akan tersedia pada setiap instance 'kelas' Person kita.

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

Sekarang, karena kita meletakkan fungsi sayName pada prototipe, setiap instance dari Person akan dapat memanggil fungsi sayName untuk mengingatkan nama instance itu.

Sekarang kita memiliki fungsi konstruktor Person kita dan fungsi sayName kita pada prototipe, mari kita benar-benar membuat instance Person kemudian memanggil fungsi sayName.

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

Jadi, bersama-sama kode untuk membuat konstruktor Person, menambahkan fungsi ke prototipe itu, membuat contoh Person, dan kemudian memanggil fungsi pada prototipe terlihat seperti ini.

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'

Sekarang mari kita lihat apa yang sebenarnya terjadi ketika Anda menggunakan kata kunci 'baru' dalam JavaScript. Hal pertama yang harus Anda perhatikan adalah bahwa setelah menggunakan 'baru' dalam contoh kami, kami dapat memanggil metode (sayName) di 'tyler' seolah-olah itu adalah objek - itu karena itu. Jadi pertama-tama, kita tahu bahwa konstruktor Person kita mengembalikan objek, apakah kita dapat melihatnya dalam kode atau tidak. Kedua, kita tahu bahwa karena fungsi sayName kita terletak pada prototipe dan tidak langsung pada contoh Person, objek yang dikembalikan fungsi Person harus didelegasikan ke prototipe pada pencarian gagal. Dalam istilah yang lebih sederhana, ketika kita memanggil tyler.sayName () interpreter mengatakan “OK, aku akan melihat objek 'tyler' yang baru saja kita buat, cari fungsi sayName, lalu panggil saja. Tunggu sebentar, saya tidak melihatnya di sini - yang saya lihat hanyalah nama dan umur, izinkan saya memeriksa prototipe. Yup, sepertinya ada di prototipe, biar saya sebut saja. ”.

Di bawah ini adalah kode untuk cara Anda berpikir tentang apa yang sebenarnya dilakukan kata kunci 'baru' dalam JavaScript. Ini pada dasarnya adalah contoh kode paragraf di atas. Saya telah menempatkan 'tampilan penerjemah' atau cara penerjemah melihat kode di dalam catatan.

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;
}

Sekarang memiliki pengetahuan tentang apa yang sebenarnya dilakukan kata kunci 'baru' dalam JavaScript, membuat Layanan di Angular harus lebih mudah dipahami.

Hal terbesar untuk dipahami saat membuat Layanan adalah mengetahui bahwa Layanan dipakai dengan kata kunci 'baru'. Menggabungkan pengetahuan itu dengan contoh-contoh kami di atas, Anda sekarang harus mengakui bahwa Anda akan melampirkan properti dan metode Anda langsung ke 'ini' yang kemudian akan dikembalikan dari Layanan itu sendiri. Mari kita lihat ini dalam aksi.

Tidak seperti apa yang awalnya kami lakukan dengan contoh Pabrik, kita tidak perlu membuat objek lalu mengembalikan objek itu karena, seperti yang disebutkan berkali-kali sebelumnya, kita menggunakan kata kunci 'baru' sehingga penerjemah akan membuat objek itu, minta didelegasikan kepada itu prototipe, lalu kembalikan untuk kita tanpa kita harus melakukan pekerjaan.

Hal pertama yang pertama, mari kita buat fungsi 'pribadi' dan penolong kami. Ini seharusnya terlihat sangat akrab karena kami melakukan hal yang persis sama dengan pabrik kami. Saya tidak akan menjelaskan apa yang dilakukan setiap baris di sini karena saya melakukannya di contoh pabrik, jika Anda bingung, baca kembali contoh pabrik.

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;
  }
});

Sekarang, kami akan melampirkan semua metode kami yang akan tersedia di controller kami untuk 'ini'.

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;
  }

});

Sekarang sama seperti di pabrik kami, setArtist, getArtist, dan callItunes akan tersedia di mana pun controller kita lewati myService. Inilah pengendali myService (yang hampir persis sama dengan pengontrol pabrik kami).

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);
      })
  }
});

Seperti yang saya sebutkan sebelumnya, begitu Anda benar-benar memahami apa yang 'baru' lakukan, Layanan hampir identik dengan pabrik di Angular.


12
Anda mungkin ingin memberikan tautan langsung ke blog Anda. tylermcginnis.com/angularjs-factory-vs-service-vs-provider Saya menemukan bahwa sedikit lebih mudah dibaca.
Tyler Collier

3
Tidak ada yang salah dengan mengulangi blog Anda di sini, tapi saya setuju itu adalah posting blog greta.
R Claven

5
Penjelasan detail yang bagus tentang apa yang masing-masing lakukan di bawah tenda, tetapi masih belum jelas mengapa dan kapan seseorang memilih untuk menggunakan Layanan di atas Pabrik. Dengan kata lain, kapan saya akan memilih untuk memiliki objek yang baru vs yang dikembalikan oleh pabrik. Saya pikir ini adalah kebingungan terbesar.
demisx

2
Pada dasarnya, jika Anda ingin membuat koneksi persisten ke layanan jarak jauh, seperti iTunes API yang disebutkan dalam contoh dengan koneksi konstan (keadaan koneksi, riwayat panggilan, penyimpanan data), Anda dapat pergi dengan Factory. Jika Anda menerapkannya sebagai Layanan, maka setiap kali Anda menginginkan sesuatu dari API, Anda harus membuat kembali koneksi dan tidak dapat menyimpan apa pun di dalamnya. Karena setiap kali Anda membuat ulang layanan, Anda akan mendapatkan objek kosong / default.
Meki

4
Saya tidak berpikir itu benar, @Aznim. Seperti yang dikatakan orang lain, keduanya menyediakan lajang.
Cryptovirus

35

Petunjuk ada dalam nama

Layanan dan pabrik mirip satu sama lain. Keduanya akan menghasilkan objek tunggal yang dapat disuntikkan ke objek lain, dan sering digunakan secara bergantian.

Mereka dimaksudkan untuk digunakan secara semantik untuk menerapkan pola desain yang berbeda.

Layanan adalah untuk menerapkan pola layanan

Pola layanan adalah pola di mana aplikasi Anda dipecah menjadi unit fungsional yang konsisten secara logis. Contohnya mungkin pengakses API, atau serangkaian logika bisnis.

Hal ini sangat penting dalam Angular karena model Angular biasanya hanya objek JSON yang ditarik dari server, jadi kami membutuhkan tempat untuk meletakkan logika bisnis kami.

Berikut adalah layanan Github misalnya. Ia tahu cara berbicara dengan Github. Ia tahu tentang url dan metode. Kita bisa menyuntikkannya ke controller, dan itu akan menghasilkan dan mengembalikan janji.

(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);
      }
    });
  )();

Pabrik menerapkan pola pabrik

Pabrik, di sisi lain dimaksudkan untuk menerapkan pola pabrik. Pola pabrik di mana kita menggunakan fungsi pabrik untuk menghasilkan objek. Biasanya kita dapat menggunakan ini untuk membangun model. Berikut adalah pabrik yang mengembalikan konstruktor Penulis:

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

Kami akan menggunakan ini seperti ini:

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

Perhatikan bahwa pabrik juga mengembalikan lajang.

Pabrik dapat mengembalikan konstruktor

Karena pabrik hanya mengembalikan objek, itu dapat mengembalikan semua jenis objek yang Anda suka, termasuk fungsi konstruktor, seperti yang kita lihat di atas.

Pabrik mengembalikan objek; layanan baru

Perbedaan teknis lainnya adalah dalam hal layanan dan pabrik disusun. Fungsi layanan akan dikabarkan baru untuk menghasilkan objek. Fungsi pabrik akan dipanggil dan akan mengembalikan objek.

  • Layanan adalah konstruktor yang baru.
  • Pabrik hanya dipanggil dan mengembalikan objek.

Ini berarti bahwa dalam suatu layanan, kami menambahkan "ini" yang, dalam konteks konstruktor, akan menunjuk ke objek yang sedang dibangun.

Untuk menggambarkan hal ini, berikut adalah objek sederhana yang sama dibuat menggunakan layanan dan pabrik:

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

2
penjelasan yang bagus, terima kasih! juga ada jenis kode sampel Pabrik di mana Authorparameter injektor seharusnya Person.
mikhail-t

Terima kasih @ mik-T, saya memperbaiki kesalahan ketik.
superluminary

1
Penggunaan pola layanan oleh Anda salah - ini harusnya pabrik. Jika Anda memanggil .factory () alih-alih .service () Anda akan melihat bahwa kerjanya persis sama. Pola layanan dimaksudkan untuk diberikan dengan fungsi konstruktor, bukan fungsi yang mengembalikan objek baru. Panggilan sudut (secara efektif) "baru" pada fungsi konstruktor Anda. Satu-satunya alasan layanan Anda berfungsi adalah jika Anda memanggil "baru" pada fungsi konstruktor yang mengembalikan objek, Anda benar-benar mendapatkan kembali objek yang dikembalikan daripada yang dibangun. Dan pabrik dapat digunakan untuk membuat apa pun yang Anda inginkan, bukan hanya model.
Dan King

27

Semua jawaban di sini tampaknya ada di sekitar layanan dan pabrik, dan itu sah karena itulah yang ditanyakan. Tapi itu juga penting untuk diingat bahwa ada beberapa orang lain termasuk provider(), value(), dan constant().

Kunci untuk diingat adalah bahwa masing-masing adalah kasus khusus dari yang lain. Setiap kasing khusus memungkinkan Anda melakukan hal yang sama dengan kode lebih sedikit. Masing-masing juga memiliki beberapa batasan tambahan.

Untuk memutuskan kapan harus menggunakan yang baru saja Anda lihat mana yang memungkinkan Anda melakukan apa yang Anda inginkan dalam kode yang lebih sedikit. Berikut adalah gambar yang menggambarkan betapa miripnya mereka:

masukkan deskripsi gambar di sini

Untuk rincian langkah demi langkah lengkap dan referensi cepat kapan harus menggunakan masing-masing Anda dapat mengunjungi posting blog tempat saya mendapatkan gambar ini dari:

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


3
@ Jacob mungkin begitu, tapi saya pikir konsep keseluruhan tidak hanya kapan harus menggunakan masing-masing, tetapi mereka semua pada dasarnya variasi dari hal yang sama adalah yang penting.
Luis Perez

1
@LuisPerez Tautan ke blog Anda dan video yang menjelaskan perbedaannya sangat bagus. Lebih mudah untuk memahami dengan contoh-contoh dari video :)
Alin Ciocan

24

app.factory ('fn', fn) vs. app.service ('fn', fn)

Konstruksi

Dengan pabrik, Angular akan memanggil fungsi untuk mendapatkan hasilnya. Ini adalah hasil yang di-cache dan disuntikkan.

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

Dengan layanan, Angular akan memanggil fungsi konstruktor dengan memanggil yang baru . Fungsi yang dibangun di-cache dan disuntikkan.

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

Penerapan

Pabrik biasanya mengembalikan objek literal karena nilai kembali adalah apa yang disuntikkan ke pengontrol, menjalankan blok, arahan, dll

  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
         }
  });

Fungsi layanan biasanya tidak mengembalikan apa pun. Sebagai gantinya, mereka melakukan inisialisasi dan mengekspos fungsi. Fungsi juga dapat merujuk 'ini' karena dibangun menggunakan 'baru'.

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

Kesimpulan

Dalam hal menggunakan pabrik atau layanan, keduanya sangat mirip. Mereka disuntikkan ke controller, arahan, run block, dll, dan digunakan dalam kode klien dengan cara yang hampir sama. Keduanya juga lajang - yang berarti contoh yang sama dibagi antara semua tempat di mana layanan / pabrik disuntikkan.

Jadi mana yang harus Anda pilih? Salah satunya - mereka sangat mirip sehingga perbedaannya sepele. Jika Anda memilih salah satu dari yang lain, perhatikan saja cara pembuatannya, sehingga Anda dapat menerapkannya dengan benar.


Fungsi layanan tidak "tidak mengembalikan apa-apa", mereka secara implisit mengembalikan objek yang dibangun JIKA Anda tidak menentukan pernyataan pengembalian Anda sendiri (dalam kasus terakhir objek yang Anda kembalikan adalah apa yang akan dibuat dan di-cache, mirip dengan pabrik).
Cryptovirus

Saya pikir Anda salah mengartikannya ... Ketika saya katakan kembali, maksud saya dari sudut pandang implementasi fungsi layanan
pixelbits

apakah Anda yakin pabrik juga kota tunggal?
Martian2049

5

Saya telah menghabiskan beberapa waktu untuk mencari tahu perbedaannya.

Dan saya pikir fungsi pabrik menggunakan pola modul dan fungsi layanan menggunakan pola konstruktor skrip java standar.


2

Pola pabrik lebih fleksibel karena dapat mengembalikan fungsi dan nilai serta objek.

Tidak ada banyak titik dalam pola layanan IMHO, karena semua yang dilakukannya dapat dengan mudah dilakukan dengan pabrik. Pengecualian mungkin:

  • Jika Anda peduli tentang jenis layanan instantiated yang diumumkan karena alasan tertentu - jika Anda menggunakan pola layanan, konstruktor Anda akan menjadi jenis layanan baru.
  • Jika Anda sudah memiliki fungsi konstruktor yang Anda gunakan di tempat lain yang juga ingin Anda gunakan sebagai layanan (walaupun mungkin tidak banyak digunakan jika Anda ingin menyuntikkan sesuatu ke dalamnya!).

Bisa dibilang, pola layanan adalah cara yang sedikit lebih baik untuk membuat objek baru dari sudut pandang sintaksis, tetapi juga lebih mahal untuk instantiate. Yang lain telah mengindikasikan bahwa sudut menggunakan "baru" untuk membuat layanan, tetapi ini tidak sepenuhnya benar - tidak dapat melakukan itu karena setiap konstruktor layanan memiliki jumlah parameter yang berbeda. Apa yang sebenarnya dilakukan angular adalah menggunakan pola pabrik secara internal untuk membungkus fungsi konstruktor Anda. Kemudian ia melakukan beberapa pokery jiggery yang pandai untuk mensimulasikan operator "baru" javascript, memanggil konstruktor Anda dengan sejumlah variabel argumen yang dapat diinjeksi - tetapi Anda dapat meninggalkan langkah ini jika Anda hanya menggunakan pola pabrik secara langsung, sehingga sangat sedikit meningkatkan efisiensi Anda kode.


Layanan lebih efisien untuk dibangun daripada Pabrik karena pabrik menggunakan penutupan yang relatif mahal dan layanan (kelas) dapat memanfaatkan prototipe.
jacob

@ jacob Tidak yakin apa yang Anda maksud tentang penutupan? Pabrik hanyalah fungsi yang mengembalikan objek. Anda hanya perlu menggunakan penutupan jika objek Anda yang dikembalikan memerlukan status "pribadi". Anda masih harus melakukan hal yang sama jika Anda menggunakan konstruktor (layanan). Saya mengambil poin Anda tentang prototipe - meskipun Anda masih bisa melakukan ini di pabrik jika Anda mau.
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 } }); } Sementara MyFactory dan MyService menggunakan prototipe, MyFactory masih membutuhkan kinerja karena harus membuat objek yang sedang dikembalikan. Dalam kedua contoh, mereka memiliki privat, tetapi di MyService relatif tidak ada perbedaan kinerja.
jacob

1
Bagi saya, perbedaannya adalah apakah saya ingin menggunakan pabrik secara langsung tanpa metode: MyFactory(someArgument)(mis $http()). Yang tidak mungkin dengan layanan seperti Anda akan referensi konstruktor: MyService(someArgument).
jacob

Pada waktu pembangunan objek, saya tidak benar-benar melihat bagaimana factory = {} adalah hit kinerja, lebih dari javascript menginisialisasi "ini" untuk Anda ketika memanggil konstruktor Anda? Dan saya pikir hit performa yang lebih besar ada di sisi sudut ketika membungkus konstruktor Anda di pabrik dan kemudian harus melompat melalui lingkaran untuk mensimulasikan "baru" sehingga dapat menyuntikkan dependensi Anda.
Dan King
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.