angular.service vs angular.factory


1065

Я бачив як angular.factory (), так і angular.service (), які використовуються для оголошення оголошень; однак я не можу angular.service ніде знайти офіційну документацію.

У чому різниця між двома методами?
Що слід використовувати для чого (якщо робити різні речі)?



4
Я шукав "фабрику послуг [[angularjs]", але також пам’ятав, що вже було питання з цього приводу (тому що я думав про те, щоб написати / це питання в один момент).
Марк Райкок

2
Чи означають квадратні дужки тег?
jacob

11
@Jacob Квадратні дужки звужують ваш пошук. [angularjs] директиви - буде шукати "директиви" для питань, які вже позначені тегами angularjs.
Махбуб

1
@Mahbub Іншими словами, "так" :)
Брайан

Відповіді:


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

У мене виникли проблеми з обертанням голови навколо цієї концепції, поки я не поставив це так:

Сервіс : функція, яку ви пишете, буде новою :

  myInjectedService  <----  new myServiceFunction()

Фабрика : функція (конструктор), яку ви пишете, буде викликана :

  myInjectedFactory  <---  myFactoryFunction()

Що ви робите з цим, залежить від вас, але є кілька корисних моделей ...

Наприклад, написання функції служби для відкриття загальнодоступного API:

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

Або використовуючи заводську функцію для відкриття загальнодоступного API:

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

Або використовуючи заводську функцію для повернення конструктора:

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

Який використовувати? ...

Ви можете зробити те ж саме з обома. Однак у деяких випадках фабрика надає вам трохи більшої гнучкості, щоб створити ін’єкційну форму з більш простим синтаксисом. Це тому, що, хоча myInjectedService завжди повинен бути об'єктом, myInjectedFactory може бути об'єктом, посиланням на функцію або будь-яким значенням. Наприклад, якщо ви написали службу для створення конструктора (як в останньому прикладі вище), її потрібно було б створити таким чином:

var myShinyNewObject = new myInjectedService.myFunction()

що, мабуть, менш бажано, ніж це:

var myShinyNewObject = new myInjectedFactory();

(Але ви повинні насторожено використовувати цей тип шаблону, в першу чергу, оскільки нові об'єкти в контролерах створюють важкі для відстеження залежності, які важко обмірковувати для тестування. Краще мати сервіс, який керує колекцією об'єктів для ти, ніж використовуй new()хитро-невольно.)


І ще одне - всі вони одиночні ...

Також пам’ятайте, що в обох випадках кутовий допомагає вам керувати одинокою. Незалежно від того, куди чи скільки разів ви вводите свою послугу чи функцію, ви отримаєте те саме посилання на той самий об’єкт чи функцію. (За винятком випадків, коли фабрика просто повертає таке значення, як число чи рядок. У цьому випадку ви завжди отримаєте те саме значення, але не посилання.)


2
Чи було б краще назвати це конструктором об’єктів, ніж Newable?
markyzm

2
@Hugo, я демонстрував, що ти можеш ефективно виконати те саме з обома, просто синтаксис відрізнятиметься.
Гіл Бірман

105
Я не впевнений, скільки разів мені доведеться прочитати про різницю між сервісом та фабрикою, перш ніж переконатись, що вони потрібні
DMac the Destroyer

10
У нас вже є дієслово сказати «новому», це «миттєво». Тільки для довідки. :)
sscarduzio

7
Фабрики - це функції, які викликаються, тому вони можуть повернути що завгодно. З іншого боку, служби інстанціюються угловим через new fn(), тому вони повинні повернути екземпляр.
Гіл Бірман

318

Простіше кажучи ..

// 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
Чувак, дякую. Не те, що деталі інших відповідей не вірні, але іноді потрібна версія 10 секунд.
R Клавен

4
Просто сервісна функція нічого не повертає. This.name = ... досить , щоб показати , що вона піддаючи API.
піксельбіт

3
Однак якщо ви повернетесь і заперечуєте, він використовуватиме це замість цього. jsfiddle.net/Ne5P8/1221
MrB

@MrB, це звичайна функція JavaScript, не специфічна для Angular або контексту цього питання.
Ом Шанкар

