Nhầm lẫn về Dịch vụ vs Nhà máy


618

Theo tôi hiểu, khi ở trong nhà máy, tôi trả lại một vật được tiêm vào bộ điều khiển. Khi bên trong một dịch vụ tôi đang xử lý đối tượng sử dụng thisvà không trả lại bất cứ thứ gì.

Tôi đã giả định rằng một dịch vụ luôn luôn là một singleton và một đối tượng nhà máy mới được đưa vào trong mọi bộ điều khiển. Tuy nhiên, hóa ra, một đối tượng nhà máy cũng là một người độc thân?

Mã ví dụ để chứng minh:

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

Khi thay đổi user.firsttrong ACtrlnó chỉ ra rằng user.firsttrong BCtrlcũng được thay đổi, ví dụ như Userlà một singleton?

Giả định của tôi là một phiên bản mới đã được đưa vào bộ điều khiển với một nhà máy?


4
Bên cạnh "module.service" và "module.factory", có thêm 2 cách để tạo dịch vụ trong AngularJS. Để biết thêm thông tin, hãy kiểm tra qua bài đăng trên blog: " Cách tạo (singleton) dịch vụ AngularJS theo 4 cách khác nhau "
Emil van Galen

Bản sao có thể có của angular.service vs angular.factory
Kaushal28

Câu trả lời:


600

Tất cả các dịch vụ góc là singletons :

Tài liệu (xem Dịch vụ dưới dạng singletons ): https://docs.angularjs.org/guide/service

Cuối cùng, điều quan trọng là phải nhận ra rằng tất cả các dịch vụ Angular là các singletons ứng dụng. Điều này có nghĩa là chỉ có một phiên bản của một dịch vụ nhất định cho mỗi người tiêm.

Về cơ bản sự khác biệt giữa dịch vụ và nhà máy như sau:

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 + "!";
    }
  }
});

Kiểm tra bản trình bày này về $ cung cấp: http://slides.wesalvaro.com/20121113/#/

Những slide này đã được sử dụng trong một trong những cuộc gặp gỡ của AngularJs: http://blog.angularjs.org/2012/11/more-angularjs-meetup-ideo.html


13
Xem thêm stackoverflow.com/questions/15666048/ , trong đó thảo luận về sự khác biệt giữa dịch vụ, nhà máy và cung cấp.
Mark Rajcok

31
Các tài liệu chính thức gián tiếp [sic! không đủ rõ ràng] ngụ ý rằng ngay cả khi bạn xác định dịch vụ với nhà máy, nó chỉ được tạo một lần. Nói cách khác, nó KHÔNG được tạo lại theo tham chiếu (điểm tiêm) - bất cứ điều gì bạn gọi nó. Cả hai cách đều dẫn đến một trường hợp đơn lẻ cho mỗi người tiêm.
honzajde

3
Bạn nói "dịch vụ chỉ là một hàm tạo sẽ được gọi bằng 'mới'" nhưng tôi nghĩ đó là sai lệch. Tôi không nghĩ nó được gọi với cái mới đằng sau hậu trường, tôi nghĩ nhà phát triển chịu trách nhiệm kêu gọi newnó.
Tim Kindberg

5
@nfiniteloop, hãy kiểm tra mã nguồn gần dòng 3574. Các nhà máy là phương thức $ get của nhà cung cấp và các dịch vụ đang tạo ra các nhà máy sử dụng phương thức gọi $ kim phun.instantiate trên hàm được cung cấp, sau đó gọi mới. ( Xem Tài liệu )
công dân

14
Tôi có ấn tượng rằng một dịch vụ là đơn lẻ mà bạn đã sử dụng bằng cách tham chiếu đến nó. Và rằng một nhà máy là một đơn vị đã trả lại một đối tượng mới mỗi lần. Đó là, một dịch vụ sẽ cung cấp cho bạn một "chiếc xe" và mọi thứ trong dự án của bạn sẽ sử dụng chiếc xe này. Trong khi một nhà máy sẽ cung cấp cho bạn một chiếc xe mới mỗi khi bạn gọi nhà máy. Một người là người độc thân đã trả lại một người độc thân và một người là người độc thân đã trả lại một đối tượng. Bất cứ ai có thể giải thích? Gọi tất cả mọi thứ một singleton không giúp đỡ vì nó có thể đề cập đến nhiều thứ.
dùng2483724

