AngularJS: Когда использовать сервис вместо фабрики


296

Пожалуйста, потерпите меня здесь. Я знаю, что есть и другие ответы, такие как: AngularJS: Сервис против провайдера против фабрики

Однако я все еще не могу понять, когда вы будете использовать сервис на заводе.

Из того, что я могу сказать, фабрика обычно используется для создания «общих» функций, которые могут вызываться несколькими контроллерами: Создание общих функций контроллера

Angular docs, кажется, предпочитает фабрику, а не сервис. Они даже ссылаются на «сервис», когда используют фабрику, что еще более запутанно! http://docs.angularjs.org/guide/dev_guide.services.creating_services

Так когда же можно будет воспользоваться услугой?

Есть ли что-то, что только возможно или намного проще сделать с помощью сервиса?

Есть что-нибудь другое, что происходит за кулисами? Различия производительности / памяти?

Вот пример. Кроме метода объявления, они кажутся идентичными, и я не могу понять, почему я сделал бы одно против другого. http://jsfiddle.net/uEpkE/

Обновление: из ответа Томаса, похоже, подразумевается, что сервис предназначен для более простой логики и фабрики для более сложной логики с закрытыми методами, поэтому я обновил приведенный ниже код скрипты, и кажется, что оба способны поддерживать частные функции?

myApp.factory('fooFactory', function() {
    var fooVar;
    var addHi = function(foo){ fooVar = 'Hi '+foo; }

    return {
        setFoobar: function(foo){
            addHi(foo);
        },
        getFoobar:function(){
            return fooVar;
        }
    };
});
myApp.service('fooService', function() {
    var fooVar;
    var addHi = function(foo){ fooVar = 'Hi '+foo;}

    this.setFoobar = function(foo){
        addHi(foo);
    }
    this.getFoobar = function(){
        return fooVar;
    }
});

function MyCtrl($scope, fooService, fooFactory) {
    fooFactory.setFoobar("fooFactory");
    fooService.setFoobar("fooService");
    //foobars = "Hi fooFactory, Hi fooService"
    $scope.foobars = [
        fooFactory.getFoobar(),
        fooService.getFoobar()
    ];
}

Конечно, сервис поддерживает private, но если вы правильно прочитаете мой пост, это чисто кодовый стиль: мы также можем воспользоваться новой лексической областью для симуляции «приватных» переменных. Это "SIMULATE"
Томас Понс

Я считаю это обсуждение очень полезным stackoverflow.com/questions/15666048/…
Ананд Гупта

Ответы:


280

объяснение

Здесь есть разные вещи:

Первый:

  • Если вы используете сервис, вы получите экземпляр функции (" this" ключевое слово).
  • Если вы используете фабрику, вы получите возвращаемое значение, вызвав ссылку на функцию (оператор возврата в фабрике).

ref: angular.service против angular.factory

Во-вторых:

Имейте в виду, что все провайдеры в AngularJS (стоимость, константа, услуги, фабрики) являются одиночками!

Третий:

Использование одного или другого (сервис или фабрика) о стиле кода. Но в AngularJS распространенным способом является использование фабрики .

Зачем ?

Так как «фабричный метод является наиболее распространенным способом получения объектов в систему внедрения зависимостей AngularJS. Он очень гибкий и может содержать сложную логику создания. Поскольку фабрики являются регулярными функциями, мы также можем воспользоваться новой лексической областью для моделирования» частного "Переменные. Это очень полезно, так как мы можем скрыть детали реализации данного сервиса."