@ Om Shankar, Відповідь, наведена вище, показує, що різниця полягає у використанні цього відносно об'єкта, який повертається. Я показував, що "ЦЕ" - це значення за замовчуванням, яке буде використано для послуги, однак якщо ви повернете значення, воно буде діяти майже так само, як і заводське. Однак на зворотному боці фабрика, як видається, вимагає поверненого значення, інакше буде статися помилка - (показано в цьому прикладі - jsfiddle.net/hmoc0q3v/1 ).
MrB

247

Ось основні відмінності:

Послуги

Синтаксис: module.service( 'serviceName', function );

Результат: При оголошенні serviceName як аргументу, який можна ввести, вам буде наданий екземпляр функції, переданої в module.service.

Використання: може бути корисним для спільного використання функцій утиліти , які корисно викликати, просто додавши ( )до введеної посилання функції. Може також працювати з injectedArg.call( this )подібним або подібним.

Заводи

Синтаксис: module.factory( 'factoryName', function );

Результат: При оголошенні factoryName як аргументу, який можна ввести, вам буде надано значення, яке повертається, викликаючи посилання на функцію, передану на module.factory.

Використання: Може бути корисним для повернення функції "class", яка потім може бути new'ed для створення примірників.

Ось приклад використання служб та фабрики . Детальніше про AngularJS Service vs Factory .

Ви також можете перевірити документацію AngularJS та подібне запитання про stackoverflow, що плутається щодо сервісу та фабрики .


27
Я не згоден з вашим прикладом використання фабрики. Нові послуги та фабрики (при умові повернення функції. Це може бути просто значення або об'єкт). Насправді сервіс - це єдиний варіант, який гарантовано стане новим, коли вам надається екземпляр функції. Я б сказав, що перевага від використання ФАБРИКИ над ПОСЛУГОю полягає в тому, що вона дозволяє контролювати доступ до власних ресурсів - приватних та загальнодоступних, хоча всі властивості послуги піддаються природі. І я думаю про постачальника як про фабрику заводу - лише він є ін'єкційним і налаштовується в час конфігурації.
Дрю Р

1
@DrewR Спасибі за ваш коментар, я знайшов хороший приклад державних і приватних методів , які використовують Factory: stackoverflow.com/a/14904891/65025
edzillion

Насправді я маю згоду з @DrewR. Раніше я використовував фабрики для повернення об'єктів, але, чесно кажучи, на даний момент, можливо, варто просто використовувати $providersвесь час.
jedd.ahyoung

сервіс - автоматичне інстанціювання конструктора, правда?
Martian2049

1
@DrewR - Наскільки я розумію, це правда, що ви можете домогтися такого ж нового ефекту від служби, як ви можете з фабрики, але це не те, для чого це призначено. Його головна мета полягає в тому, коли ви просто хочете повернути якийсь об’єкт корисної програми, і для цього він забезпечує більш підходящий синтаксис - ви можете просто написати this.myFunc = function(){}в вашій службі (заощаджує вас від написання коду, щоб створити об'єкт, як ви повинні робити з заводською ).
BornToCode

137

TL; DR

1) Коли ви використовуєте Factory, ви створюєте об'єкт, додаєте до нього властивості та повертаєте цей самий об’єкт. Коли ви передасте цю фабрику у свій контролер, ці властивості об’єкта тепер будуть доступні в цьому контролері через вашу фабрику.

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) Коли ви користуєтесь службою , Angular створює її за кадром за допомогою "нового" ключового слова. Через це ви додасте властивості до "цього", і служба поверне "це". Коли ви передасте послугу в свій контролер, ці властивості на "це" тепер будуть доступні на цьому контролері через вашу службу.

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) Заводські
фабрики - найпопулярніший спосіб створення та налаштування послуги. Дійсно не набагато більше, ніж те, що сказав TL; DR. Ви просто створюєте об'єкт, додаєте до нього властивості, а потім повертаєте той самий об’єкт. Потім, коли ви передасте завод у свій контролер, ці властивості об’єкта тепер будуть доступні в цьому контролері через вашу фабрику. Більш обширний приклад наведено нижче.

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

Тепер будь-які властивості, які ми надаємо до "служби", будуть нам доступні, коли ми передамо "myFactory" в наш контролер.

Тепер додамо кілька "приватних" змінних до нашої функції зворотного дзвінка. Вони не будуть доступні безпосередньо від контролера, але ми зрештою встановимо кілька методів getter / setter на "service", щоб мати можливість змінювати ці "приватні" змінні при необхідності.

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