380

Đối với tôi, sự mặc khải đã đến khi tôi nhận ra rằng tất cả chúng đều hoạt động theo cùng một cách: bằng cách chạy một cái gì đó một lần , lưu trữ giá trị họ nhận được, và sau đó ho lên cùng một giá trị được lưu trữ đó khi được tham chiếu qua Dependency Injection.

Nói rằng chúng tôi có:

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

Sự khác biệt giữa ba là:

  1. aGiá trị được lưu trữ đến từ việc chạy fn, nói cách khác:fn()
  2. bGiá trị được lưu trữ đến từ new ing fn, nói cách khác:new fn()
  3. cGiá trị được lưu trữ đến từ lần đầu tiên nhận được một ví dụ bởi new ing fn, và sau đó chạy một $getphương pháp sơ thẩm

điều đó có nghĩa là, có một cái gì đó giống như một đối tượng bộ đệm trong góc, giá trị của mỗi lần tiêm chỉ được gán một lần, khi chúng được tiêm lần đầu tiên và ở đâu:

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

Đây là lý do tại sao chúng tôi sử dụng this trong các dịch vụ và xác định mộtthis.$get trong các nhà cung cấp.

Hi vọng điêu nay co ich.


54
cuối cùng, một lời giải thích lành mạnh. Angular là điên rồ và hoàn toàn xấu đến nỗi nó đau.
osiris

8
Đây phải là câu trả lời được chấp nhận vì nó thực sự trả lời câu hỏi TẠI SAO các nhà máy, dịch vụ và nhà cung cấp trả về các giá trị đơn lẻ. Các câu trả lời khác giải thích sự khác biệt giữa các nhà máy, dịch vụ và nhà cung cấp nhưng không bao giờ chạm vào khía cạnh đơn lẻ.
wmock

3
Tôi thích điều này ... Khi tôi đọc hàng ngàn dòng câu từ các blogger khác .. tôi chỉ có thể hiểu được nhà máy. Nhưng tôi đã đọc nó ... tôi hiểu tất cả 3.
tsohtan

@osiris Tôi đồng ý. Tôi không thích nó. Nó chỉ cảm thấy rất kỳ dị kết hợp chặt chẽ đến nỗi nó làm cho răng tôi nghiến lại.
Thomas

2
vì vậy bạn phải cung cấp triển khai $ get khi sử dụng nhà cung cấp?
Victor

95

ví dụ sống

ví dụ "xin chào thế giới"

với 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

Ngoài ra còn có một cách để trả về hàm xây dựng để bạn có thể trả về các lớp có thể tạo mới trong các nhà máy, như thế này:

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

Vì vậy, bạn có thể làm điều này trong một bộ điều khiển, sử dụng MyObjectWithParam:

var obj = new MyObjectWithParam("hello"),

Xem ở đây ví dụ đầy đủ:
http://plnkr.co/edit/GKnhIN?p=preview

Và tại đây, các trang nhóm google, nơi nó đã được thảo luận:
https://groups.google.com/forum/#!msg/angular/56sdORweoqg/b8hdPskxZXsJ


Tôi đang gặp vấn đề với việc thu nhỏ bằng cách sử dụng ví dụ của bạn. Bạn có biết làm thế nào tôi nên chú thích điều này?
Pål

2
Vâng, có tồn tại một ký hiệu rút gọn cho Angular. Nó phải là một cái gì đó như thế này: App.factory('MyObjectWithParam', ['$injector', function ($injector) { return function(name) { return $injector.instantiate(MyObjectWithParam,{ name: name }); }; }]); Đọc thêm về nó ở đây: docs.angularjs.org/tutorial/step_05
JustGoscha

4
Tại sao bạn muốn làm điều này, nếu bạn có thể sử dụng .servicethay thế?
flup

tôi đã có cùng suy nghĩ @flup. @justgoscha, có một số lợi ích (được giải quyết ? ) của việc sử dụng .factorytrái ngược với .service?
xandercoding

