web-dev-qa-db-ja.com

AngularJS:サービス対プロバイダ対工場

AngularJSのServiceProvider、およびFactoryの違いは何ですか?

3257
Lior

AngularJSメーリングリストから、私は すばらしいスレッド サービス対ファクトリ対プロバイダ、そしてそれらのインジェクションの使い方を説明しています。答えをまとめる:

サービス内容

構文:module.service( 'serviceName', function );
結果:serviceNameを挿入可能な引数として宣言すると、関数のインスタンスが提供されます。言い換えればnew FunctionYouPassedToService()です。

工場

構文:module.factory( 'factoryName', function );
結果:factoryNameを注入可能な引数として宣言すると、module.factoryに渡された関数参照を呼び出すことによって返される値が提供されます。

プロバイダ

構文:module.provider( 'providerName', function );
結果:providerNameを注入可能な引数として宣言すると、(new ProviderFunction()).$get()が提供されます。コンストラクタ関数は$ getメソッドが呼び出される前にインスタンス化されます - ProviderFunctionはmodule.providerに渡される関数参照です。

プロバイダには、モジュール構成段階で構成できるという利点があります。

提供されたコードについては ここ を参照してください。

これがMiskoによるさらに詳しい説明です。

provide.value('a', 123);

function Controller(a) {
  expect(a).toEqual(123);
}

この場合、インジェクタは単に値をそのまま返します。しかし、もしあなたが値を計算したいとしたら?それから工場を使う

provide.factory('b', function(a) {
  return a*2;
});

function Controller(b) {
  expect(b).toEqual(246);
}

だからfactoryは値を作成する責任がある関数です。ファクトリ関数は他​​の依存関係を要求できることに注意してください。

しかし、もっとOOになり、Greeterというクラスを作りたいとしたら?

function Greeter(a) {
  this.greet = function() {
    return 'Hello ' + a;
  }
}

それからインスタンス化するためにあなたは書く必要があるでしょう

provide.factory('greeter', function(a) {
  return new Greeter(a);
});

それから私達はこのようにコントローラーで 'greeter'を要求することができます

function Controller(greeter) {
  expect(greeter instanceof Greeter).toBe(true);
  expect(greeter.greet()).toEqual('Hello 123');
}

しかし、それはあまりにも言葉遣いです。これを書くもっと短い方法はprovider.service('greeter', Greeter);でしょう

しかし、インジェクションの前にGreeterクラスを設定したいとしたらどうでしょうか。それから私達は書くことができる

provide.provider('greeter2', function() {
  var salutation = 'Hello';
  this.setSalutation = function(s) {
    salutation = s;
  }

  function Greeter(a) {
    this.greet = function() {
      return salutation + ' ' + a;
    }
  }

  this.$get = function(a) {
    return new Greeter(a);
  };
});

それから我々はこれを行うことができます:

angular.module('abc', []).config(function(greeter2Provider) {
  greeter2Provider.setSalutation('Halo');
});

function Controller(greeter2) {
  expect(greeter2.greet()).toEqual('Halo 123');
}

ちなみに、servicefactory、およびvalueはすべてproviderから派生しています。

provider.service = function(name, Class) {
  provider.provide(name, function() {
    this.$get = function($injector) {
      return $injector.instantiate(Class);
    };
  });
}

provider.factory = function(name, factory) {
  provider.provide(name, function() {
    this.$get = function($injector) {
      return $injector.invoke(factory);
    };
  });
}

provider.value = function(name, value) {
  provider.factory(name, function() {
    return value;
  });
};
2849
Lior

JS Fiddleデモ

factory/service/providerを使った "Hello world"の例:

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 src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="MyCtrl">
    {{hellos}}
</div>
</body>
807
EpokK

TL; DR

1) Factory を使用している場合は、オブジェクトを作成し、それにプロパティを追加してから、同じオブジェクトを返します。このファクトリをコントローラに渡すと、オブジェクトのこれらのプロパティはファクトリを通じてそのコントローラで利用できるようになります。

app.controller(‘myFactoryCtrl’, function($scope, myFactory){
  $scope.artist = myFactory.getArtist();
});

app.factory(‘myFactory’, function(){
  var _artist = ‘Shakira’;
  var service = {};

  service.getArtist = function(){
    return _artist;
  }

  return service;
});


2) Service を使用している場合、AngularJSは「new」キーワードを使用してその背後でインスタンス化します。そのため、「this」にプロパティを追加すると、サービスは「this」を返します。あなたがあなたのコントローラにサービスを渡すとき、「これ」のそれらのプロパティはあなたのサービスを通してそのコントローラで利用可能になります。

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

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



3) プロバイダ は、あなたが.config()関数に渡すことができる唯一のサービスです。利用可能にする前にサービスオブジェクトにモジュール全体の設定を提供する場合は、プロバイダを使用してください。

app.controller(‘myProvider’, function($scope, myProvider){
  $scope.artist = myProvider.getArtist();
  $scope.data.thingFromConfig = myProvider.thingOnConfig;
});

app.provider(‘myProvider’, function(){
 //Only the next two lines are available in the app.config()
 this._artist = ‘’;
 this.thingFromConfig = ‘’;
  this.$get = function(){
    var that = this;
    return {
      getArtist: function(){
        return that._artist;
      },
      thingOnConfig: that.thingFromConfig
    }
  }
});

app.config(function(myProviderProvider){
  myProviderProvider.thingFromConfig = ‘This was set in config’;
});



非TL; DR

1)工場
工場は、サービスを作成および構成するための最も一般的な方法です。 TL、DRが言ったこと以上のものは本当にありません。オブジェクトを作成し、それにプロパティを追加してから、同じオブジェクトを返すだけです。その後、ファクトリをコントローラに渡すと、オブジェクトのこれらのプロパティはファクトリを通じてそのコントローラで利用できるようになります。より広範な例を以下に示します。

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

MyFactoryをコントローラに渡すと、serviceに付加したプロパティはすべて使用できるようになります。

それでは、コールバック関数にいくつかの「非公開」変数を追加しましょう。これらはコントローラから直接アクセスすることはできませんが、必要に応じてこれらの「プライベート」変数を変更できるように、最終的に「service」にゲッター/セッターメソッドを設定します。

app.factory(‘myFactory’, function($http, $q){
  var service = {};
  var baseUrl = ‘https://iTunes.Apple.com/search?term=’;
  var _artist = ‘’;
  var _finalUrl = ‘’;

  var makeUrl = function(){
   _artist = _artist.split(‘ ‘).join(‘+’);
    _finalUrl = baseUrl + _artist + ‘&callback=JSON_CALLBACK’;
    return _finalUrl
  }

  return service;
});

ここでは、これらの変数や関数を「service」に関連付けていないことに気付くでしょう。後で使用または変更するために、それらを作成するだけです。

  • baseUrlは、iTunes APIが必要とするベースURLです。
  • _artistは私たちが検索したいアーティストです
  • _finalUrlは、最後に完全に構​​築されたURLで、ここからiTunesに電話をかけます。
  • makeUrlは、私たちのiTunes用のURLを作成して返す機能です。

これで、ヘルパー/プライベート変数と関数が用意されたので、 'service'オブジェクトにいくつかのプロパティを追加しましょう。 myFactoryを渡したどのコントローラでも、serviceに設定したものはすべて直接使用できます。

アーティストを返すか設定するだけのsetArtistおよびgetArtistメソッドを作成します。作成したURLでiTunes APIを呼び出すメソッドも作成します。このメソッドは、データがiTunes APIから戻ってきたときに実行される約束を返します。 Angular JSでプロミスを使用した経験があまりない場合は、それらについて深く掘り下げることを強くお勧めします。

Below setArtist アーティストを受け入れ、アーティストを設定できます。 getArtist はアーティストを返します。 callItunes はまず$ httpリクエストで使用するURLを作成するためにmakeUrl()を呼び出します。それからpromiseオブジェクトを設定し、最後のURLで$ httpリクエストを行います。そして$ httpがpromiseを返すので、リクエストの後に.successまたは.errorを呼び出すことができます。その後、私たちはiTunesのデータで約束を解決するか、「エラーがありました」というメッセージでそれを拒否します。

