Плутати про Сервіс проти Фабрику


618

Як я розумію, коли всередині фабрики я повертаю об'єкт, який потрапляє в контролер. У службі я маю справу з об'єктом, використовуючи thisі нічого не повертаючи.

Я був припущений, що служба завжди є однотонною і що новий заводський об'єкт вводиться в кожен контролер. Однак, як виявляється, заводський об’єкт теж сингтон?

Приклад коду для демонстрації:

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

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

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

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

При зміні user.firstв ACtrlній виходить, що user.firstв BCtrlтакож змінюється, наприклад , Userодноелементна?

Моє припущення було, що новий екземпляр був введений в контролер на заводі?


4
Поруч з "module.service" та "module.factory" є ще два способи створення послуг у AngularJS. Для отримання додаткової інформації перегляньте повідомлення в блозі: " Як створити (одиночні) послуги AngularJS 4 різними способами "
Еміль ван Гален

Можливий дублікат angular.service vs angular.factory
Kaushal28

Відповіді:


600

Всі кутові послуги є одинаковими :

Документи (див. Служби як одиночні кнопки ): https://docs.angularjs.org/guide/services

Нарешті, важливо усвідомити, що всі послуги Angular - це додаткові одинаки. Це означає, що на інжектор є лише один екземпляр даної послуги.

В основному різниця між сервісом і заводом полягає в наступному:

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

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

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

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

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

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

Ознайомтеся з цією презентацією про $ provide: http://slides.wesalvaro.com/20121113/#/

Ці слайди були використані в одному з зустрічей AngularJs: http://blog.angularjs.org/2012/11/more-angularjs-meetup-videos.html


13
Дивіться також stackoverflow.com/questions/15666048/…, де обговорюються відмінності між сервісом, заводом та послугами.
Марк Райкок

31
Офіційний doc опосередковано [sic! not enought clear] означає, що навіть якщо ви визначаєте сервіс із заводу, його створюють лише один раз. Іншими словами, його НЕ створюють знову за посиланням (точкою введення) - як би ви його не називали. Обидва способи призводять до одиничного екземпляра на інжектор.
honzajde

3
Ви кажете, що "сервіс - це лише конструкторська функція, яку називатимуть" новою "", але я думаю, що це вводить в оману. Я не думаю, що його називають новим за кадром, я думаю, що розробник несе відповідальність за те, щоб зателефонувати newна нього.
Тім Кіндберг

5
@nfiniteloop, перевірте вихідний код біля рядка 3574. Фабрики - це метод отримання $ провайдера, а служби генерують фабрики за допомогою методу, який викликає $ injector.instantiate за наданою функцією, яка потім викликає нову. ( Див Docs )
citizenslave

14
У мене було враження, що послуга настільки синглтон, яку ви використовували, отримуючи посилання на неї. І що фабрика була одинокою, яка щоразу повертала новий об’єкт. Тобто сервіс дав би вам одну «машину» і все, що у вашому проекті, використовувало б цю машину. Хоча фабрика даватиме вам новий автомобіль кожного разу, коли ви звертаєтесь до фабрики. Один був синглтон, який повернув синглтон, а один - сингтон, який повернув об'єкт. Хтось може пояснити? Викликати все, що є одним, не допомагає, оскільки воно може стосуватися кількох речей.
користувач2483724

380

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

Скажіть, у нас є:

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

Різниця між трьома полягає в тому, що:

  1. aЗбережене значення походить від запуску fn, іншими словами:fn()
  2. bЗбережене значення походить від newing fn, іншими словами:new fn()
  3. cЗбережене значення походить від спочатку отримання екземпляра newing fn, а потім запуску $getметоду цього примірника

значить, усередині кута є щось на зразок об’єкта кешу, значення кожного введення якого призначається лише один раз, коли вони були введені вперше, і де:

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

Ось чому ми використовуємо thisв сервісах і визначаємо this.$getпровайдери.

Сподіваюсь, це допомагає.


54
нарешті, здорове пояснення. Кутовий божевільний і настільки поганий, що болить.
osiris