5
Tôi nghĩ bởi vì một dịch vụ là một singleton . Những gì tôi xây dựng ở đây về cơ bản là một lớp có thể làm được. Vì vậy, bạn có thể có một cái gì đó giống như một nhà máy dịch vụ xe hơi và sau đó đưa ra new Car('BMW')new Car('Ford')và họ không chia sẻ các biến tương tự và tất cả mọi thứ.
JustGoscha

51

Dưới đây là những khác biệt chính:

Dịch vụ

Cú pháp: module.service( 'serviceName', function );

Kết quả: Khi khai báo serviceName dưới dạng đối số có thể tiêm, bạn sẽ được cung cấp ví dụ của hàm được truyền chomodule.service .

Cách sử dụng: Có thể hữu ích cho việc chia sẻ các hàm tiện ích hữu ích để gọi bằng cách thêm () vào tham chiếu hàm được chèn. Cũng có thể được chạy với injectedArg.call( this )hoặc tương tự.

Các nhà máy

Cú pháp: module.factory( 'factoryName', function );

Kết quả: Khi khai báo FactoryName là một đối số có thể tiêm, bạn sẽ được cung cấp giá trị được trả về bằng cách gọi tham chiếu hàm được truyền vào module.factory.

Cách sử dụng: Có thể hữu ích cho việc trả về một 'lớp' mà sau đó có thể được tạo mới để tạo các thể hiện.

Đồng thời kiểm tra tài liệu AngularJS và câu hỏi tương tự trên stackoverflow nhầm lẫn về dịch vụ so với nhà máy .

Dưới đây là ví dụ sử dụng dịch vụ và nhà máy . Tìm hiểu thêm về dịch vụ AngularJS so với nhà máy .


6
Điều này có ý nghĩa với tôi. Nhà máy ông trả lại bản thiết kế để tạo ra các đối tượng mới.

27