Тут ви помітите, що ми не прив'язуємо ці змінні / функції до "служби". Ми просто створюємо їх для того, щоб пізніше їх використовувати чи змінювати.

  • baseUrl - це базова URL-адреса, необхідна API iTunes
  • _artist - художник, якого ми хочемо знайти
  • _finalUrl - це остаточна і повністю вбудована URL-адреса, до якої ми здійснимо виклик до iTunes makeUrl - це функція, яка створить та поверне нашу iTunes дружню URL-адресу.

Тепер, коли наші помічникові / приватні змінні та функціонують на місці, давайте додамо деякі властивості до об’єкта 'service'. Що б ми не поставили на "послугу", ми зможемо безпосередньо використовувати в тому контролері, в який ми передамо "myFactory".

Ми створимо методи setArtist і getArtist, які просто повертають або встановлюють виконавця. Ми також створимо метод, який викликатиме API iTunes за допомогою створеної нами URL-адреси. Цей метод поверне обіцянку, яка виконається, коли дані повернуться з iTunes API. Якщо у вас не було великого досвіду використання обіцянок у Angular, я настійно рекомендую зробити глибоке занурення у них.

Нижче setArtist приймає виконавця та дозволяє встановити виконавця. getArtist повертає виконавцю callItunes перші дзвінки makeUrl (), щоб створити URL-адресу, яку ми будемо використовувати з нашим $ http-запитом. Потім він встановлює об'єкт обіцянки, робить $ http запит з нашою остаточною URL-адресою, і тому, що $ http повертає обіцянку, ми можемо викликати .success або .error після нашого запиту. Потім ми вирішуємо свою обіцянку за допомогою даних iTunes або відхиляємо її повідомленням "Виникла помилка".

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

Зараз наша фабрика завершена. Тепер ми можемо ввести 'myFactory' у будь-який контролер, і тоді ми зможемо викликати наші методи, які ми приєднали до нашого сервісного об’єкта (setArtist, getArtist та 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);
      })
  }
});

У контролері вище ми вводимо в службу "myFactory". Потім ми встановлюємо властивості для нашого об'єкта $ range, які надходять із даних "myFactory". Єдиний хитрий код вище - якщо ви ніколи раніше не займалися обіцянками. Оскільки callItunes повертає обіцянку, ми можемо скористатися методом .then () і встановити лише $ range.data.artistData, як тільки наша обіцянка буде виконана з даними iTunes. Ви помітите, що наш контролер дуже "тонкий". Всі наші логічні та стійкі дані знаходяться в нашій службі, а не в нашому контролері.

2) Сервіс
Мабуть, найбільше, що потрібно знати при створенні Служби, - це те, що вона створена "новим" ключовим словом. Для вас, гуру JavaScript, це повинно дати вам великий натяк на природу коду. Для тих із вас, хто має обмежений досвід роботи в JavaScript, або для тих, хто не надто знайомий з тим, що насправді має "нове" ключове слово, давайте розглянемо деякі основи JavaScript, які з часом допоможуть нам зрозуміти природу Сервісу.

Щоб дійсно побачити зміни, які виникають, коли ви викликаєте функцію за допомогою ключового слова "new", давайте створимо функцію та позовимо її за допомогою "new" ключового слова, тоді покажемо, що робить інтерпретатор, коли бачить "new" ключове слово. Кінцеві результати будуть однаковими.

Спочатку давайте створимо наш Конструктор.

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

Це типова функція конструктора JavaScript. Тепер, коли ми викликаємо функцію Person, використовуючи ключове слово "new", "це" буде прив'язане до новоствореного об'єкта.

Тепер додамо метод до прототипу нашого Person, щоб він був доступний у всіх екземплярах нашого класу Person.

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

Тепер, оскільки ми поклали функцію sayName на прототип, кожен екземпляр Person зможе викликати функцію sayName, щоб оповістити ім'я цього екземпляра.

Тепер, коли у нас в прототипі є функція конструктора Person і наша функція sayName, давайте створимо екземпляр Person, а потім викличемо функцію sayName.

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

Отже, все разом код для створення конструктора Person, додавання функції до його прототипу, створення екземпляра Person, а потім виклик функції в її прототипі виглядає приблизно так.

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'