8
Це має бути прийнятою відповіддю, оскільки вона насправді відповідає на питання ЧОМУ фабрики, послуги та постачальники повертають однотонні значення. Інші відповіді пояснюють різницю між фабриками, службами та постачальниками, але ніколи не торкаються однотонного аспекту.
wmock

3
Мені це подобається ... Коли я читаю тисячі рядків речення від іншого блогера .. мені лише вдається зрозуміти фабрику. Але я читаю це ... я розумію всі 3.
tоhtan

@osiris Я згоден. Мені це не подобається. Він просто відчуває себе настільки сильно спареним, що змушує мої зуби.
Томас

2
значить, ви повинні забезпечити реалізацію $ get при використанні провайдерів?
Віктор

95

живий приклад

приклад "привіт світ"

з factory/ service/ provider:

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

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

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

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

    this.name = 'Default';

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

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

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


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

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

57

Існує також спосіб повернення функції конструктори , так що ви можете повернутися newable класів на заводах, як це:

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

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

Отже, ви можете зробити це в контролері, який використовує MyObjectWithParam:

var obj = new MyObjectWithParam("hello"),

Дивіться тут повний приклад:
http://plnkr.co/edit/GKnhIN?p=preview

І ось сторінки групи Google, де це обговорювалося:
https://groups.google.com/forum/#!msg/angular/56sdORWEoqg/b8hdPskxZXsJ


У мене виникають проблеми з мінімізацією на вашому прикладі. Чи знаєте ви, як я повинен це помітити?
Pål

2
Так, існує мінімізоване позначення для кутового. Це має бути приблизно так: App.factory('MyObjectWithParam', ['$injector', function ($injector) { return function(name) { return $injector.instantiate(MyObjectWithParam,{ name: name }); }; }]); Детальніше про це читайте тут: docs.angularjs.org/tutorial/step_05
JustGoscha

4
чому б ви хотіли це зробити, якщо ви можете використовувати .serviceзамість цього?
Flup

у мене була така ж думка @flup. @justgoscha, чи є якась користь ( сприймається? ) від використання .factoryна відміну від .service?
xandercoded

5
Я думаю, тому що послуга - це одинока . Що я тут сконструював - це в основному клас, який є новим. Таким чином , ви можете мати що - щось на зразок автосервісу заводу , а потім зробити new Car('BMW')і new Car('Ford')вони не поділяють одні й ті ж змінні і все.
JustGoscha

51

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

Послуги

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

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

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

Заводи

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

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

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

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

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


6
Це має для мене сенс. Фабрика повертає план створення нових об'єктів.

27

Додаючи до першої відповіді, я думаю .service () призначений для людей, які написали свій код у більш об'єктно-орієнтованому стилі (C # / Java) (використовуючи це ключове слово та об'єкт інстанції за допомогою прототипу / функції конструктора).

Фабрика призначена для розробників, які пишуть код, більш природний для JavaScript / функціональний стиль кодування.

Погляньте на вихідний код методу .service та .factory всередині angular.js - внутрішньо всі вони викликають метод постачальника:

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

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

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

25

Дуже просто:

.service - зареєстрована функція буде викликана як конструктор (він же "новий")

.factory - зареєстрована функція буде викликана як проста функція

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


6
так. давайте не будемо робити речі складнішими, ніж вони є насправді
промальовуйте

20

Всі провайдери працюють однаково. Різні методи service, factory, providerпросто дозволяють зробити те ж саме в менше коду.

PS Там також valueі constant.

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

Ось малюнок, який показує, що я маю на увазі:

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

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

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


Кажуть, що послуги є однотонними, але як це сінглтон, якщо кожен раз створюється новий екземпляр?
Ankur Marwaha

1
@AnkurMarwaha Новий екземпляр не створюється кожен раз, він створюється лише один раз і кешується AngularJS. Це вірно, незалежно від того, чи використовуєте ви постачальника, фабрику, послугу тощо. Це можна підтвердити, використовуючи console.log()та вводивши в декілька контролерів.
Луїс Перес