app.factory('myFactory', function($http, $q){
  var service = {};
  var baseUrl = 'https://iTunes.Apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  service.setArtist = function(artist){
    _artist = artist;
  }

  service.getArtist = function(){
    return _artist;
  }

  service.callItunes = function(){
    makeUrl();
    var deferred = $q.defer();
    $http({
      method: 'JSONP',
      url: _finalUrl
    }).success(function(data){
      deferred.resolve(data);
    }).error(function(){
      deferred.reject('There was an error')
    })
    return deferred.promise;
  }

  return service;
});

これで私たちの工場は完成しました。これで「myFactory」を任意のコントローラに注入できるようになり、サービスオブジェクトにアタッチしたメソッドを呼び出すことができるようになります(setArtist、getArtist、およびcallItunes)。

app.controller('myFactoryCtrl', function($scope, myFactory){
  $scope.data = {};
  $scope.updateArtist = function(){
    myFactory.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myFactory.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }
});

上記のコントローラでは、「myFactory」サービスを注入しています。次に、 'myFactory'からのデータを使用して、$ scopeオブジェクトのプロパティを設定します。上記の唯一のトリッキーなコードは、あなたがこれまで約束を扱ったことがない場合です。 callItunesは約束を返しているので、.then()メソッドを使用して、約束がiTunesデータで満たされた後にのみ$ scope.data.artistDataを設定することができます。あなたは私たちのコントローラーが非常に「薄い」ことに気付くでしょう(これは良いコーディング習慣です)。私たちのロジックと永続データはすべて私たちのサービス内にあり、私たちのコントローラー内にはありません。

2)サービス
おそらく、サービスの作成を扱うときに知っておくべき最大のことは、それが「new」キーワードでインスタンス化されているということです。あなたにとってJavaScriptの達人はこれがあなたにコードの性質への大きなヒントを与えるべきです。 JavaScriptの知識が限られている方、または「new」キーワードが実際に行うことに慣れていない方のために、最終的にサービスの性質を理解するのに役立つJavaScriptの基礎をいくつか見てみましょう。

「new」キーワードを使用して関数を呼び出したときに発生する変更を実際に確認するには、関数を作成して「new」キーワードを使用して呼び出してから、「new」キーワードを見たときのインタプリタの動作を示します。最終結果は両方とも同じになります。

まずコンストラクタを作成しましょう。

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

これは典型的なJavaScriptコンストラクタ関数です。 「new」キーワードを使用してPerson関数を呼び出すたびに、「this」は新しく作成されたオブジェクトにバインドされます。

それでは、Personのプロトタイプにメソッドを追加して、Personのすべてのインスタンスのクラスで使用できるようにしましょう。

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

プロトタイプにsayName関数を追加したので、Personのすべてのインスタンスは、そのインスタンスの名前を警告するためにsayName関数を呼び出すことができます。

プロトタイプにPersonコンストラクター関数とsayName関数があるので、実際にPersonのインスタンスを作成してから、sayName関数を呼び出します。

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

つまり、Personコンストラクタを作成し、そのプロトタイプに関数を追加し、Personインスタンスを作成してから、そのプロトタイプでその関数を呼び出すためのコードは、すべてこのようになります。

var Person = function(name, age){
  this.name = name;
  this.age = age;
}
Person.prototype.sayName = function(){
  alert(‘My name is ‘ + this.name);
}
var tyler = new Person(‘Tyler’, 23);
tyler.sayName(); //alerts ‘My name is Tyler’

それでは、JavaScriptで「new」キーワードを使用したときに実際に何が起きているのかを見てみましょう。この例で「new」を使用した後は、それがオブジェクトであるかのように、「tyler」でメソッド(sayName)を呼び出すことができます。つまり、最初にPersonコンストラクタがオブジェクトを返していることがわかります。それがコード内で確認できるかどうかは関係ありません。次に、sayName関数は直接Personインスタンスではなくプロトタイプにあるため、Person関数が返すオブジェクトは失敗したルックアップでそのプロトタイプに委任する必要があります。もっと簡単に言うと、tyler.sayName()を呼び出すと、インタプリタは「OK、今作成した「tyler」オブジェクトを調べ、sayName関数を見つけて呼び出します」と言います。ちょっと待って、私はここでそれを見ません - 私が見るのは名前と年齢だけです、私はプロトタイプをチェックしましょう。うん、それはプロトタイプの上にあるように見えます、私がそれを呼びましょう。」.

下記は「new」キーワードが実際にJavaScriptで何をしているのかを考えるためのコードです。これは基本的に上の段落のコード例です。私は「インタプリタビュー」、つまりインタプリタがコードの中にコードを見る方法を置きます。

var Person = function(name, age){
  //The below line creates an object(obj) that will delegate to the person’s prototype on failed lookups.
  //var obj = Object.create(Person.prototype);

  //The line directly below this sets ‘this’ to the newly created object
  //this = obj;

  this.name = name;
  this.age = age;

  //return this;
}

JavaScriptで 'new'キーワードが実際に何をするのかについてのこの知識を持っているので、AngularJSでサービスを作成することは理解しやすいはずです。

サービスを作成するときに理解するべき最大のことは、サービスが「new」キーワードでインスタンス化されていることを知っていることです。その知識を上記の例と組み合わせることで、あなたは自分のプロパティとメソッドを「this」に直接付加することになり、それがサービス自体から返されることになります。これを実際に見てみましょう。

Factoryの例で最初に行ったこととは異なり、オブジェクトを作成してからそのオブジェクトを返す必要はありません。これは、前述のように、 'new'キーワードを使用してインタープリタがそのオブジェクトを作成するためです。それはプロトタイプであり、それから私たちがその仕事をする必要なしにそれを私たちのために返します。

まず最初に、私たちの「プライベート」およびヘルパー関数を作成しましょう。私達は私達の工場と全く同じことをしたので、これは非常におなじみのはずです。ここでは各行の動作を説明しません。ファクトリの例で説明したのですが、混乱した場合はファクトリの例をもう一度読んでください。

app.service('myService', function($http, $q){
  var baseUrl = 'https://iTunes.Apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }
});

これで、コントローラで利用できるようになるすべてのメソッドを「this」に追加します。

app.service('myService', function($http, $q){
  var baseUrl = 'https://iTunes.Apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  this.setArtist = function(artist){
    _artist = artist;
  }

  this.getArtist = function(){
    return _artist;
  }

  this.callItunes = function(){
    makeUrl();
    var deferred = $q.defer();
    $http({
      method: 'JSONP',
      url: _finalUrl
    }).success(function(data){
      deferred.resolve(data);
    }).error(function(){
      deferred.reject('There was an error')
    })
    return deferred.promise;
  }

});

今や私たちの工場のように、setArtist、getArtist、およびcallItunesはmyServiceを渡したどのコントローラでも利用可能になります。これがmyServiceコントローラーです(これは、ファクトリーコントローラーとほぼ同じです)。

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

  $scope.submitArtist = function(){
    myService.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }
});

前述したように、「新しい」機能の概要を理解すると、サービスはAngularJSの工場とほぼ同じになります。

3)プロバイダ

プロバイダについて覚えておくべき最大のことは、それらがあなたがあなたのアプリケーションのapp.config部分に渡すことができる唯一のサービスであるということです。アプリケーション内の他の場所で利用できるようになる前にサービスオブジェクトの一部を変更する必要がある場合、これは非常に重要です。サービス/ファクトリに非常に似ていますが、私たちが議論するいくつかの違いがあります。

最初に私達は私達が私達のサービスと工場で行ったのと同じ方法で私達のプロバイダーを設定しました。以下の変数は、私たちの「非公開」およびヘルパー関数です。

app.provider('myProvider', function(){
   var baseUrl = 'https://iTunes.Apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  //Going to set this property on the config function below.
  this.thingFromConfig = ‘’;

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }
}

*上記のコードのいずれかの部分が混乱を招くような場合は、Factoryのセクションを見てください。ここで、すべての詳細について説明しています。

プロバイダは3つのセクションを持つと考えることができます。最初のセクションは、後で変更/設定される「非公開の」変数/関数です(上図)。 2番目のセクションは、app.config関数で使用できる変数/関数です。したがって、他の場所でも使用可能になる前に変更することができます(上記も参照)。これらの変数は「this」キーワードに付加する必要があることに注意することが重要です。この例では、app.configファイルで変更できるのはthingFromConfigだけです。 3番目のセクション(下図)は、 'myProvider'サービスをその特定のコントローラーに渡したときに、コントローラーで利用できるすべての変数/関数です。