Thêm vào câu trả lời đầu tiên, tôi nghĩ .service () dành cho những người đã viết mã của họ theo kiểu hướng đối tượng hơn (C # / Java) (sử dụng từ khóa này và khởi tạo đối tượng thông qua hàm nguyên mẫu / Hàm xây dựng).

Factory dành cho các nhà phát triển viết mã tự nhiên hơn cho phong cách mã hóa javascript / chức năng.

Hãy xem mã nguồn của phương thức .service và .factory bên trong angular.js - bên trong tất cả chúng đều gọi phương thức nhà cung cấp:

  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

Rất đơn giản:

.service - chức năng đã đăng ký sẽ được gọi dưới dạng hàm tạo (còn gọi là 'newed')

.factory - Hàm đã đăng ký sẽ được gọi là một hàm đơn giản

Cả hai đều được gọi một lần dẫn đến một đối tượng đơn lẻ được đưa vào các thành phần khác trong ứng dụng của bạn.


6
Đúng. chúng ta đừng làm mọi thứ phức tạp hơn thực tế
flup 6/1/2015

20

Tất cả các nhà cung cấp làm việc theo cùng một cách. Các phương pháp khác nhau service, factory,provider chỉ cho phép bạn thực hiện được điều tương tự trong mã ít hơn.

PS cũng có valueconstant .

Mỗi trường hợp đặc biệt xuống chuỗi bắt đầu bằng providervà kết thúc bằngvalue có một giới hạn được thêm vào. Vì vậy, để quyết định giữa họ, bạn phải tự hỏi mình hãy thực hiện những gì bạn muốn với ít mã hơn.

Đây là một hình ảnh cho bạn thấy những gì tôi có nghĩa là:

nhập mô tả hình ảnh ở đây

Bạn có thể phân tích và hướng dẫn tham khảo trên bài đăng blog tôi đã nhận được hình ảnh này từ:

http://www.simplygoodcode.com/2015/11/the-difference-b between-service-cung cấp-and-factory-in-angularjs /


Các dịch vụ được gọi là singleton, nhưng tại sao nó lại đơn lẻ, nếu phiên bản mới được tạo ra mỗi lần tôi tiêm?
Ankur Marwaha

1
@AnkurMarwaha Một trường hợp mới không được tạo mỗi lần, nó chỉ được tạo một lần và được lưu trữ bởi AngularJS. Điều này đúng cho dù bạn đang sử dụng nhà cung cấp, nhà máy, dịch vụ, v.v. Bạn có thể xác nhận điều này bằng cách sử dụng console.log()và tiêm vào nhiều bộ điều khiển.
Luis Perez

Luis, Nhận xét của bạn mâu thuẫn với câu trả lời được chấp nhận như đã nói - Cuối cùng, điều quan trọng là phải nhận ra rằng tất cả các dịch vụ của Angular đều là các ứng dụng đơn. Điều này có nghĩa là chỉ có một phiên bản của một dịch vụ nhất định cho mỗi người tiêm.
Ankur Marwaha

@AnkurMarwaha có lẽ tôi đang hiểu nhầm điều gì đó. Bạn đã trích dẫn "điều quan trọng là phải nhận ra rằng tất cả các dịch vụ Angular đều là các singletons ứng dụng" - thực tế rằng chúng là singletons có nghĩa là chúng chỉ được tạo một lần. Đó là những gì tôi đã nói "Một trường hợp mới không được tạo mỗi lần, nó chỉ được tạo một lần và được lưu trong bộ nhớ cache ...". Bạn có thể chỉ ra chi tiết hơn nơi bạn nhìn thấy xung đột?
Luis Perez

1
Ah, tôi thấy sự nhầm lẫn. "Người tiêm" là một đối tượng trong góc. Đó là trách nhiệm thực hiện "tiêm". Ví dụ, khi bộ điều khiển chạy lần đầu tiên, "kim phun" sẽ xem xét các tham số và tiêm từng cái. Chỉ có một "kim phun" cho toàn bộ ứng dụng của bạn. Một khi người tiêm tạo ra một nhà máy hoặc dịch vụ cụ thể, nó sẽ giữ một cá thể cho nó và sử dụng lại nó - do đó là singleton. Vì vậy, chỉ có một người tiêm cho mỗi ứng dụng và chỉ có một phiên bản của một dịch vụ nhất định cho mỗi người tiêm. Hầu hết các ứng dụng Angular chỉ có một ứng dụng, do đó, một người tiêm, do đó, một phiên bản của bất kỳ dịch vụ, bộ điều khiển nào, v.v.
Luis Perez

13

Dưới đây là một số ví dụ khác về dịch vụ so với các nhà máy có thể hữu ích khi thấy sự khác biệt giữa chúng. Về cơ bản, một dịch vụ có "mới ..." được gọi trên đó, nó đã được khởi tạo. Một nhà máy không được khởi tạo tự động.

Ví dụ cơ bản

Trả về một đối tượng lớp có một phương thức duy nhất

Đây là một dịch vụ có một phương thức duy nhất:

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

Đây là một nhà máy trả về một đối tượng với một phương thức:

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

Trả về một giá trị

Một nhà máy trả về một danh sách các số:

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

console.log(NumberListFactory);

Một dịch vụ trả về danh sách các số:

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

console.log(NumberLister.numbers);

Đầu ra trong cả hai trường hợp là như nhau, danh sách các số.

Ví dụ nâng cao

Biến "Class" sử dụng các nhà máy

Trong ví dụ này, chúng tôi xác định CounterFactory, nó tăng hoặc giảm một bộ đếm và bạn có thể lấy số lượng hiện tại hoặc nhận được bao nhiêu đối tượng CounterFactory đã được tạo:

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

})

Chúng tôi sử dụng CounterFactoryđể tạo ra nhiều quầy. Chúng ta có thể truy cập biến lớp để xem có bao nhiêu bộ đếm được tạo:

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

Đầu ra của mã này là:

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

đó là một ví dụ hữu ích, number_of_corer_factories giống như một thuộc tính meta của lớp CounterFactory, phải không?, Tôi hiểu ví dụ này có thể sao chép trên một dịch vụ (cho tôi biết nếu tôi sai), sự khác biệt về ngữ nghĩa trong trường hợp này là gì?
geoom

Ví dụ hữu ích! Vì vậy, điều này về cơ bản có nghĩa là trong một nhà máy, bạn có thể có thêm một lớp trừu tượng mà sẽ không có trong một dịch vụ. Dù trả lại bất cứ điều gì, một phiên bản mới của nó sẽ được trả lại bất cứ khi nào 'mới' được sử dụng. Bất kỳ biến nào không được khai báo bên trong khối trả về sẽ là singleton. Tôi đã làm đúng chứ?
Swanidhi