( ссылка : http://www.amazon.com/Mastering-Web-Application-Development-AngularJS/dp/1782161821 ).


использование

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

Фабрика: Может быть полезна для возврата функции класса, которая затем может быть новой для создания экземпляров.

Итак, используйте фабрику, когда у вас есть сложная логика в вашем сервисе, и вы не хотите раскрывать эту сложность .

В других случаях, если вы хотите вернуть экземпляр службы, просто используйте службу .

Но я думаю, что со временем вы увидите, что будете использовать фабрику в 80% случаев.

Для более подробной информации: http://blog.manishchhabra.com/2013/09/angularjs-service-vs-factory-with-example/


ОБНОВИТЬ :

Отличный пост здесь: http://iffycan.blogspot.com.ar/2013/05/angular-service-or-factory.html

«Если вы хотите, чтобы ваша функция вызывалась как обычная функция , используйте фабрику . Если вы хотите, чтобы ваша функция создавалась с помощью нового оператора, используйте сервис. Если вы не знаете разницу, используйте фабрику».


ОБНОВИТЬ :

Команда AngularJS выполняет свою работу и дает объяснения: http://docs.angularjs.org/guide/providers

И с этой страницы:

«Фабрика и Сервис - наиболее часто используемые рецепты. Единственное отличие между ними состоит в том, что Сервисный рецепт работает лучше для объектов пользовательского типа, тогда как Фабрика может создавать примитивы и функции JavaScript».


7
Re First: Я читаю это везде, но я не понимаю практических последствий этого. Я думаю, из вашего ответа нет практической разницы "по большей части"? Спасибо за книгу ref хотя!
user1941747 22.09.13

Это просто, если ваш сервис действительно сложный и вам нужны частные методы и объекты, использующие фабрику
Томас Понс

1
Я заметил, что вы добавили «Если вы хотите вернуть экземпляр службы, просто используйте службу». Мой следующий вопрос: КОГДА бы вы хотели вернуть экземпляр службы? Я пытаюсь найти конкретный вариант использования здесь.
user1941747 22.09.13

12
«Поскольку фабрики являются регулярными функциями, мы также можем воспользоваться новой лексической областью для моделирования« частных »переменных». - это не относится только к фабрикам, вы можете сделать то же самое с услугами ..
pootzko

Кажется, команда Google предпочитает сервис по сравнению с заводом, это делает вещи еще более запутанными! google-styleguide.googlecode.com/svn/trunk/…
xzhang

111

allernhwkim первоначально отправил ответ на этот вопрос , связывающую в своем блоге , однако модератор удалил его. Это единственный пост, который я нашел, который не только говорит вам, как сделать то же самое с сервисом, провайдером и фабрикой, но также рассказывает, что вы можете сделать с провайдером, чего не можете с фабрикой, завод, который вы не можете с обслуживанием.

Прямо из его блога:

app.service('CarService', function() {
   this.dealer="Bad";
    this.numCylinder = 4;
});

app.factory('CarFactory', function() {
    return function(numCylinder) {
      this.dealer="Bad";
        this.numCylinder = numCylinder
    };
});

app.provider('CarProvider', function() {
    this.dealerName = 'Bad';
    this.$get = function() {
        return function(numCylinder) {
            this.numCylinder = numCylinder;
            this.dealer = this.dealerName;
        }
    };
    this.setDealerName = function(str) {
      this.dealerName = str;
    }      
});

Это показывает, как CarService всегда будет производить автомобиль с 4 цилиндрами, вы не можете изменить его для отдельных автомобилей. Принимая во внимание, что CarFactory возвращает функцию, которую вы можете сделать new CarFactoryв своем контроллере, передавая количество цилиндров, характерных для этого автомобиля. Вы не можете сделать это, new CarServiceпотому что CarService - это объект, а не функция.

Фабрики причины не работают так:

app.factory('CarFactory', function(numCylinder) {
      this.dealer="Bad";
      this.numCylinder = numCylinder
});

И автоматически возвращать функцию, которую вы хотите создать, потому что тогда вы не можете сделать это (добавить вещи в прототип / etc):

app.factory('CarFactory', function() {
    function Car(numCylinder) {
        this.dealer="Bad";
        this.numCylinder = numCylinder
    };
    Car.prototype.breakCylinder = function() {
        this.numCylinder -= 1;
    };
    return Car;
});

Посмотрите, как это буквально завод по производству автомобилей.

Вывод из его блога довольно хорош:

В заключение,

---------------------------------------------------  
| Provider| Singleton| Instantiable | Configurable|
---------------------------------------------------  
| Factory | Yes      | Yes          | No          |
---------------------------------------------------  
| Service | Yes      | No           | No          |
---------------------------------------------------  
| Provider| Yes      | Yes          | Yes         |       
---------------------------------------------------  
  1. Используйте Service, когда вам нужен простой объект, такой как Hash, например, {foo; 1, bar: 2} Код легко написать, но вы не можете создать его экземпляр.

  2. Используйте Factory, когда вам нужно создать экземпляр объекта, то есть new Customer (), new Comment () и т. Д.

  3. Используйте провайдера, когда вам нужно его настроить. т.е. тестовый URL, QA URL, производственный URL.

Если вы обнаружите, что вы просто возвращаете объект на фабрику, вам, вероятно, следует использовать сервис.

Не делай этого:

app.factory('CarFactory', function() {
    return {
        numCylinder: 4
    };
});

Используйте сервис вместо:

app.service('CarService', function() {
    this.numCylinder = 4;
});

11
это очень полезно для меня. +1 для сравнительной таблицы
Ву Ань

5
если вы определяете сервисную функцию с одним параметром numCylinder, тогда она будет иметь ту же гибкость, что и фабричный метод
Ovi

иди и прочитай блог, и трать свое время на попытки разобраться в угловатости. Если после прочтения этого поста ты узнаешь javascript, то поймешь разницу между ними.
ncubica

4
Очень удивлен ! Вы имеете в виду блог здесь, и оба говорят совершенно противоположное. Вы говорите: Фабрика - Неизвестный - Да Блог говорит: Фабрика - Неизвестный - Нет
Девеш М

1
Я согласен с @Devesh. Я думаю, что вы перепутали экземпляры. Из сообщения в блоге: «Только с фабрикой вы не можете достичь этого, потому что фабрика не может быть создана»
Мэтт

20

Концепция всех этих провайдеров намного проще, чем кажется на первый взгляд. Если вы рассекаете поставщика и вынимаете различные части, это становится очень ясным.

Проще говоря каждый из этих провайдеров является специализированной версией другого, в следующем порядке: provider> factory> value/ constant/service .

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

Это изображение иллюстрирует то, что я имею в виду, на этом изображении вы увидите код для провайдера, с выделенными частями, показывающими, какие части провайдера могут быть использованы для создания фабрики, стоимости и т. Д.

Поставщики AngularJS, фабрики, сервисы и т. Д. - это одно и то же
(источник: simplygoodcode.com )

Для получения более подробной информации и примеров из поста в блоге, где я получил изображение, перейдите по ссылке : http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/


8

И фабрика, и сервис приводят к созданию одноэлементных объектов, которые могут настраиваться поставщиками и вводиться в контроллеры и блоки выполнения. С точки зрения инженера, нет абсолютно никакой разницы, поступил ли объект с фабрики или из службы.

Итак, когда использовать фабрику, а когда использовать сервис? Это сводится к вашему предпочтению кодирования, и ничего больше. Если вам нравится модульный шаблон JS, то идите на завод. Если вам нравится стиль функции конструктора ("class"), тогда переходите к сервису. Обратите внимание, что оба стиля поддерживают частные члены.

Преимущество службы может заключаться в том, что она более интуитивно понятна с точки зрения ООП: создайте «класс» и, совместно с поставщиком, повторно используйте один и тот же код в разных модулях и изменяйте поведение созданных объектов, просто предоставляя различные параметры для конструктора в блоке конфигурации.


Не могли бы вы привести пример того, что вы подразумеваете под предоставлением различных параметров конструктору в блоке конфигурации? Как вы предоставляете параметры, если это просто сервис или фабрика. Что вы подразумеваете под «совместно с провайдером»? Возможность его настройки заставляет меня думать, что многие мои объекты должны быть провайдерами или фабриками или службами.
Timbrown

2

Фабрика не может ничего сделать или сделать лучше по сравнению с Сервисом. И наоборот. Фабрика просто кажется более популярной. Причиной этого является удобство работы с частными / публичными членами. Сервис будет более неуклюжим в этом отношении. При кодировании Сервиса вы стремитесь сделать ваши члены объекта публичными с помощью ключевого слова «this» и можете внезапно обнаружить, что эти открытые члены не видны частным методам (то есть внутренним функциям).

var Service = function(){

  //public
  this.age = 13;

  //private
  function getAge(){

    return this.age; //private does not see public

  }

  console.log("age: " + getAge());

};

var s = new Service(); //prints 'age: undefined'

Angular использует ключевое слово «new» для создания службы для вас, поэтому экземпляр Angular, передаваемый в контроллер, будет иметь тот же недостаток. Конечно, вы можете преодолеть проблему, используя это / что:

var Service = function(){

  var that = this;

  //public
  this.age = 13;

  //private
  function getAge(){

    return that.age;

  }

  console.log("age: " + getAge());

};

var s = new Service();// prints 'age: 13'  

Но с большой константой Service это может сделать код плохо читаемым. Более того, прототипы Сервиса не будут видеть частных участников - им будут доступны только публичные:

var Service = function(){

  var name = "George";

};

Service.prototype.getName = function(){

  return this.name; //will not see a private member

};

var s = new Service();
console.log("name: " + s.getName());//prints 'name: undefined'

Подводя итог, использование Factory более удобно. Так как у Factory нет этих недостатков. Я бы порекомендовал использовать его по умолчанию.


Этот ответ имеет несколько проблем. Во-первых, этот пост демонстрирует концепцию лексического анализа в Javascript, а не то, как работают сервисы AngularJS. Во-вторых, контекст вызова myapp.service(...)полностью отсутствует. Где new Service()предполагается вызывать, в сервисной функции или в месте, где сервис вводится. Третий листинг просто невозможен в контексте myapp.service ('Service', function() {...}).
lanoxx

2

Даже когда они говорят, что все сервисы и фабрики одноразовые, я не согласен на 100% с этим. Я бы сказал, что фабрики - это не одиночки, и в этом смысл моего ответа. Я бы действительно подумал об имени, которое определяет каждый компонент (Service / Factory), я имею в виду:

завод , потому что это не синглтон, вы можете создать столько , сколько вы хотите , когда вы придете, так что он работает как фабрика объектов. Вы можете создать фабрику сущности вашего домена и более комфортно работать с этими объектами, которые могут быть как объекты вашей модели. Когда вы извлекаете несколько объектов, вы можете отобразить их в этих объектах, и он может действовать как еще один слой между DDBB и моделью AngularJs. Вы можете добавлять методы к объектам, чтобы ориентировать их на объекты немного больше, чем в приложении AngularJs.

Между тем сервис является одноэлементной, поэтому мы можем создать только 1 вид, может быть, не создавать, но у нас есть только 1 экземпляр, когда мы внедряем в контроллер, поэтому сервис больше похож на обычный сервис (вызовы покой, функциональность ..) к контролерам.

Концептуально вы можете думать, как сервисы предоставляют сервис, фабрики могут создавать несколько экземпляров (объектов) класса


0

Сервисы

Синтаксис : module.service ('имя_службы', функция); Результат : при объявлении serviceName в качестве вводимого аргумента вам будет предоставлена ​​фактическая ссылка на функцию, переданную в module.service.

Использование : Может быть полезно для совместного использования служебных функций, которые полезно вызывать, просто добавляя () к введенной ссылке на функцию. Также может быть запущен с injectedArg.call (this) или аналогичным.

Заводы

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

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

Использование : Может быть полезно для возврата функции 'class', которая затем может быть добавлена ​​new для создания экземпляров.

Провайдеры

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

Результат : при объявлении providerName в качестве вводимого аргумента вам будет предоставлено значение, возвращаемое путем вызова метода $ get ссылки на функцию, переданной в module.provider.

Использование : Может быть полезно для возврата функции «класс», которая затем может быть новой для создания экземпляров, но для ее внедрения требуется некоторая конфигурация. Возможно, полезно для классов, которые можно использовать в разных проектах? Все еще немного смутно на этом.


0

Можно использовать как способа, как вы хотите : создать объект или просто для доступа к функциям из обоих


Вы можете создать новый объект из сервиса

app.service('carservice', function() {
    this.model = function(){
        this.name = Math.random(22222);
        this.price = 1000;
        this.colour = 'green';
        this.manufacturer = 'bmw';
    }
});

.controller('carcontroller', function ($scope,carservice) { 
    $scope = new carservice.model();
})

Примечание :

  • Сервис по умолчанию возвращает объект, а не функцию конструктора.
  • Вот почему для функции конструктора установлено свойство this.model.
  • Благодаря этому сервис вернет объект, но внутри этого объекта будет функция конструктора, которая будет использоваться для создания нового объекта;

Вы можете создать новый объект с завода

app.factory('carfactory', function() {
    var model = function(){
        this.name = Math.random(22222);
        this.price = 1000;
        this.colour = 'green';
        this.manufacturer = 'bmw';
    }
    return model;
});

.controller('carcontroller', function ($scope,carfactory) { 
    $scope = new carfactory();
})

Примечание :

  • Фабрика по умолчанию возвращает функцию конструктора, а не объект.
  • Вот почему новый объект может быть создан с помощью функции конструктора.

Создать сервис для простого доступа к простым функциям

app.service('carservice', function () {
   this.createCar = function () {
       console.log('createCar');
   };
   this.deleteCar = function () {
       console.log('deleteCar');
   };
});

.controller('MyService', function ($scope,carservice) { 
    carservice.createCar()
})

Создать фабрику для простого доступа к простым функциям

app.factory('carfactory', function () {
    var obj = {} 
        obj.createCar = function () {
            console.log('createCar');
        };
       obj.deleteCar = function () {
       console.log('deleteCar');
    };
});

.controller('MyService', function ($scope,carfactory) { 
    carfactory.createCar()
})

Вывод :

  • Вы можете использовать как вы хотите , чтобы создать новый объект или просто для доступа к простым функциям
  • Там не будет никакого снижения производительности, используя один над другим
  • Оба являются одноэлементными объектами, и для каждого приложения создается только один экземпляр.
  • Будучи только одним экземпляром каждый раз, когда передается их ссылка.
  • В угловой документации фабрика называется сервисом, а сервис - сервисом .

0

Фабрика и Сервис - наиболее часто используемый метод. Единственное различие между ними заключается в том, что метод Service лучше работает для объектов, которым требуется иерархия наследования, тогда как Factory может создавать примитивы и функции JavaScript.

Функция Provider является основным методом, а все остальные являются просто синтаксическим сахаром. Это необходимо только в том случае, если вы создаете многократно используемый фрагмент кода, который требует глобальной настройки.

Существует пять способов создания сервисов: Value, Factory, Service, Provider и Constant. Вы можете узнать больше об этом здесь угловом сервисе , эта статья объясняет все эти методы на практических демонстрационных примерах.

,

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.