Providerでサービスを作成するとき、あなたのコントローラで利用できる唯一のプロパティ/メソッドは$ get()関数から返されるそれらのプロパティ/メソッドです。以下のコードは$ getを 'this'にします(これは最終的にその関数から返されることがわかっています)。これで、その$ get関数は、コントローラで利用可能にしたいすべてのメソッド/プロパティを返します。これがコード例です。

this.$get = function($http, $q){
    return {
      callItunes: function(){
        makeUrl();
        var deferred = $q.defer();
        $http({
          method: 'JSONP',
          url: _finalUrl
        }).success(function(data){
          deferred.resolve(data);
        }).error(function(){
          deferred.reject('There was an error')
        })
        return deferred.promise;
      },
      setArtist: function(artist){
        _artist = artist;
      },
      getArtist: function(){
        return _artist;
      },
      thingOnConfig: this.thingFromConfig
    }
  }

今すぐ完全なプロバイダコードはこのようになります

app.provider('myProvider', function(){
  var baseUrl = 'https://iTunes.Apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  //Going to set this property on the config function below
  this.thingFromConfig = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  this.$get = function($http, $q){
    return {
      callItunes: function(){
        makeUrl();
        var deferred = $q.defer();
        $http({
          method: 'JSONP',
          url: _finalUrl
        }).success(function(data){
          deferred.resolve(data);
        }).error(function(){
          deferred.reject('There was an error')
        })
        return deferred.promise;
      },
      setArtist: function(artist){
        _artist = artist;
      },
      getArtist: function(){
        return _artist;
      },
      thingOnConfig: this.thingFromConfig
    }
  }
});

これで、ファクトリやサービスと同じように、setArtist、getArtist、およびcallItunesは、myProviderを渡したどのコントローラでも使用可能になります。これがmyProviderコントローラです(これは、ファクトリ/サービスコントローラとほぼ同じです)。

app.controller('myProviderCtrl', function($scope, myProvider){
  $scope.data = {};
  $scope.updateArtist = function(){
    myProvider.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myProvider.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }

  $scope.data.thingFromConfig = myProvider.thingOnConfig;
});

前述のように、Providerを使用してサービスを作成することの全体的な目的は、最後のオブジェクトがアプリケーションの残りの部分に渡される前に、app.config関数を介していくつかの変数を変更できるようにすることです。その例を見てみましょう。

app.config(function(myProviderProvider){
  //Providers are the only service you can pass into app.config
  myProviderProvider.thingFromConfig = 'This sentence was set in app.config. Providers are the only service that can be passed into config. Check out the code to see how it works';
});

これで、私たちのプロバイダでは「thingFromConfig」が空の文字列であることがわかりますが、それがDOMに表示されると、「This文が設定されました…」となります。

635
Tyler McGinnis

AngularJSのファクトリ、サービス、およびプロバイダについて

これらはすべて、再利用可能なシングルトンオブジェクトを共有するために使用されています。それはあなたのアプリ/様々なコンポーネント/モジュール間で再利用可能なコードを共有するのを助けます。

Docs Service/Factory から:

  • 遅延インスタンス化 - Angularは、アプリケーションコンポーネントが依存する場合にのみサービス/ファクトリをインスタンス化します。
  • シングルトン - サービスに依存する各コンポーネントは、サービスファクトリによって生成された単一のインスタンスへの参照を取得します。

工場

ファクトリは、オブジェクトを作成する前にロジックを操作/追加することができる機能で、新しく作成されたオブジェクトが返されます。

app.factory('MyFactory', function() {
    var serviceObj = {};
    //creating an object with methods/functions or variables
    serviceObj.myFunction = function() {
        //TO DO:
    };
    //return that object
    return serviceObj;
});

使用方法

それは単なるクラスのような関数の集まりです。したがって、それをあなたのcontroller/factory/directive関数の中にインジェクトするとき、それは異なるコントローラでインスタンス化されることができます。アプリごとに一度だけインスタンス化されます。

サービス

サービスを見ながら、単にアレイのプロトタイプについて考えてください。サービスは 'new'キーワードを使って新しいオブジェクトをインスタンス化する関数です。 thisキーワードを使用して、サービスオブジェクトにプロパティと関数を追加できます。ファクトリとは異なり、何も返しません(メソッド/プロパティを含むオブジェクトを返します)。

app.service('MyService', function() {
    //directly binding events to this context
    this.myServiceFunction = function() {
        //TO DO:
    };
});

使用方法

アプリケーション全体で単一のオブジェクトを共有する必要があるときに使用します。例えば、認証されたユーザーの詳細、共有可能な方法/データ、ユーティリティ機能など.

プロバイダ

プロバイダは、設定可能なサービスオブジェクトを作成するために使用されます。 config関数からサービス設定を構成できます。 $get()関数を使って値を返します。 $get関数は、実行フェーズで角度付きで実行されます。

app.provider('configurableService', function() {
    var name = '';
    //this method can be be available at configuration time inside app.config.
    this.setName = function(newName) {
        name = newName;
    };
    this.$get = function() {
        var getName = function() {
             return name;
        };
        return {
            getName: getName //exposed object to where it gets injected.
        };
    };
});

使用方法

サービスオブジェクトを利用可能にする前に、モジュール単位の設定を提供する必要がある場合。 devstageprodのように、自分の環境に基づいてAPI URLを設定したいとします。

_ note _

Service&factoryはそうではありませんがプロバイダだけが角度の設定段階で利用可能になります。

これで ファクトリー、サービス、およびプロバイダー についての理解が深まったことを願います。

222
Pankaj Parkar

私にとっては、何かが once を実行し、得られた値を格納し、それから 参照されたときに同じ格納された値 を実行することによって 依存性注入を介して

たとえば、

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

この3つの違いは、

  1. aの格納値は、fnを実行することによって得られます。
  2. bの保存値はnewing fnから来ます。
  3. cの格納値は、まずnewfnすることによってインスタンスを取得し、次にそのインスタンスの$getメソッドを実行することによって得られます。

つまり、AngularJSの内部にはキャッシュオブジェクトのようなものがあります。各インジェクションの値は、最初にインジェクションされたときに一度だけ割り当てられます。

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

これが、サービスでthisを使用し、プロバイダでthis.$getを定義する理由です。

191
Lucia

サービス対プロバイダ対工場:

私はそれを単純にしようとしています。基本的なJavaScriptの概念に関するすべてです。

まずはじめに、AngularJSで services について説明しましょう。

サービスとは: AngularJSでは、 Service は、便利なメソッドやプロパティを格納できるシングルトンJavaScriptオブジェクトに他なりません。このシングルトンオブジェクトはngApp(Angular app)ごとに作成され、現在のアプリ内のすべてのコントローラ間で共有されます。 Angularは、サービスオブジェクトをインスタンス化するときに、このサービスオブジェクトを一意のサービス名で登録します。そのため、サービスインスタンスが必要になるたびに、Angularがこのサービス名のレジストリを検索し、サービスオブジェクトへの参照を返します。メソッドを呼び出したり、サービスオブジェクトのプロパティにアクセスしたりできるようにします。プロパティ、メソッドをコントローラのスコープオブジェクトにも置くことができるかどうか質問があるかもしれません!それでは、なぜあなたはサービスオブジェクトが必要ですか?答えは次のとおりです。サービスは複数のコントローラスコープ間で共有されます。いくつかのプロパティ/メソッドをコントローラのスコープオブジェクトに入れると、それは現在のスコープでのみ利用可能になります。しかし、サービスオブジェクトにメソッドやプロパティを定義すると、それはグローバルに利用可能になり、そのサービスを注入することで任意のコントローラのスコープ内でアクセスできるようになります。

そのため、3つのコントローラスコープがある場合、それをcontrollerA、controllerB、controllerCとすると、すべて同じサービスインスタンスを共有します。

<div ng-controller='controllerA'>
    <!-- controllerA scope -->
</div>
<div ng-controller='controllerB'>
    <!-- controllerB scope -->
</div>
<div ng-controller='controllerC'>
    <!-- controllerC scope -->
</div>

サービスの作り方

AngularJSには、サービスを登録するためのさまざまな方法があります。ここでは3つのメソッドfactory(..)、service(..)、provider(..)に集中します。

コード参照にこのリンクを使用してください

工場出荷時の機能:

ファクトリ関数は以下のように定義できます。

factory('serviceName',function fnFactory(){ return serviceInstance;})