@Swanidhi về cơ bản là có, bạn có thể khai báo các biến là singletons trong nhà máy. Đó là lý do tại sao tôi gọi chúng là các biến "lớp".

13

Nhà máy ngay lập tức và nhà cung cấp dịch vụ trực tuyến là những cách khác nhau để thực hiện DI (Dependency tiêm) trong góc.

Vì vậy, khi chúng tôi xác định DI bằng cách sử dụng dịch vụ của Wap như thể hiện trong đoạn mã dưới đây. Điều này tạo ra một thể hiện GLOBAL mới của đối tượng Log Logger và đưa nó vào hàm.

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

Khi bạn xác định DI bằng cách sử dụng một nhà máy, thì nó không tạo ra một thể hiện. Nó chỉ truyền phương thức và sau đó người tiêu dùng trong nội bộ phải thực hiện các cuộc gọi đến nhà máy để lấy các đối tượng.

app.factory("Customerfactory", CreateCustomer);

Dưới đây là một hình ảnh đơn giản cho thấy trực quan quá trình DI đối với Dịch vụ của Cameron khác với Nhà máy chế biến như thế nào.

nhập mô tả hình ảnh ở đây

Nhà máy nên được sử dụng Khi chúng ta muốn tạo các loại đối tượng khác nhau tùy theo kịch bản. Ví dụ, tùy thuộc vào kịch bản, chúng tôi muốn tạo một đối tượng Khách hàng trực tuyến đơn giản, hoặc đối tượng khách hàng trực tuyến với đối tượng địa chỉ trực tuyến hoặc đối tượng khách hàng trực tuyến với đối tượng điện thoại trực tiếp. Dưới đây là một lời giải thích chi tiết của đoạn này

Dịch vụ nên được sử dụng Khi chúng ta có các chức năng chia sẻ tiện ích hoặc chia sẻ như Utility, Logger, Trình xử lý lỗi, v.v.


Mỗi câu trả lời tôi đã thấy về câu hỏi này và những câu hỏi tương tự khác đang chỉ định sự khác biệt về cơ học và cú pháp. Câu trả lời này đưa ra một lý do thực sự tại sao bạn sẽ chọn cái này hơn cái kia. Đó là vấn đề ngữ nghĩa và nhìn vào tên, dịch vụ hoặc nhà máy, truyền đạt mục đích của chúng và cách chúng được sử dụng.
Joe Mayo

8

Phong cách phục vụ : ( có lẽ là đơn giản nhất ) trả về hàm thực tế: Hữu ích cho việc chia sẻ các hàm tiện ích hữu ích để gọi bằng cách nối thêm () vào tham chiếu hàm được chèn.

Một dịch vụ trong AngularJS là một đối tượng JavaScript đơn lẻ chứa một tập hợp các hàm

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

});

Phong cách nhà máy : ( tham gia nhiều hơn nhưng tinh vi hơn ) trả về giá trị trả về của hàm: khởi tạo một đối tượng như đối tượng mới () trong java.

Nhà máy là một chức năng tạo ra các giá trị. Khi một dịch vụ, bộ điều khiển, vv cần một giá trị được đưa vào từ một nhà máy, nhà máy sẽ tạo ra giá trị theo yêu cầu. Sau khi được tạo, giá trị được sử dụng lại cho tất cả các dịch vụ, bộ điều khiển, v.v.

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

});

Kiểu nhà cung cấp : ( phiên bản đầy đủ, cấu hình ) trả về đầu ra của hàm $ get của hàm: Có thể định cấu hình.

Các nhà cung cấp trong AngularJS là hình thức nhà máy linh hoạt nhất mà bạn có thể tạo. Bạn đăng ký nhà cung cấp với một mô-đun giống như bạn làm với một dịch vụ hoặc nhà máy, ngoại trừ bạn sử dụng hàm nhà cung cấp () thay thế.

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

Sự khác biệt cơ bản, là nhà cung cấp đó cho phép đặt các giá trị hàm nguyên thủy (không phải đối tượng), mảng hoặc hàm gọi lại vào biến khai báo của nhà máy và do đó, nếu trả về một đối tượng, nó phải được khai báo và trả lại rõ ràng.