Луїс, Ваш коментар суперечить прийнятій відповіді, як сказано. - Нарешті, важливо усвідомити, що всі послуги Angular - це додаткові одинаки. Це означає, що на інжектор є лише один екземпляр даної послуги.
Ankur Marwaha

@AnkurMarwaha, можливо, я щось нерозумію. Ви цитували "важливо усвідомити, що всі сервіси Angular - це додаткові одинаки" - той факт, що вони є однотонними, означає, що вони створені лише один раз. Що я сказав: "Новий екземпляр створюється не кожен раз, він створюється лише один раз і кешується ...". Чи можете ви детальніше вказати, де ви бачите конфлікт?
Луїс Перес

1
Ах, я бачу плутанину. "Інжектор" - це об'єкт кутовий. Це відповідає за те, щоб зробити "ін'єкцію". Наприклад, коли контролер вперше запущений, "інжектор" розглядає параметри і вводить кожен з них. Існує лише один «інжектор» для всього вашого додатка. Після того як інжектор створює певну фабрику або службу, він зберігає примірник і повторно використовує її - отже, синглтон. Таким чином, існує лише один інжектор на додаток і лише один екземпляр даної послуги на одного інжектора. Більшість кутових додатків мають лише одне додаток, тому один інжектор, тому один екземпляр будь-якої служби, контролера тощо
Луїс Перес,

13

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

Основні приклади

Поверніть об’єкт класу, який має єдиний метод

Ось послуга, яка має єдиний метод:

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

Ось фабрика, яка повертає об'єкт методом:

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

Повернути значення

Фабрика, яка повертає список номерів:

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

console.log(NumberListFactory);

Послуга, яка повертає список номерів:

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

console.log(NumberLister.numbers);

Вихід в обох випадках однаковий, список чисел.

Розширені приклади

Змінні "класу" з використанням заводів

У цьому прикладі ми визначаємо CounterFactory, він збільшує чи зменшує лічильник, і ви можете отримати поточний підрахунок або отримати кількість об'єктів CounterFactory:

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

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

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

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

})

Ми використовуємо CounterFactoryдля створення декількох лічильників. Ми можемо отримати доступ до змінної класу, щоб побачити, скільки створено лічильників:

var people_counter;
var places_counter;

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

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

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

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

Вихід цього коду:

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

це корисний приклад, число_of_counter_factories - це як мета-атрибут класу CounterFactory, так? Я розумію, що цей приклад можна повторити на сервісі (скажіть, якщо я помиляюся), яка би була смислова різниця в цьому випадку?
geoom

Корисний приклад! Таким чином, це в основному означає, що на заводі ви можете мати додатковий шар абстракції, який не міг би отримати службу. Що б не повернуто, новий екземпляр його буде повертатися, коли використовується новий. Будь-які змінні, які не задекларовані всередині блоку повернення, будуть одинаковими. Я правильно зрозумів?
Swanidhi

@Swanidhi в основному так, ви можете оголосити змінні, які є однофактурними фабриками. Тому я назвав їх змінними "класу".

13

"Фабрика" та "Сервіс" - це різні способи виконання DI (впорскування) у кутовий.

Отже, коли ми визначаємо DI за допомогою "service", як показано в коді нижче. Це створює новий екземпляр GLOBAL об’єкта “Logger” та вводить його у функцію.

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

Коли ви визначаєте DI за допомогою "фабрики", він не створює екземпляр. Він просто передає метод і пізніше споживач внутрішньо повинен зателефонувати на фабрику для об'єктних екземплярів.

app.factory("Customerfactory", CreateCustomer);

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

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

Фабрику слід використовувати, коли ми хочемо створити різні типи об'єктів залежно від сценаріїв. Наприклад, залежно від сценарію, ми хочемо створити простий об’єкт «Клієнт» або «Замовник» з об’єктом «Адреса» або «Клієнт» з об’єктом «Телефон». Ось детальне пояснення цього пункту