AngularJSは 'factory(' serviceName '、fnFactory)' の2つのパラメータserviceNameとJavaScript関数を取るメソッドを提供します。 Angularは、次のように fnFactory() という関数を呼び出してサービスインスタンスを作成します。

var serviceInstace = fnFactory();

渡された関数はオブジェクトを定義し、そのオブジェクトを返すことができます。 AngularJSは、このオブジェクト参照を最初の引数として渡される変数に単純に格納します。 fnFactoryから返されるものはすべてserviceInstanceにバインドされます。オブジェクトを返す代わりに、関数、値なども返すことができます。返されるものはすべて、インスタンスのサービスに使用できます。

例:

var app= angular.module('myApp', []);
//creating service using factory method
app.factory('factoryPattern',function(){
  var data={
    'firstName':'Tom',
    'lastName':' Cruise',
    greet: function(){
      console.log('hello!' + this.firstName + this.lastName);
    }
  };

  //Now all the properties and methods of data object will be available in our service object
  return data;
});

サービス機能:

service('serviceName',function fnServiceConstructor(){})

それは別の方法です、私たちはサービスを登録することができます。唯一の違いは、AngularJSがサービスオブジェクトをインスタンス化する方法です。今回はAngularは 'new'キーワードを使用して以下のようなコンストラクタ関数を呼び出します。

var serviceInstance = new fnServiceConstructor();

コンストラクター関数では、サービスオブジェクトにプロパティ/メソッドを追加するために 'this'キーワードを使用できます。例:

//Creating a service using the service method
var app= angular.module('myApp', []);
app.service('servicePattern',function(){
  this.firstName ='James';
  this.lastName =' Bond';
  this.greet = function(){
    console.log('My Name is '+ this.firstName + this.lastName);
  };
});

プロバイダ機能:

Provider()関数は、サービスを作成するためのもう1つの方法です。ユーザーにグリーティングメッセージを表示するだけのサービスを作成したいと思います。しかし私達はまたユーザーが彼ら自身の挨拶メッセージを設定できるような機能を提供したいと思います。技術的には、設定可能なサービスを作りたいです。どうすればこれができますか?アプリがカスタムのあいさつメッセージを渡すことができ、Angularjsがそれを私たちのサービスインスタンスを作成するファクトリ/コンストラクタ関数で利用できるようにする方法があるはずです。そのような場合、provider()関数が仕事をします。 provider()関数を使用して、設定可能なサービスを作成できます。

以下に示すように、プロバイダ構文を使用して構成可能サービスを作成できます。

/*step1:define a service */
app.provider('service',function serviceProviderConstructor(){});

/*step2:configure the service */
app.config(function configureService(serviceProvider){});

プロバイダの構文は内部的にどのように機能しますか?

1.Providerオブジェクトは、プロバイダ関数で定義したコンストラクタ関数を使って作成されます。

var serviceProvider = new serviceProviderConstructor();

2. app.config()で渡した関数が実行されます。これは設定段階と呼ばれ、ここで私達は私達のサービスをカスタマイズする機会があります。

configureService(serviceProvider);

3.最後にserviceProviderの$ getメソッドを呼び出してサービスインスタンスを作成します。

serviceInstance = serviceProvider.$get()

提供構文を使用してサービスを作成するためのサンプルコード:

var app= angular.module('myApp', []);
app.provider('providerPattern',function providerConstructor(){
  //this function works as constructor function for provider
  this.firstName = 'Arnold ';
  this.lastName = ' Schwarzenegger' ;
  this.greetMessage = ' Welcome, This is default Greeting Message' ;
  //adding some method which we can call in app.config() function
  this.setGreetMsg = function(msg){
    if(msg){
      this.greetMessage =  msg ;
    }
  };

  //We can also add a method which can change firstName and lastName
  this.$get = function(){
    var firstName = this.firstName;
    var lastName = this.lastName ;
    var greetMessage = this.greetMessage;
    var data={
       greet: function(){
         console.log('hello, ' + firstName + lastName+'! '+ greetMessage);
       }
    };
    return data ;
  };
});

app.config(
  function(providerPatternProvider){
    providerPatternProvider.setGreetMsg(' How do you do ?');
  }
);

ワーキングデモ

要約:


Factory サービスインスタンスを返すファクトリ関数を使用します。 serviceInstance = fnFactory();

Service コンストラクタ関数を使用し、Angularサービスインスタンスを作成するために 'new'キーワードを使用してこのコンストラクタ関数を呼び出します。 serviceInstance = new fnServiceConstructor();

Provider はproviderConstructor関数を定義し、このproviderConstructor関数はファクトリ関数 $ get を定義します。 Angularは$ get()を呼び出してサービスオブジェクトを作成します。プロバイダ構文には、インスタンス化される前にサービスオブジェクトを設定するという追加の利点があります。 serviceInstance = $ get();

135
Anant

ここで何人かの人々によって正しく指摘されているように、ファクトリー、プロバイダー、サービス、さらには値と定数さえ同じもののバージョンです。あなたはより一般的なproviderをそれらすべてに詳細に分けることができます。そのようです:

enter image description here

この画像の元の記事は次のとおりです。

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

84
Luis Perez

工場

AngularJSに関数を与えると、AngularJSはファクトリが要求されたときに戻り値をキャッシュして注入します。

例:

app.factory('factory', function() {
    var name = '';
    // Return value **is** the object that will be injected
    return {
        name: name;
    }
})

使用法:

app.controller('ctrl', function($scope, factory) {
     $scope.name = factory.name;
});

サービス

AngularJSに関数を指定すると、AngularJSがnewを呼び出してインスタンス化します。サービスが要求されたときにキャッシュおよび挿入されるのは、AngularJSが作成するインスタンスです。 newがサービスのインスタンス化に使用されたため、キーワードthis は有効で、インスタンスを参照します。

例:

app.service('service', function() {
     var name = '';
     this.setName = function(newName) {
         name = newName;
     }
     this.getName = function() {
         return name;
     }
});

使用法:

app.controller('ctrl', function($scope, service) {
   $scope.name = service.getName();
});

プロバイダー

AngularJSに関数を指定すると、AngularJSはその$get関数を呼び出します。サービスが要求されたときにキャッシュおよび挿入されるのは、$get関数からの戻り値です。

プロバイダーを使用すると、プロバイダーを構成できますbefore AngularJSは$getメソッドを呼び出して、注入可能を取得します。

例:

app.provider('provider', function() {
     var name = '';
     this.setName = function(newName) {
          name = newName;
     }
     this.$get = function() {
         return {
            name: name
         }
     }
})

使用法(コントローラーに注入可能なものとして)

app.controller('ctrl', function($scope, provider) {
    $scope.name = provider.name;
});

使用法($getが呼び出される前にプロバイダーを構成して、注入可能オブジェクトを作成します)

app.config(function(providerProvider) {
    providerProvider.setName('John');
});
63
pixelbits

私はプロバイダーと遊んでいるときに面白いことに気づきました。

注射剤の視認性は、サービスや工場の場合とはプロバイダーによって異なります。 AngularJSを「定数」(たとえば、myApp.constant('a', 'Robert');)として宣言すると、それをサービス、ファクトリ、およびプロバイダに挿入できます。

しかし、AngularJSの "value"(たとえば、myApp.value('b', {name: 'Jones'});)を宣言すると、それをサービスやファクトリに挿入できますが、プロバイダ作成関数には挿入できません。ただし、プロバイダに定義した$get関数に挿入することはできます。これはAngularJSのドキュメントに記載されていますが、見逃しがちです。値メソッドと定数メソッドのセクションの%provideページにあります。

http://jsfiddle.net/R2Frv/1/ /

<div ng-app="MyAppName">
    <div ng-controller="MyCtrl">
        <p>from Service: {{servGreet}}</p>
        <p>from Provider: {{provGreet}}</p>
    </div>
</div>
<script>
    var myApp = angular.module('MyAppName', []);

    myApp.constant('a', 'Robert');
    myApp.value('b', {name: 'Jones'});

    myApp.service('greetService', function(a,b) {
        this.greeter = 'Hi there, ' + a + ' ' + b.name;
    });

    myApp.provider('greetProvider', function(a) {
        this.firstName = a;
        this.$get = function(b) {
            this.lastName = b.name;
            this.fullName = this.firstName + ' ' + this.lastName;
            return this;
        };
    });

    function MyCtrl($scope, greetService, greetProvider) {
        $scope.servGreet = greetService.greeter;
        $scope.provGreet = greetProvider.fullName;
    }