Тепер давайте розглянемо, що насправді відбувається, коли ви використовуєте "нове" ключове слово в JavaScript. Перше, що ви повинні зауважити, це те, що, використовуючи «new» у нашому прикладі, ми можемо викликати метод (sayName) на «tyler» так само, як якщо б це був об’єкт - це тому, що це так. Отже, спочатку ми знаємо, що наш конструктор Person повертає об'єкт, можемо ми бачити це в коді чи ні. По-друге, ми знаємо, що оскільки наша функція sayName розташована на прототипі, а не безпосередньо в екземплярі Person, об'єкт, який повертає функція Person, повинен бути делегований своєму прототипу при невдалих пошуках. Простіше кажучи, коли ми називаємо tyler.sayName () інтерпретатор каже: «Добре, я перегляну об’єкт« tyler », який ми тільки що створили, знайдіть функцію sayName, а потім зателефонуйте їй. Почекайте хвилину, я не бачу тут - все, що я бачу, це ім'я та вік, дозвольте перевірити прототип. Так, схоже на прототип, дозвольте мені це назвати ».

Нижче наведено код того, як ви можете подумати про те, що насправді працює нове ключове слово в JavaScript. Це в основному приклад коду вищевказаного абзацу. Я поставив "погляд інтерпретатора" або те, як перекладач бачить код всередині приміток.

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

Тепер, маючи це знання про те, що "нове" ключове слово насправді робить у JavaScript, легше зрозуміти створення сервісу в Angular.

Найголовніше, що потрібно розуміти під час створення Служби - це знати, що Служби створені за допомогою "нового" ключового слова. Поєднуючи ці знання з нашими прикладами вище, тепер ви повинні визнати, що ви будете прив’язувати свої властивості та методи безпосередньо до "цього", який потім буде повернуто з самої Служби. Давайте розглянемо це в дії.

На відміну від того, що ми робили з фабричного прикладу, нам не потрібно створювати об'єкт, а потім повертати цей об'єкт, тому що, як уже згадувалося багато разів, ми використовували ключове слово "новий", щоб інтерпретатор створив цей об'єкт, чи його делегувати це прототип, то поверніть його нам, не маючи необхідності виконувати роботу.

Спочатку спочатку давайте створимо нашу "приватну" та допоміжну функцію. Це повинно виглядати дуже знайомо, оскільки ми зробили абсолютно те ж саме з нашою фабрикою. Я не поясню, що тут робить кожен рядок, тому що я це робив на заводському прикладі, якщо ви плутаєте, перечитайте заводський приклад.

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

Тепер ми додамо всі наші методи, які будуть доступні в нашому контролері, до цього.

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

});

Тепер так само, як на нашому заводі, setArtist, getArtist та callItunes будуть доступні в тому контролері, в який ми передамо myService. Ось контролер myService (який майже точно такий, як наш заводський контролер).

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

Як я вже згадував раніше, коли ви дійсно зрозумієте, що означає "нове", Послуги майже ідентичні фабрикам у Angular.


12
Ви можете надати посилання безпосередньо на свій блог. tylermcginnis.com/angularjs-factory-vs-service-vs-provider Я виявив, що трохи легше читати.
Тайлер Коллієр

3
Нічого не помиляється з повторенням свого блогу тут, але я згоден, що це публікація в блозі Ґрета.
R Клавен

5
Добре детальне пояснення того, що кожен робить під кришкою, але все ще не зрозуміло, чому і коли хтось вирішить скористатись Службою над Фабрикою. Іншими словами, коли я вважаю за краще мати новий об’єкт порівняно з поверненим заводом. Я думаю, що це найбільша плутанина.
демікс