Служба повинна використовуватися, коли у нас є утиліта або спільні функції, які потрібно вводити, як утиліта, реєстратор, обробник помилок тощо


Кожна відповідь, яку я бачив на це питання та подібні інші, вказує на різницю в механіці та синтаксисі. Ця відповідь дає справжню причину, чому ви обрали б один за іншим. Це питання семантики, і, переглядаючи найменування, службу чи фабрику, повідомляє їх призначення та спосіб їх використання.
Джо Мейо

8

Стиль сервісу : ( мабуть, найпростіший ) повертає фактичну функцію: Корисно для обміну корисними функціями, корисними для виклику, просто додавши () до введеної посилання функції.

Послуга в AngularJS - це однотонний JavaScript-об’єкт, який містить набір функцій

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

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

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

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

    myService.doIt();

});

Фабричний стиль: ( більш задіяний, але більш досконалий ) повертає повернене значення функції: інстанціювати такий об'єкт, як новий Object () у Java.

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

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

myModule.value("numberValue", 999);

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

    console.log(myFactory);

});

Стиль провайдера : ( повномасштабна, конфігурувана версія ) повертає висновок функції $ get функції: Налаштовується.

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

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

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

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

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

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

        return service;
    }

    return provider;
});

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

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

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

});

src jenkov

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

jsbin

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

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

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

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

    this.name = 'Default';

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

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

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

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

</body>
</html>

jsfiddle


2

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

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

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


2

Ось як я зрозумів різницю між ними з точки зору дизайну:

Служба : Поверніть тип, який буде створений для створення об'єкта цього типу. Якщо використовується аналогія Java, сервіс повертає визначення класу Java .

Фабрика : Повертає конкретний предмет, який можна негайно використати. У Java Analogy завод повертає об'єкт Java .

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


1

Це було б найкращою та короткою відповіддю для розуміння постачальника послуг Vs Factory Vs

Джерело : https://groups.google.com/forum/#!msg/angular/56sdORWEoqg/HuZsOsMvKv4J

Ось що говорить Бен із демонстрацією http://jsbin.com/ohamub/1/edit?html,output

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

Послуги

Синтаксис : module.service ('serviceName', функція);

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

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

Заводи

Синтаксис : module.factory ('factoryName', функція);

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

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

Постачальники

Синтаксис : module.provider ('providerName', функція);

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

Використання : Може бути корисним для повернення функції "class", яка потім може бути new'ed для створення примірників, але для введення потрібна певна конфігурація. Можливо, корисно для занять, які можна використовувати повторно в проектах? На цьому все-таки каламутніший ". Бен


1

Я мав деяку плутанину на деякий час, і я намагаюся тут дати просте пояснення. Сподіваюся, це допоможе!

angular .factoryі angular .serviceобидва використовуються для ініціалізації послуги та роботи однаковим чином.

Різниця полягає лише в тому, як ви хочете ініціалізувати свою послугу.

Обидва - одиночні


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


Заводська

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

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

напр

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

app.factory('myService', myService);

Під час введення цієї послуги (наприклад, у ваш контролер):

  • Кутовий буде називати вашу дану функцію (як myService()) , щоб повернути об'єкт
  • Singleton - викликається лише один раз, зберігається і передається один і той же об'єкт.


Сервіс

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

Якщо ви хочете ініціалізувати свою послугу з функції конструктора (за допомогою thisключового слова), вам потрібно скористатися цим serviceметодом.

напр

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

app.service('myService', myService);

Під час введення цієї послуги (наприклад, у ваш контролер):

  • Кутовий зробить newвашу задану функцію (як new myService()) для повернення об'єкта
  • Singleton - викликається лише один раз, зберігається і передається один і той же об'єкт.


ПРИМІТКА. Якщо ви користуєтесь factoryз <constructor function>або serviceразом із ним <function with a return value>, це не працюватиме.


Приклади - DEMO


1

Саме це допомогло мені зрозуміти різницю завдяки публікації в блозі Паскаля Прехта.

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

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