Mặt khác, một dịch vụ chỉ có thể được sử dụng để đặt biến khai báo dịch vụ thành một đối tượng, do đó chúng ta có thể tránh việc tạo và trả lại rõ ràng của các đối tượng, mặt khác, nó cho phép sử dụng từ khóa này .

Hoặc nói ngắn gọn " nhà cung cấp là một hình thức chung chung hơn trong khi dịch vụ chỉ giới hạn ở các đối tượng".


2

Đây là cách tôi hiểu sự khác biệt giữa chúng về các mẫu thiết kế:

Dịch vụ : Trả về một loại, sẽ được tạo mới để tạo một đối tượng của loại đó. Nếu tương tự Java được sử dụng, Dịch vụ trả về định nghĩa Lớp Java .

Nhà máy : Trả về một đối tượng cụ thể có thể được sử dụng ngay lập tức. Trong Java Analogy, Factory trả về một đối tượng Java .

Phần thường làm mọi người nhầm lẫn (bao gồm cả bản thân tôi) là khi bạn tiêm Dịch vụ hoặc Nhà máy vào mã của mình, chúng có thể được sử dụng theo cùng một cách, những gì bạn nhận được trong mã của mình trong cả hai trường hợp là một đối tượng cụ thể mà bạn có thể gọi ngay lập tức. Có nghĩa là trong trường hợp Dịch vụ, các cuộc gọi góc cạnh "mới" trên tờ khai dịch vụ thay mặt bạn. Tôi nghĩ rằng đây là một khái niệm phức tạp.


1

Đây sẽ là câu trả lời hay nhất và ngắn gọn để hiểu Dịch vụ Vs Factory Vs Nhà cung cấp

Nguồn : https://groups.google.com/forum/#!msg/angular/56sdORweoqg/HuZsOsMvKv4J

Dưới đây là những gì ben nói với bản demo http://jsbin.com/ohamub/1/edit?html,output

"Có những bình luận trong mã minh họa cho sự khác biệt chính nhưng tôi sẽ mở rộng về chúng một chút ở đây. Một lưu ý, tôi chỉ đang loay hoay với điều này vì vậy nếu tôi nói bất cứ điều gì sai xin vui lòng cho tôi biết.

Dịch vụ

Cú pháp : module.service ('serviceName', function);

Kết quả : Khi khai báo serviceName dưới dạng đối số có thể tiêm, bạn sẽ được cung cấp tham chiếu hàm thực tế được truyền cho module.service.

Cách sử dụng : Có thể hữu ích cho việc chia sẻ các hàm tiện ích hữu ích để gọi bằng cách thêm () vào tham chiếu hàm được chèn. Cũng có thể được chạy với in tiêmArg.call (cái này) hoặc tương tự.

Các nhà máy

Cú pháp : module.factory ('FactoryName', function);

Kết quả : Khi khai báo FactoryName là một đối số có thể tiêm, bạn sẽ được cung cấp giá trị được trả về bằng cách gọi tham chiếu hàm được truyền cho module.factory.

Cách sử dụng : Có thể hữu ích cho việc trả về một hàm 'lớp' mà sau đó có thể được tạo mới để tạo các thể hiện.

Nhà cung cấp

Cú pháp : module.provider ('CarrierName', function);

Kết quả : Khi khai báo tên nhà cung cấp dưới dạng đối số có thể tiêm, bạn sẽ được cung cấp giá trị được trả về bằng cách gọi phương thức $ get của tham chiếu hàm được truyền cho module.provider.

Cách sử dụng : Có thể hữu ích cho việc trả về một hàm 'lớp' mà sau đó có thể được tạo mới để tạo các thể hiện nhưng yêu cầu một số loại cấu hình trước khi được đưa vào. Có lẽ hữu ích cho các lớp có thể tái sử dụng trên các dự án? Vẫn còn mơ hồ về điều này. "Ben


1

Tôi đã có sự nhầm lẫn này trong một thời gian và tôi đang cố gắng hết sức để đưa ra một lời giải thích đơn giản ở đây. Hy vọng điều này sẽ giúp!

angular .factoryangular .servicecả hai đều được sử dụng để khởi tạo một dịch vụ và hoạt động theo cùng một cách.

Sự khác biệt duy nhất là, cách bạn muốn khởi tạo dịch vụ của mình.

Cả hai đều là người độc thân


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


Nhà máy

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