2
В основному, якщо ви хочете створити стійке з'єднання з віддаленою службою, як API iTunes, згаданий у прикладі, з постійним з'єднанням (стан з'єднання, історія викликів, зберігання даних), ви можете перейти до програми Factory. Якщо ви реалізуєте його як Службу, то кожного разу, коли вам захочеться чогось із API, вам доведеться заново створювати з'єднання і насправді нічого в ньому не зберігати. Тому що кожного разу, коли ви заново створюєте послугу, ви отримуватимете порожній / за замовчуванням об’єкт.
Мекі

4
Я не думаю, що це правильно, @Aznim. Як і інші говорили, обидва забезпечують одиноких однорогів.
Криптовірус

35

Підказка в назві

Послуги та фабрики схожі між собою. Обидва дають однотонний об'єкт, який можна вводити в інші об’єкти, і тому вони часто використовуються взаємозамінно.

Вони призначені для семантичного використання для реалізації різних моделей дизайну.

Служби призначені для реалізації схеми обслуговування

Схема обслуговування - це те, в якому ваша програма розбита на логічно несумісні одиниці функціональності. Прикладом може бути аксесуар API або набір бізнес-логіки.

Це особливо важливо для кутових, тому що кутові моделі, як правило, є лише об'єктами JSON, витягнутими з сервера, і тому нам потрібно десь вкласти свою бізнес-логіку.

Ось, наприклад, сервіс Github. Він знає, як розмовляти з Гітбубом. Він знає про URL-адреси та методи. Ми можемо ввести його в контролер, і він породжує і поверне обіцянку.

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

Заводи реалізують заводський зразок

З іншого боку, заводи покликані реалізувати заводський зразок. Фабричний візерунок, в якому ми використовуємо фабричну функцію для створення об'єкта. Зазвичай ми можемо використовувати це для побудови моделей. Ось фабрика, яка повертає авторського конструктора:

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

Ми використаємо це так:

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

Зауважте, що фабрики також повертають однотонних.

Заводи можуть повернути конструктор

Оскільки фабрика просто повертає об'єкт, він може повертати будь-який тип об'єкта, який вам подобається, включаючи функцію конструктора, як ми бачимо вище.

Фабрики повертають об’єкт; послуги є новими

Інша технічна відмінність полягає в тому, як складаються служби та фабрики. Функція обслуговування буде створена для створення об'єкта. Буде викликана заводська функція і поверне об’єкт.

  • Послуги - це нові конструктори.
  • Фабрики просто називають і повертають об'єкт.

Це означає, що в сервісі ми додаємо "це", що в контексті конструктора вкаже на об'єкт, що будується.

Щоб проілюструвати це, ось той самий простий об’єкт, створений за допомогою сервісу та фабрики:

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

2
чудове пояснення, дякую! також у типовому коді AuthorФабрик є тип, де повинен бути параметр інжектора Person.
mikhail-t

Дякуючи @ mik-T, я виправив помилки друку.
суперлюмінація

1
Використання схеми обслуговування невірно - це повинно бути завод. Якщо ви зателефонуєте .factory () замість .service (), ви побачите, що він працює точно так само. Мається на увазі, що модель обслуговування надається функцією конструктора, а не функцією, яка повертає новий об'єкт. Кутовий (ефективно) викликає "нове" на вашій функції конструктора. Єдина причина, по якій працює ваша служба, полягає в тому, що, якщо ви викликаєте "нове" у функції конструктора, яка повертає об'єкт, ви фактично отримуєте повернутий об'єкт, а не сконструйований. І фабрики можна використовувати для створення всього, що завгодно, а не лише моделей.
Дан Кінг

27

Всі відповіді тут, здається, стосуються сервісного обслуговування та фабрики, і це дійсно, оскільки саме про це питали. Але це також важливо мати на увазі , що є кілька інших , включаючи provider(), value()і constant().

Ключове значення, що потрібно пам’ятати, - це те, що кожен з них є окремим випадком іншого. Кожен окремий випадок вниз по ланцюгу, що дозволяє вам робити те саме, що менше коду. Кожен з них також має додаткове обмеження.

Щоб вирішити, коли використовувати, який ви просто бачите, який дозволяє вам робити те, що ви хочете, за меншим кодом. Ось зображення, що ілюструє, наскільки вони схожі:

введіть тут опис зображення

Для повного покрокового розбиття та швидкого ознайомлення з тим, коли використовувати кожен, ви можете відвідати допис у блозі, звідки я отримав це зображення:

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


3
@jacob, можливо, так, але я думаю, що загальна концепція не тільки коли використовувати кожен, але й те, що всі вони є по суті варіаціями однієї і тієї ж речі, є важливою.
Луїс Перес

1
@LuisPerez Посилання на ваш блог та відео, що пояснюють різницю, це справді чудово. Простіше зрозуміти з тими прикладами з відео :)
Алін Чьокан

24

app.factory ('fn', fn) проти app.service ('fn', fn)

Будівництво

На заводах Angular буде викликати функцію для отримання результату. Це результат, який кешується та вводиться.

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

За допомогою послуг Angular буде викликати функцію конструктора, викликаючи нову . Побудована функція кешується та вводиться.

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

Впровадження

Заводи зазвичай повертають об'єкт буквально, оскільки значення повернення - це те, що вводиться в контролери, запущені блоки, директиви тощо

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