</script>
55
justlooking

これは初心者にとって非常に混乱を招く部分であり、私は簡単な言葉でそれを明確にしようとしました

AngularJS Service: は、コントローラ内のサービス参照とユーティリティ機能を共有するために使用されます。サービスは本質的にシングルトンなので、1つのサービスではブラウザに1つのインスタンスしか作成されず、ページ全体で同じ参照が使用されます。

このサービスでは、this objectを持つプロパティとして関数名を作成します。

AngularJS Factory: Factoryの目的もServiceと同じですが、この場合は新しいオブジェクトを作成し、このオブジェクトのプロパティとして関数を追加して、最後にこのオブジェクトを返します。

AngularJSプロバイダ: この目的は同じですが、プロバイダは$ get関数の出力を返します。

Service、Factory、Providerの定義と使用方法は http://www.dotnetfunda.com/articles/show/3156/difference-between-angularjs-service-factory-and-provider で説明されています。

44
Sheo Narayan

私にとって違いを理解するための最善かつ最も簡単な方法は次のとおりです。

var service, factory;
service = factory = function(injection) {}

AngularJSが特定のコンポーネントをインスタンス化する方法(簡略化):

// service
var angularService = new service(injection);

// factory
var angularFactory = factory(injection);

したがって、サービスにとってAngularJSコンポーネントとなるのは、サービス宣言関数によって表されるクラスのオブジェクトインスタンスです。ファクトリの場合は、ファクトリ宣言関数から返された結果です。ファクトリはサービスと同じように振る舞うかもしれません:

var factoryAsService = function(injection) {
  return new function(injection) {
    // Service content
  }
}

最も簡単な考え方は次のとおりです。

  • サービスはシングルトンオブジェクトインスタンスです。コードにシングルトンオブジェクトを提供したい場合はサービスを使用してください。
  • 工場はクラスです。コードにカスタムクラスを提供したい場合はファクトリを使用します(すでにインスタンス化されているためサービスでは実行できません)。

ファクトリの「クラス」の例は、プロバイダの違いとともに、周りのコメントで提供されています。

34

この問題に関する私の説明:

基本的に、上記のタイプ(サービス、ファクトリ、プロバイダなど)はすべて、グローバル変数(もちろんアプリケーション全体に対してグローバル)を作成および構成しているだけです。

グローバル変数はお勧めできませんが、これらのグローバル変数の実際の使用法は、変数を関連するコントローラーに渡すことによって 依存性注入 を提供することです。

「グローバル変数」の値を作成する際には、さまざまなレベルの複雑さがあります。

  1. 定数
    これは、他の言語の定数と同じように(JavaScriptにはない)、アプリケーション全体で変更してはいけない実際の定数を定義します。

  2. これは変更可能な値またはオブジェクトであり、他のサービスまたはファクトリを作成するときに挿入することもできる、何らかのグローバル変数として機能します(詳細はこれらを参照)。しかし、それは "リテラル値"でなければなりません。つまり、実際の値を書き出さなければならず、計算ロジックやプログラミングロジックを使用することはできません(つまり、39または_)myTextまたは{prop: "value"}は問題ありませんが、2 + 2は問題ありません)。
  3. 工場
    より一般的な値。すぐに計算することができます。値を計算するのに必要なロジックでAngularJSに関数を渡してAngularJSがそれを実行し、戻り値を名前付き変数に保存します。
    オブジェクト(その場合はserviceのように機能する)または関数(コールバック関数として変数に保存される)を返すことが可能です。
  4. サービス
    サービスは、値がオブジェクトの場合にのみ有効なfactoryのより簡略化されたバージョンであり、関数内に直接ロジックを記述することを可能にします(それがそうであるように)。 thisキーワードを使用してオブジェクトのプロパティを宣言してアクセスするのと同様に、コンストラクタ)。
  5. プロバイダ
    factoryの簡易版であるサービスとは異なり、プロバイダは "グローバル"変数を初期化するためのより複雑でありながらより柔軟な方法です。最大の柔軟性は設定のオプションです。 app.configからの値。
    thisキーワードを使用して宣言されたプロパティを持つ関数をproviderに渡すことで、serviceproviderの組み合わせを使用するように機能します。 app.configから使用できます。
    それからapp.configファイルを通して上記のプロパティを設定した後にAngularJSによって実行される独立した$ .get関数を持つ必要があり、そしてこの$ .get関数は振る舞います。上記のfactoryと同じように、その戻り値は「グローバル」変数の初期化に使用されます。
33
yoel halb

私の理解は以下でとても簡単です。

ファクトリ: あなたは単にファクトリの中にオブジェクトを作成してそれを返す。

サービス:

このキーワードを使って関数を定義する標準関数があります。

プロバイダー:

あなたが定義する$getオブジェクトがあり、それはデータを返すオブジェクトを取得するために使うことができます。

26

Angular docs からの要約:

  • オブジェクトの作成方法を定義する5つのレシピタイプがあります。- 工場サービスプロバイダーおよび定数
  • FactoryおよびServiceは、最も一般的に使用されるレシピです。それらの唯一の違いは、Serviceレシピはカスタムタイプのオブジェクトに対してより適切に機能するのに対し、FactoryJavaScriptプリミティブと関数を生成できます。
  • Providerレシピはコアレシピタイプであり、他のレシピはすべてその上にある構文上の砂糖です。
  • Providerは最も複雑なレシピタイプです。グローバルな構成が必要な再利用可能なコードを構築する場合を除き、必要ありません。

enter image description here


SOからのベストアンサー:

https://stackoverflow.com/a/26924234/16567 (<-GOOD) https://stackoverflow.com/a/27263882/16567
https://stackoverflow.com/a/16566144/16567

24
Yarin

良い答えはもうありますが、これを共有したいと思います。

まず最初に、Providerは$ injectorによってインジェクトされると想定されるservice(singletonオブジェクト)を作成する方法/レシピです(AngulaJSはIoCパターンをどう扱うか)。

そしてValue、Factory、ServiceそしてConstant(4つの方法) - Provider way/recepieに対する統語上の糖。

Service vs Factoryの部分がカバーされています: https://www.youtube.com/watch?v=BLzNCkPn3ao

Serviceは実際にはすべてnewキーワードに関するもので、これは4つのことを行います。

  1. 新しいオブジェクトを作成します
  2. それをprototypeオブジェクトにリンクします
  3. contextthisに接続します
  4. そしてthisを返します

そしてFactoryはすべてFactory Patternに関するものです - そのサービスのようなオブジェクトを返す関数を含みます。

  1. 他のサービスを使用する能力(依存関係がある)
  2. サービス初期化
  3. 遅延/遅延初期化

そして、この簡単で短いビデオ:Providerhttps://www.youtube.com/watch?v=HvTZbQ_hUZY をカバーしています。

Provider recipeは、アプリが完全に起動または初期化される前に、主にアプリ構成で使用されます。

16
ses

さらに明確にすると、ファクトリーは関数/プリミティブを作成できますが、サービスはできません。これをチェックしてください jsFiddle Epokkに基づいて: http://jsfiddle.net/skeller88/PxdSP/1351/

ファクトリは呼び出すことができる関数を返します。

myApp.factory('helloWorldFromFactory', function() {
  return function() {
    return "Hello, World!";
  };
});

ファクトリは、呼び出すことができるメソッドでオブジェクトを返すこともできます。

myApp.factory('helloWorldFromFactory', function() {
  return {
    sayHello: function() {
      return "Hello, World!";
    }
  };
});

サービスは、呼び出すことができるメソッドを持つオブジェクトを返します。

myApp.service('helloWorldFromService', function() {
  this.sayHello = function() {
     return "Hello, World!";
  };
});

詳細については、私が違いについて書いた記事を参照してください。 http://www.shanemkeller.com/tldr-services-vs-factories-in-angular/ /

16
skeller88