Nếu bạn muốn khởi tạo dịch vụ của mình từ một hàm mà bạn có với giá trị trả về , bạn phải sử dụng factoryphương thức này .

ví dụ

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

app.factory('myService', myService);

Khi tiêm dịch vụ này (ví dụ: bộ điều khiển của bạn):

  • Angular sẽ gọi hàm đã cho của bạn (as myService()) để trả về đối tượng
  • Singleton - chỉ được gọi một lần, được lưu trữ và truyền cùng một đối tượng.


Dịch vụ

ứng dụng dịch vụ ( <service name>, <constructor function>)

Nếu bạn muốn khởi tạo dịch vụ của mình từ hàm tạo (sử dụng thistừ khóa), bạn phải sử dụng servicephương pháp này .

ví dụ

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

app.service('myService', myService);

Khi tiêm dịch vụ này (ví dụ: bộ điều khiển của bạn):

  • Angular sẽ newlấy hàm đã cho của bạn (as new myService()) để trả về đối tượng
  • Singleton - chỉ được gọi một lần, được lưu trữ và truyền cùng một đối tượng.


LƯU Ý: Nếu bạn sử dụng factorycùng <constructor function>hoặc servicevới <function with a return value>, nó sẽ không hoạt động.


Ví dụ - DEMOs


1

Đây là điều giúp tôi hiểu được sự khác biệt, nhờ vào một bài đăng trên blog của Pascal Precht.

Dịch vụ là một phương thức trên một mô-đun có tên và chức năng xác định dịch vụ. Bạn có thể tiêm và sử dụng dịch vụ cụ thể đó trong các thành phần khác, như bộ điều khiển, chỉ thị và bộ lọc. Một nhà máy là một phương thức trên một mô-đun và nó cũng có một tên và một chức năng, xác định nhà máy. Chúng tôi cũng có thể tiêm và sử dụng nó giống như cách chúng tôi đã làm với dịch vụ.

Các đối tượng được tạo mới sử dụng giá trị của thuộc tính nguyên mẫu của hàm xây dựng của chúng làm nguyên mẫu, vì vậy tôi tìm thấy mã Angular gọi Object.create (), mà tôi tin là hàm xây dựng dịch vụ khi được khởi tạo. Tuy nhiên, một chức năng của nhà máy thực sự chỉ là một chức năng được gọi, đó là lý do tại sao chúng ta phải trả về một đối tượng theo nghĩa đen cho nhà máy.

Đây là mã 1,5 góc tôi tìm thấy cho nhà máy:

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

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

Đoạn mã nguồn góc cho hàm Factory ():

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

Nó lấy tên và hàm xuất xưởng được truyền và trả về một nhà cung cấp có cùng tên, có phương thức $ get là hàm xuất xưởng của chúng tôi. Bất cứ khi nào bạn yêu cầu người tiêm cho một phụ thuộc cụ thể, về cơ bản, nó sẽ hỏi nhà cung cấp tương ứng về một thể hiện của dịch vụ đó, bằng cách gọi phương thức $ get (). Đó là lý do tại sao $ get () là bắt buộc, khi tạo nhà cung cấp.

Đây là mã 1,5 góc cho dịch vụ.

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

Hóa ra khi chúng ta gọi dịch vụ (), nó thực sự gọi là nhà máy ()! Tuy nhiên, nó không chỉ chuyển chức năng xây dựng dịch vụ của chúng tôi cho nhà máy. Nó cũng truyền một hàm yêu cầu trình tạo khởi tạo một đối tượng bởi hàm tạo đã cho.

Nói cách khác, nếu chúng ta tiêm MyService ở đâu đó, điều xảy ra trong mã là:

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

Để phục hồi lại, một dịch vụ gọi một nhà máy, đó là phương thức $ get () trên nhà cung cấp tương ứng. Hơn nữa, $ kim phun.instantiate () là phương thức cuối cùng gọi Object.create () với hàm xây dựng. Đó là lý do tại sao chúng tôi sử dụng "cái này" trong các dịch vụ.

Đối với ES5, chúng tôi không sử dụng dịch vụ: dịch vụ () hoặc nhà máy (), đó luôn là một nhà máy được gọi là nhà cung cấp dịch vụ của chúng tôi.