Сервісні функції зазвичай нічого не повертають. Натомість вони виконують ініціалізацію та розкривають функції. Функції також можуть посилатися на "це", оскільки воно було побудоване з використанням "нового".

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

Висновок

Що стосується використання фабрик чи служб, вони обидва дуже схожі. Вони вводяться в контролери, директиви, блок запуску тощо, і використовуються в коді клієнта майже однаково. Вони також обидва одиночні, тобто один і той же екземпляр ділиться між усіма місцями, куди вводиться служба / фабрика.

Отже, якому вам слід віддати перевагу? Або один - вони настільки схожі, що відмінності банальні. Якщо ви обираєте один над іншим, просто знайте, як вони побудовані, щоб ви могли їх правильно реалізувати.


Службові функції не "не повертають нічого", вони неявно повертають побудований об'єкт, якщо ви не вказуєте власне твердження про повернення (в останньому випадку об'єкт, який ви повертаєте, - це те, що буде створено та кешовано, подібно до заводських).
Криптовірус

Я думаю, ви неправильно трактуєте ... Коли я кажу, що повертаюсь, я маю на увазі з точки зору реалізації функції служби
пікселі

Ви впевнені, що фабрика також є одним містом?
Martian2049

5

Я витратив деякий час, намагаючись з’ясувати різницю.

І я думаю, що фабрична функція використовує шаблон модуля, а сервісна функція використовує стандартний шаблон конструктора сценарію Java.


2

Заводський зразок є більш гнучким, оскільки він може повертати функції та значення, а також об'єкти.

Немає сенсу в схемі обслуговування IMHO, оскільки все, що ви робите, ви можете зробити так само легко, як і на заводі. Винятки можуть бути:

  • Якщо ви з якоїсь причини переймаєтесь задекларованим типом своєї створеної послуги - якщо ви використовуєте шаблон обслуговування, ваш конструктор буде типом нової послуги.
  • Якщо у вас вже є конструкторська функція, яку ви використовуєте в іншому місці, яку ви також хочете використовувати як сервіс (хоча, ймовірно, не так багато, якщо ви хочете щось ввести в неї!).

Можливо, модель обслуговування є дещо приємнішим способом створення нового об’єкта з точки зору синтаксису, але також дорожче інстанціювати. Інші вказали, що кутовий використовує "нове" для створення служби, але це не зовсім вірно - це не в змозі зробити, оскільки кожен конструктор служби має різну кількість параметрів. Насправді кутовий - це використовувати фабричний візерунок всередині, щоб завершити функцію конструктора. Тоді він робить розумний покер джиггері для імітації "нового" оператора javascript, викликаючи вашого конструктора зі змінною кількістю аргументів, які можна вводити, - але ви можете вийти з цього кроку, якщо просто використовувати заводський зразок безпосередньо, тим самим дуже трохи підвищуючи ефективність роботи код.


Послуги побудувати ефективніше, ніж Фабрики, оскільки на заводах використовується відносно дороге закриття, а послуги (класи) можуть скористатися прототипом.
jacob

@jacob Не знаєте, що ви маєте на увазі про закриття? Фабрика - це лише функція, яка повертає об’єкт. Ви повинні використовувати закриття, лише якщо ваш повернутий об'єкт вимагає "приватного" стану. Ви все одно повинні зробити те ж саме, якщо б ви використовували конструктор (послугу). Але я вважаю, що ви думаєте про прототип - хоча ви все-таки могли б це зробити на заводі, якщо хочете.
Дан Кінг

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 } }); } Хоча як MyFactory, так і MyService використовують прототип, MyFactory все ще приймає результативність, щоб побудувати об'єкт, який повертається. В обох прикладах у них є приватні особи, але в MyService порівняно немає різниці в продуктивності.
Якоб

1
Для мене різниця полягає в тому, чи хочу я використовувати фабрику безпосередньо без методу: MyFactory(someArgument)(ex $http()). Це не можливо з послугою , як ви б посилається конструктор: MyService(someArgument).
jacob

На час побудови об'єкта я не дуже розумію, наскільки factory = {} вражає продуктивність, більше ніж JavaScript ініціалізує "це" для вас, коли він викликає ваш конструктор? І я думаю, що більший удар по продуктивності припадає на кутову сторону, коли він заводить ваш конструктор на заводі, а потім повинен стрибати через обручі, щоб імітувати "нове", щоб він міг ввести ваші залежності.
Дан Кінг
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.