これらすべての記事を読んだ後、それは私のためにもっと混乱を作成しました。

  • インジェクタはレシピを使用して2種類のオブジェクトを作成します。サービスと特殊目的オブジェクト
  • オブジェクトの作成方法を定義する5つのレシピタイプがあります。値、ファクトリ、サービス、プロバイダ、および定数です。
  • 工場とサービスは最も一般的に使用されるレシピです。唯一の違いは、Serviceレシピはカスタム型のオブジェクトに対してうまく機能するのに対し、FactoryはJavaScriptのプリミティブと関数を生成できるという点です。
  • プロバイダーレシピはコアレシピタイプで、他のすべてのレシピは単なる構文糖です。
  • プロバイダは最も複雑なレシピの種類です。グローバル構成を必要とする再利用可能なコードを構築しているのでなければ、それは必要ありません。
  • コントローラーを除くすべての特殊目的オブジェクトは、工場レシピで定義されています。

enter image description here

そして初心者のために理解してください: - これは正しいユースケースではないかもしれませんが、高レベルでこれはこれら3つのユースケースです。

  1. 角度モジュールで使用したい場合はconfig関数を provider のように作成してください。
angular.module('myApp').config(function($testProvider){
$testProvider.someFunction();
})
  1. Ajaxの呼び出しまたはサードパーティの統合は service である必要があります。
  2. データ操作の場合は、 factory のように作成します。

基本的なシナリオでは、factory&Serviceは同じように振る舞います。

13

AngularjSでオブジェクトファクトリのコードテンプレートとして私が思い付いた、いくつかの定型コードがあります。例としてCar/CarFactoryを使用しました。コントローラに簡単な実装コードを作ります。

     <script>
        angular.module('app', [])
            .factory('CarFactory', function() {

                /**
                 * BroilerPlate Object Instance Factory Definition / Example
                 */
                this.Car = function() {

                    // initialize instance properties
                    angular.extend(this, {
                        color           : null,
                        numberOfDoors   : null,
                        hasFancyRadio   : null,
                        hasLeatherSeats : null
                    });

                    // generic setter (with optional default value)
                    this.set = function(key, value, defaultValue, allowUndefined) {

                        // by default,
                        if (typeof allowUndefined === 'undefined') {
                            // we don't allow setter to accept "undefined" as a value
                            allowUndefined = false;
                        }
                        // if we do not allow undefined values, and..
                        if (!allowUndefined) {
                            // if an undefined value was passed in
                            if (value === undefined) {
                                // and a default value was specified
                                if (defaultValue !== undefined) {
                                    // use the specified default value
                                    value = defaultValue;
                                } else {
                                    // otherwise use the class.prototype.defaults value
                                    value = this.defaults[key];
                                } // end if/else
                            } // end if
                        } // end if

                        // update 
                        this[key] = value;

                        // return reference to this object (fluent)
                        return this;

                    }; // end this.set()

                }; // end this.Car class definition

                // instance properties default values
                this.Car.prototype.defaults = {
                    color: 'yellow',
                    numberOfDoors: 2,
                    hasLeatherSeats: null,
                    hasFancyRadio: false
                };

                // instance factory method / constructor
                this.Car.prototype.instance = function(params) {
                    return new 
                        this.constructor()
                                .set('color',           params.color)
                                .set('numberOfDoors',   params.numberOfDoors)
                                .set('hasFancyRadio',   params.hasFancyRadio)
                                .set('hasLeatherSeats', params.hasLeatherSeats)
                    ;
                };

                return new this.Car();

            }) // end Factory Definition
            .controller('testCtrl', function($scope, CarFactory) {

                window.testCtrl = $scope;

                // first car, is red, uses class default for:
                // numberOfDoors, and hasLeatherSeats
                $scope.car1     = CarFactory
                                    .instance({
                                        color: 'red'
                                    })
                                ;

                // second car, is blue, has 3 doors, 
                // uses class default for hasLeatherSeats
                $scope.car2     = CarFactory
                                    .instance({
                                        color: 'blue',
                                        numberOfDoors: 3
                                    })
                                ;
                // third car, has 4 doors, uses class default for 
                // color and hasLeatherSeats
                $scope.car3     = CarFactory
                                    .instance({
                                        numberOfDoors: 4
                                    })
                                ;
                // sets an undefined variable for 'hasFancyRadio',
                // explicitly defines "true" as default when value is undefined
                $scope.hasFancyRadio = undefined;
                $scope.car3.set('hasFancyRadio', $scope.hasFancyRadio, true);

                // fourth car, purple, 4 doors,
                // uses class default for hasLeatherSeats
                $scope.car4     = CarFactory
                                    .instance({
                                        color: 'purple',
                                        numberOfDoors: 4
                                    });
                // and then explicitly sets hasLeatherSeats to undefined
                $scope.hasLeatherSeats = undefined;
                $scope.car4.set('hasLeatherSeats', $scope.hasLeatherSeats, undefined, true);

                // in console, type window.testCtrl to see the resulting objects

            });
    </script>

これはもっと簡単な例です。私は緯度と経度を公開する "Position"オブジェクトを期待するが、異なるオブジェクトプロパティを介して、いくつかのサードパーティライブラリを使用しています。ベンダーコードをハックしたくなかったので、渡した "Position"オブジェクトを調整しました。

    angular.module('app')
.factory('PositionFactory', function() {

    /**
     * BroilerPlate Object Instance Factory Definition / Example
     */
    this.Position = function() {

        // initialize instance properties 
        // (multiple properties to satisfy multiple external interface contracts)
        angular.extend(this, {
            lat         : null,
            lon         : null,
            latitude    : null,
            longitude   : null,
            coords: {
                latitude: null,
                longitude: null
            }
        });

        this.setLatitude = function(latitude) {
            this.latitude           = latitude;
            this.lat                = latitude;
            this.coords.latitude    = latitude;
            return this;
        };
        this.setLongitude = function(longitude) {
            this.longitude          = longitude;
            this.lon                = longitude;
            this.coords.longitude   = longitude;
            return this;
        };

    }; // end class definition

    // instance factory method / constructor
    this.Position.prototype.instance = function(params) {
        return new 
            this.constructor()
                    .setLatitude(params.latitude)
                    .setLongitude(params.longitude)
        ;
    };

    return new this.Position();

}) // end Factory Definition

.controller('testCtrl', function($scope, PositionFactory) {
    $scope.position1 = PositionFactory.instance({latitude: 39, longitude: 42.3123});
    $scope.position2 = PositionFactory.instance({latitude: 39, longitude: 42.3333});
}) // end controller

;

13
James Earlywine

このページと ドキュメンテーション (前回見てから大きく改善されたようです)を参考にして、以下の5つのうち4つのプロバイダのフレーバーを使用する以下の実際の(現実の)世界のデモをまとめました。価値、定数、工場および本格的なプロバイダー。

HTML:

<div ng-controller="mainCtrl as main">
    <h1>{{main.title}}*</h1>
    <h2>{{main.strapline}}</h2>
    <p>Earn {{main.earn}} per click</p>
    <p>You've earned {{main.earned}} by clicking!</p>
    <button ng-click="main.handleClick()">Click me to earn</button>
    <small>* Not actual money</small>
</div>

アプリ

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

// A CONSTANT is not going to change
app.constant('range', 100);

// A VALUE could change, but probably / typically doesn't
app.value('title', 'Earn money by clicking');
app.value('strapline', 'Adventures in ng Providers');

// A simple FACTORY allows us to compute a value @ runtime.
// Furthermore, it can have other dependencies injected into it such
// as our range constant.
app.factory('random', function randomFactory(range) {
    // Get a random number within the range defined in our CONSTANT
    return Math.random() * range;
});

// A PROVIDER, must return a custom type which implements the functionality 
// provided by our service (see what I did there?).
// Here we define the constructor for the custom type the PROVIDER below will 
// instantiate and return.
var Money = function(locale) {

    // Depending on locale string set during config phase, we'll
    // use different symbols and positioning for any values we 
    // need to display as currency
    this.settings = {
        uk: {
            front: true,
            currency: '£',
            thousand: ',',
            decimal: '.'
        },
        eu: {
            front: false,
            currency: '€',
            thousand: '.',
            decimal: ','
        }
    };

    this.locale = locale;
};

// Return a monetary value with currency symbol and placement, and decimal 
// and thousand delimiters according to the locale set in the config phase.
Money.prototype.convertValue = function(value) {

    var settings = this.settings[this.locale],
        decimalIndex, converted;

    converted = this.addThousandSeparator(value.toFixed(2), settings.thousand);

    decimalIndex = converted.length - 3;

    converted = converted.substr(0, decimalIndex) +
        settings.decimal +
        converted.substr(decimalIndex + 1);    

    converted = settings.front ?
            settings.currency + converted : 
            converted + settings.currency; 

    return converted;   
};