Bạn cũng có thể làm điều tương tự với các dịch vụ. Dịch vụ là một hàm tạo, tuy nhiên, điều đó không ngăn chúng ta trả lại nghĩa đen của đối tượng. Vì vậy, chúng tôi có thể lấy mã dịch vụ của mình và viết nó theo cách mà về cơ bản nó thực hiện chính xác giống như nhà máy của chúng tôi hoặc nói cách khác, bạn có thể viết một dịch vụ như một nhà máy để trả về một đối tượng.

Tại sao hầu hết mọi người khuyên nên sử dụng các nhà máy hơn các dịch vụ? Đây là câu trả lời hay nhất mà tôi đã thấy xuất phát từ cuốn sách của Pawel Kozlowski: Làm chủ phát triển ứng dụng web với AngularJS.

Phương pháp nhà máy là cách phổ biến nhất để đưa các đối tượng vào hệ thống tiêm phụ thuộc AngularJS. Nó rất linh hoạt và có thể chứa logic sáng tạo tinh vi. Vì các nhà máy là các chức năng thông thường, chúng tôi cũng có thể tận dụng phạm vi từ vựng mới để mô phỏng các biến "riêng tư". Điều này rất hữu ích vì chúng tôi có thể ẩn chi tiết triển khai của một dịch vụ cụ thể. "


1
  • Với nhà máy, bạn thực sự tạo ra một đối tượng bên trong nhà máy và trả lại nó.
  • Với dịch vụ bạn chỉ cần có một chức năng tiêu chuẩn sử dụng thistừ khóa để xác định chức năng.
  • Với nhà cung cấp, bạn có một $getđịnh nghĩa và nó có thể được sử dụng để lấy đối tượng trả về dữ liệu.

1

Có ba cách xử lý logic kinh doanh trong AngularJS: ( Lấy cảm hứng từ khóa học Coursera AngularJS của Yaakov ) đó là:

  1. Dịch vụ
  2. Nhà máy
  3. Các nhà cung cấp

Ở đây chúng ta sẽ chỉ nói về Service vs Factory

DỊCH VỤ :

Cú pháp:

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>

Các tính năng chính của Dịch vụ:

  1. Ngay lập tức : Nếu dịch vụ không được tiêm, nó sẽ không được khởi tạo bao giờ. Vì vậy, để sử dụng nó, bạn sẽ phải tiêm nó vào một mô-đun.

  2. Singleton : Nếu được tiêm vào nhiều mô-đun, tất cả sẽ chỉ có quyền truy cập vào một thể hiện cụ thể. Đó là lý do tại sao, rất thuận tiện để chia sẻ dữ liệu trên các bộ điều khiển khác nhau.

NHÀ MÁY

Bây giờ hãy nói về Nhà máy trong AngularJS

Trước tiên hãy xem cú pháp :

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

Bây giờ sử dụng hai ở trên trong bộ điều khiển:

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

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

Đặc điểm của Nhà máy:

  1. Các loại dịch vụ theo mô hình thiết kế nhà máy . Nhà máy có thể được coi là một nơi trung tâm tạo ra các đối tượng hoặc phương pháp mới.

  2. Điều này không chỉ sản xuất singleton, mà còn các dịch vụ tùy biến.

  3. Các .service()phương pháp là một nhà máy mà luôn tạo ra cùng một loại dịch vụ, mà là một singleton. Không có cách dễ dàng để cấu hình hành vi của nó. .service()Phương pháp đó thường được sử dụng như một lối tắt cho một cái gì đó không yêu cầu bất kỳ cấu hình nào.



0

Bạn có thể hiểu sự khác biệt với sự tương tự này - Hãy xem xét sự khác biệt giữa một hàm bình thường sẽ trả về một số giá trị và hàm xây dựng sẽ được khởi tạo bằng cách sử dụng từ khóa mới. một đối tượng) trong khi tạo dịch vụ giống như tạo hàm xây dựng (lớp OO) mà chúng ta có thể tạo cá thể bằng từ khóa mới. Điều duy nhất cần lưu ý ở đây là khi chúng ta sử dụng phương thức Dịch vụ để tạo các dịch vụ, nó sẽ tự động tạo phiên bản của nó bằng cơ chế tiêm phụ thuộc được hỗ trợ bởi AngularJS

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.