Ось кутовий код 1,5, який я знайшов для фабрики:

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

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

Кутовий фрагмент вихідного коду для функції factory ():

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

Він приймає ім'я та фабричну функцію, яка передається, і повертає постачальника з тим же ім'ям, який має метод $ get, який є нашою заводською функцією. Щоразу, коли ви запитуєте інжектор про конкретну залежність, він, як правило, запитує у відповідного постачальника примірник цієї послуги, зателефонувавши методу $ get (). Ось чому під час створення провайдерів потрібно $ get ().

Ось кутовий код 1,5 для обслуговування.

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

Виявляється, коли ми викликаємо службу (), вона насправді викликає factory ()! Однак це не просто передає функцію нашого конструктора сервісу на завод, як є. Він також передає функцію, яка просить інжектор створити об'єкт даним конструктором.

Іншими словами, якщо ми вводимо MyService кудись, що в коді відбувається:

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

Щоб відновити його ще раз, служба викликає фабрику, що є методом $ get () відповідного постачальника. Більше того, $ injector.instantiate () - це метод, який в кінцевому підсумку викликає Object.create () з функцією конструктора. Ось чому ми використовуємо "це" в сервісах.

Для ES5 не має значення, який ми використовуємо: service () або factory (), це завжди називається фабрика, яка створює постачальника нашої послуги.

Ви можете зробити те саме, що і з сервісами. Сервіс - це конструкторська функція, однак це не заважає нам повернути об'єктні літерали. Таким чином, ми можемо взяти наш сервісний код і записати його таким чином, що він в основному робить те саме, що і наш завод, або іншими словами, ви можете написати службу як завод, щоб повернути об’єкт.

Чому більшість людей рекомендують використовувати фабрики через послуги? Це найкраща відповідь, яку я бачив із книги книги Павла Козловського: Освоєння розробки веб-додатків з AngularJS.

Фабричний метод - найпоширеніший спосіб потрапляння об'єктів у систему впорскування залежності AngularJS. Він дуже гнучкий і може містити складну логіку створення. Оскільки фабрики є регулярними функціями, ми також можемо скористатися новою лексичною сферою для імітації "приватних" змінних. Це дуже корисно, оскільки ми можемо приховати деталі реалізації певної послуги. "


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

1

Існує три способи управління бізнес-логікою в AngularJS: ( натхненний курсом Якова Coursera AngularJS ), які є:

  1. Сервіс
  2. Заводська
  3. Постачальник

Тут ми лише поговоримо про Service vs Factory

ОБСЛУГОВУВАННЯ :

Синтаксис:

app.js

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

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

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

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

index.html

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

Основні особливості Сервісу:

  1. Ліниво миттєвий : Якщо послугу не вводити, вона не буде створена ніколи. Тому для його використання вам доведеться ввести його в модуль.

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

ЗАВОД

Тепер поговоримо про Фабрику в AngularJS

Спочатку давайте подивимось на синтаксис :

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

Тепер використовуємо вищевказані два в контролері:

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

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

Особливості заводу:

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

  2. Це створює не тільки одиночні, але й настроювані послуги.

  3. .service()Метод є завод , який завжди справляє один і той же тип сервісу, який одноелементна. Немає простого способу налаштувати його поведінку. Цей .service()метод зазвичай використовується як ярлик для чогось, що не вимагає жодної конфігурації.



0

Ви можете зрозуміти різницю за допомогою цієї аналогії. Розгляньте різницю між нормальною функцією, яка поверне деяке значення, і конструкторською функцією, яка отримає екземпляр за допомогою нового ключового слова. Отже, створення фабрики подібне до створення нормальної функції, яка поверне деяке значення (примітивне або об'єкт), тоді як створення послуги - це як створення функції конструктора (клас OO), з якої ми можемо створити екземпляр за допомогою нового ключового слова. Єдине, що слід зауважити, - це те, що коли ми використовуємо метод сервісу для створення служб, він автоматично створить його примірник за допомогою механізму введення залежності, який підтримує AngularJS

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.