// Add supplied thousand separator to supplied value
Money.prototype.addThousandSeparator = function(value, symbol) {
   return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, symbol);
};

// PROVIDER is the core recipe type - VALUE, CONSTANT, SERVICE & FACTORY
// are all effectively syntactic sugar built on top of the PROVIDER construct
// One of the advantages of the PROVIDER is that we can configure it before the
// application starts (see config below).
app.provider('money', function MoneyProvider() {

    var locale;

    // Function called by the config to set up the provider
    this.setLocale = function(value) {
        locale = value;   
    };

    // All providers need to implement a $get method which returns
    // an instance of the custom class which constitutes the service
    this.$get = function moneyFactory() {
        return new Money(locale);
    };
});

// We can configure a PROVIDER on application initialisation.
app.config(['moneyProvider', function(moneyProvider) {
    moneyProvider.setLocale('uk');
    //moneyProvider.setLocale('eu'); 
}]);

// The ubiquitous controller
app.controller('mainCtrl', function($scope, title, strapline, random, money) {

    // Plain old VALUE(s)
    this.title = title;
    this.strapline = strapline;

    this.count = 0;

    // Compute values using our money provider    
    this.earn = money.convertValue(random); // random is computed @ runtime
    this.earned = money.convertValue(0);

    this.handleClick = function() { 
        this.count ++;
        this.earned = money.convertValue(random * this.count);
    };
});

Working デモ

12
net.uk.sweet

この回答はトピック/質問に対応しています

どのようにFactory、Service、Constant - プロバイダーレシピの上に単なる構文上の砂糖があるのでしょうか?

_または_

工場、サービス、およびプロバイダの内部的な類似性

基本的には

あなたがfactory()を作るとき、それはあなたがプロバイダの$getへの2番目の引数で与えられたfunctionをセットしてそれを返す(provider(name, {$get:factoryFn }))、 あなたが得るのはproviderだけですが$get以外のプロパティ/メソッドはありません そのprovider(これを設定できないことを意味します)

工場のソースコード

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

service()を作成するとき、functionをインジェクトするconstructorを含むfactory()を返し(サービスで提供したコンストラクタのインスタンスを返し)、それを返します。

サービスのソースコード

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

そのため、基本的にどちらの場合も、最終的には提供された関数にプロバイダ$ getが設定されますが、configブロックのためにprovider()で元々提供されたように$ get以外のものを追加できます。

12
A.B

私はすばらしい答えをたくさん知っていますが、私の使用経験を共有しなければなりません
1。デフォルトのほとんどの場合はservice
2。特定のインスタンスのサービスを作成するために使用されるfactory

// factory.js ////////////////////////////
(function() {
'use strict';
angular
    .module('myApp.services')
    .factory('xFactory', xFactoryImp);
xFactoryImp.$inject = ['$http'];

function xFactoryImp($http) {
    var fac = function (params) {
        this._params = params; // used for query params
    };

    fac.prototype.nextPage = function () {
        var url = "/_prc";

        $http.get(url, {params: this._params}).success(function(data){ ...
    }
    return fac;
}
})();

// service.js //////////////////////////
(function() {
'use strict';
angular
    .module('myApp.services')
    .service('xService', xServiceImp);
xServiceImp.$inject = ['$http'];

function xServiceImp($http) {  
    this._params = {'model': 'account','mode': 'list'};

    this.nextPage = function () {
        var url = "/_prc";

        $http.get(url, {params: this._params}).success(function(data){ ...
    }       
}
})();

そして使用:

controller: ['xFactory', 'xService', function(xFactory, xService){

        // books = new instance of xFactory for query 'book' model
        var books = new xFactory({'model': 'book', 'mode': 'list'});

        // accounts = new instance of xFactory for query 'accounts' model
        var accounts = new xFactory({'model': 'account', 'mode': 'list'});

        // accounts2 = accounts variable
        var accounts2 = xService;
... 
11
nguyên

パーティーには少し遅れました。しかし、これは、ファクトリ、サービス、およびプロバイダの方法論を使用してAngular JSカスタムサービスを開発する上で習得したい(または明確にしたい)人にとってはより役立つと思いました。

AngularJSカスタムサービスを開発するための工場、サービス、およびプロバイダーの方法論について明確に説明しているこのビデオに出会いました。

https://www.youtube.com/watch?v=oUXku28ex-M

ソースコード: http://www.techcbt.com/Post/353/Angular-JS-basics/how-to-develop-angularjs-custom-service

ここに掲載されたコードは、読者のために上記のソースから直接コピーされています。

「ファクトリ」ベースのカスタムサービスのコードは次のとおりです(これは、httpサービスの呼び出しとともに、同期バージョンと非同期バージョンの両方に対応します)。

var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcFactory',
  function($scope, calcFactory) {
    $scope.a = 10;
    $scope.b = 20;

    $scope.doSum = function() {
      //$scope.sum = calcFactory.getSum($scope.a, $scope.b); //synchronous
      calcFactory.getSum($scope.a, $scope.b, function(r) { //aynchronous
        $scope.sum = r;
      });
    };

  }
]);

app.factory('calcFactory', ['$http', '$log',
  function($http, $log) {
    $log.log("instantiating calcFactory..");
    var oCalcService = {};

    //oCalcService.getSum = function(a,b){
    //  return parseInt(a) + parseInt(b);
    //};

    //oCalcService.getSum = function(a, b, cb){
    //  var s = parseInt(a) + parseInt(b);
    //  cb(s);
    //};

    oCalcService.getSum = function(a, b, cb) { //using http service

      $http({
        url: 'http://localhost:4467/Sum?a=' + a + '&b=' + b,
        method: 'GET'
      }).then(function(resp) {
        $log.log(resp.data);
        cb(resp.data);
      }, function(resp) {
        $log.error("ERROR occurred");
      });
    };

    return oCalcService;
  }
]);

カスタムサービスのための「サービス」方法論のためのコード(これは 'factory'に非常に似ていますが、構文の観点からは異なります):

var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcService', function($scope, calcService){
        $scope.a = 10;
        $scope.b = 20;

        $scope.doSum = function(){
                //$scope.sum = calcService.getSum($scope.a, $scope.b);
                
                calcService.getSum($scope.a, $scope.b, function(r){
                        $scope.sum = r;
                });             
        };

}]);

app.service('calcService', ['$http', '$log', function($http, $log){
        $log.log("instantiating calcService..");
        
        //this.getSum = function(a,b){
        //      return parseInt(a) + parseInt(b);
        //};

        //this.getSum = function(a, b, cb){
        //      var s = parseInt(a) + parseInt(b);
        //      cb(s);
        //};

        this.getSum = function(a, b, cb){
                $http({
                        url: 'http://localhost:4467/Sum?a=' + a + '&b=' + b,
                        method: 'GET'
                }).then(function(resp){
                        $log.log(resp.data);
                        cb(resp.data);
                },function(resp){
                        $log.error("ERROR occurred");
                });
        };

}]);

カスタムサービス用の「プロバイダ」メソドロジのコード(設定可能なサービスを開発したい場合はこれが必要です)。

var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcService', function($scope, calcService){
        $scope.a = 10;
        $scope.b = 20;

        $scope.doSum = function(){
                //$scope.sum = calcService.getSum($scope.a, $scope.b);
                
                calcService.getSum($scope.a, $scope.b, function(r){
                        $scope.sum = r;
                });             
        };

}]);

app.provider('calcService', function(){

        var baseUrl = '';

        this.config = function(url){
                baseUrl = url;
        };

        this.$get = ['$log', '$http', function($log, $http){
                $log.log("instantiating calcService...")
                var oCalcService = {};

                //oCalcService.getSum = function(a,b){
                //      return parseInt(a) + parseInt(b);
                //};

                //oCalcService.getSum = function(a, b, cb){
                //      var s = parseInt(a) + parseInt(b);
                //      cb(s);  
                //};

                oCalcService.getSum = function(a, b, cb){

                        $http({
                                url: baseUrl + '/Sum?a=' + a + '&b=' + b,
                                method: 'GET'
                        }).then(function(resp){
                                $log.log(resp.data);
                                cb(resp.data);
                        },function(resp){
                                $log.error("ERROR occurred");
                        });
                };              

                return oCalcService;
        }];

});

app.config(['calcServiceProvider', function(calcServiceProvider){
        calcServiceProvider.config("http://localhost:4467");
}]);

最後に、上記のサービスのいずれかと連携するUI:

<html>
<head>
        <title></title>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js" ></script>
        <script type="text/javascript" src="t03.js"></script>
</head>
<body ng-app="app">
        <div ng-controller="emp">
                <div>
                        Value of a is {{a}},
                        but you can change
                        <input type=text ng-model="a" /> <br>

                        Value of b is {{b}},
                        but you can change
                        <input type=text ng-model="b" /> <br>

                </div>
                Sum = {{sum}}<br>
                <button ng-click="doSum()">Calculate</button>
        </div>
</body>
</html>
10
user203687

わかりやすくするために、AngularJSのソースから、サービスがファクトリ関数を呼び出し、次にファクトリ関数がプロバイダ関数を呼び出すことを確認できます。

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

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

メモリの目的に基づいて、コントローラは必要なときにだけインスタンス化され、そうでないときは破棄されます。このため、ルートを切り替えたりページをリロードするたびに、Angularは現在のコントローラをクリーンアップします。ただし、サービスは、アプリケーションの存続期間中データを保持し続けるための手段を提供しながら、一貫した方法でさまざまなコントローラ間でデータを使用することもできます。

Angularは、独自のサービスを作成および登録するための3つの方法を提供します。

1)工場

2)サービス

3)プロバイダー

Factory :factoryはオブジェクトを作成する前にロジックを追加することを可能にする簡単な関数です。作成したオブジェクトを返します。

それは単なるクラスのような関数の集まりです。したがって、コンストラクター関数で使用しているときは、異なるコントローラーでインスタンス化できます。

Service :serviceはnewキーワードを使ってオブジェクトを作成するコンストラクタ関数です。このキーワードを使用して、サービスオブジェクトにプロパティと機能を追加できます。工場とは異なり、何も返されません。

これはシングルトンオブジェクトです。アプリケーション全体で単一のオブジェクトを共有する必要があるときに使用します。たとえば、認証済みユーザーの詳細などです。

プロバイダ :プロバイダは設定可能なサービスオブジェクトを作成するために使用されます。 $ get()関数を使用して値を返します。

サービスオブジェクトを利用可能にする前に、モジュール単位の設定を提供する必要がある場合。

次のコードを実行して出力を確認してください。

<!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>
9

簡単な方法でAngularJSのビジネスロジックを処理する3つの方法について説明しましょう。(YaakovのCoursera AngularJSコースに触発された

SERVICE

構文:

app.js

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

 ServiceExampleController.$inject = ['NameOfTheService'] //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. シングルトン :複数のモジュールに注入された場合、すべてのインスタンスが1つの特定のインスタンスのみにアクセスできます。だからこそ、異なるコントローラ間でデータを共有するのはとても便利です。

工場

まず構文を見てみましょう。

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

上記の2つをコントローラーで使用します。

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

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

工場の特徴:

  1. 工場設計パターンに従います。工場は新しい物や機能を生み出す中心的な場所です。
  2. シングルトンだけでなく、カスタマイズ可能なサービスも生み出します。
  3. .service()メソッドはfactoryで、常に同じタイプのサービスを生成します。これはシングルトンであり、その動作を設定する簡単な方法はありません。その.service()メソッドは通常、設定を一切必要としないものへのショートカットとして使用されます。

PROVIDER

もう一度構文を見てみましょう。

angular.module('ProviderModule', [])
.controller('ProviderModuleController', ProviderModuleController)
.provider('ServiceProvider', ServiceProvider)
.config(Config); //optional

Config.$inject = ['ServiceProvider'];
function Config(ServiceProvider) {
  ServiceProvider.defaults.maxItems = 10; //some default value
}


ProviderModuleController.$inject = ['ServiceProvider'];
function ProviderModuleController(ServiceProvider) {
  //some methods
}

function ServiceProvider() {
  var provider = this;

  provider.defaults = {
    maxItems: 10
  };

  provider.$get = function () {
    var someList = new someListService(provider.defaults.maxItems);

    return someList;
  };
}

}

プロバイダの機能:

  1. プロバイダはAngularでサービスを作成する最も柔軟な方法です。
  2. 動的に構成可能なファクトリを作成できるだけでなく、ファクトリをプロバイダメソッドで使用するときに、アプリケーション全体のブートストラップ時にファクトリを1回だけカスタム構成することもできます。
  3. これで、ファクトリをカスタム設定でアプリケーション全体で使用できます。つまり、アプリケーションが起動する前にこのファクトリを設定できます。実際のところ、角度付きの文書では、.serviceまたは.factoryメソッドを使ってサービスを設定するときに、プロバイダーメソッドが舞台裏で実行されるものであると述べられています。
  4. $getは、プロバイダインスタンスに直接関連付けられている関数です。その関数はfactory関数です。言い換えれば、それは私たちが.factoryメソッドに provide を提供するのに使っているものとちょうど同じです。その機能の中で、私たちは私たち自身のサービスを作り出します。 この$getプロパティは関数で、プロバイダをプロバイダにするものです _。 AngularJSは、プロバイダが$ getプロパティを持ち、その値がAngularがファクトリ関数として扱う関数であることを期待しています。 しかし、このプロバイダ全体の設定を非常に特別なものにしているのは、サービスプロバイダの内部に何らかのconfigオブジェクトを提供できるという事実と、通常は後でアプリケーション全体を設定できるステップで上書きできるデフォルトが付属するということです。
9
Pritam Banerjee

Factory: あなたが実際にファクトリの中にオブジェクトを作成してそれを返すファクトリ。
service: thisキーワードを使用して機能を定義する標準機能のみを使用するサービス。
provider: あなたが定義する$ getプロバイダがあり、それを使ってデータを返すオブジェクトを取得することができます。

7
MR Kesavan

基本的に、プロバイダ、ファクトリ、およびサービスはすべてサービスです。 Factoryは、必要なのが$ get()関数だけである場合はサービスの特殊なケースです。

サービス、工場、およびプロバイダーの主な違いはそれらの複雑さです。サービスは最も単純な形式であり、ファクトリはもう少し堅牢であり、そしてプロバイダは実行時に設定可能です。

それぞれを使用する場合の概要は次のとおりです。

工場 :あなたが提供している価値は他のデータに基づいて計算される必要があります。

Service :あなたはメソッドでオブジェクトを返しています。

プロバイダ :あなたは、それが作成される前に作成される予定のオブジェクトを、設定段階で設定できるようにしたいのです。アプリが完全に初期化される前に、主にアプリの設定でプロバイダを使用します。

7
eGhoul

1.Servicesはシングルトンオブジェクトで、必要に応じて作成され、アプリケーションのライフサイクルが終了するまで(ブラウザが閉じられるまで)クリーンアップされません。コントローラは不要になると破壊されてクリーンアップされます。

2.サービスを作成する最も簡単な方法は、factory()メソッドを使用することです。 factory()メソッドを使用すると、サービス関数とサービスデータを含むオブジェクトを返すことによってサービスを定義できます。サービス定義関数は、$ httpや$ qなど、注入可能なサービスを配置する場所です。例:

angular.module('myApp.services')
.factory('User', function($http) { // injectables go here
var backendUrl = "http://localhost:3000"; var service = {
    // our factory definition
user: {},
setName: function(newName) {
      service.user['name'] = newName;
    },
setEmail: function(newEmail) { service.user['email'] = newEmail;
},
save: function() {
return $http.post(backendUrl + '/users', { user: service.user
}); }
};
return service; });

我々のアプリでfactory()を使う

実行時に必要な場所にファクトリを注入するだけなので、ファクトリをアプリケーションで使用するのは簡単です。

angular.module('myApp')
.controller('MainController', function($scope, User) {
  $scope.saveUser = User.save;
});
  1. 一方、service()メソッドを使用すると、コンストラクタ関数を定義してサービスを作成できます。生のJavaScriptオブジェクトの代わりに、プロトタイプオブジェクトを使用してサービスを定義できます。 factory()メソッドと同様に、インジェクタブルも関数定義に設定します。
  2. サービスを作成するための最低レベルの方法はprovide()メソッドを使うことです。これが、.config()関数を使用して構成できるサービスを作成する唯一の方法です。前のメソッドとは異なり、インジェクタブルを定義済みのthis。$ get()関数定義に設定します。
4