web-dev-qa-db-ja.com

どのようにしてサービスをステートレスにしますか?

ドメイン駆動設計を行う場合、サービスはステートレスであることをお勧めします。 DDDを行う場合、いくつかの種類のサービスがあります。

  • アプリケーションサービス。
  • ドメインサービス。
  • インフラストラクチャサービス。
  • 工場、リポジトリ、仕様など...

サービスをステートレスにするにはどうすればよいですか?

それは、クラスにインスタンス変数があってはならないという意味ですか?サービス/クラスをステートレスにするためのガイドラインはありますか?

ステートフルサービスとステートレスサービスの違いを示すコードサンプルを実際に使用できます。

例:(このクラスはステートフルかどうか)

_Class DataToCsvFileGenerator{

    private String filePath;
    private ResultSet data;

    public String createCsv(ResultSet data){
       this.data=data;

       this.createLocalFile();
       this.loadDataIntoFile();

       return this.filePath;
    }

    private void createLocalFile(){    
        this.filePath=//... logic to create file    
    }

    private void loadDataIntoFile(){    
        //function uses this.filePath to load data    
    }
}
_

createCsv()への後続の呼び出しは、以前の呼び出しの影響を受けないことに注意してください。

7
Songo

ステートレスサービスは、呼び出しごとに情報を追跡しません。つまり、メソッドを呼び出した結果としてインスタンス変数を設定することはできません。ロガーや操作に必要なプロパティなど、サービスが必要とするインスタンス変数を持つことができます。

カスタマーサービスは、顧客に関する情報を電話から電話へと追跡しません。顧客の追跡に必要な情報はすべて外部に保存され、必要に応じて取得されます。通常、データベースは永続化のために使用されますが、場合によってはWebサービスがCookieまたはその他のクライアント側メカニズムを使用することがあります。

クラスはステートフルであるように見えますが、ステートは役に立ちません。ただし、追加のメソッドにより、インスタンス変数をパブリックにアクセスできるようにすることができます。 IDEでジェネレータを実行するだけの簡単な変更で可能です。次の書き換えはステートレスです。ロガー変数はロガーへの参照を保持し、クラスの状態を含まないことに注意してくださいロガーの初期化と使用は省略されました。

 Class DataToCsvFileGenerator {
 
 Static Logger logger; 
 
 public String createCsv(ResultSet data){
 String filePath = createLocalFile(); 
 this.loadDataIntoFile(filePath、data); 
 
 return filePath; 
} 
 
 private String createLocalFile(){
 string filePath = // ...ファイルを作成するロジック
 filePathを返します。 
} 
 
 private void loadDataIntoFile(String filePath、ResultSet data){
 //関数はfilePathを使用してデータをロードします
} 
}
10
BillThor

確かに、DDDの本ではそれが明確にされていませんが、「ステートレス」とある場合、「persistentまたはlong-livedステートなし」を意味します。したがって、サービスオブジェクトareは、何らかの方法で永続化または外部化された状態でない限り、インスタンス変数/フィールドで状態を保持できます。

本が扱う状態は、statefullnessについて議論するときに、ドメインentitiesおよびvalue objectsに保持されている状態です。通常、この状態は外部ストレージに保存され、そこから再構成されます。 (リレーショナルデータベース、ファイル)、または任意の長期間メモリに保持およびは、さまざまなスレッド(「オンライン顧客カート」オブジェクトなど)からアクセスできます。

特に、存続期間の短いサービスオブジェクト(つまり、真のオブジェクト)は、(通常)単一のスレッドによって作成され、同じスレッドからのみアクセスされるため、インスタンスの状態を持つのに特に適しています。

6
Rogério

もちろん、クラスにインスタンス変数を含めることはできますが、ステートレスサービスがある場合、次の呼び出しではクラスインスタンスは存在しません。

古典的なステートフルサービスは、記事を追加できるカートです。これらのステートフルサービスメソッドを使用する場合:

  • createCart
  • addArticleToCart(数量、記事ID)
  • removeArticleFromCart(数量、記事ID)
  • ....

呼び出しのパラメータとして必要な情報をすべて提供すれば、サービスをステートレスにすることができます。

  • createCartはcartIDを返します
  • addArticleToCart(カートID、数量、記事ID)
  • removeArticleFromCart(カートID、数量、記事ID)

statefull cartServiceは、cartIDを記憶します。

ステートレスなCartServiceは、サービスコールのたびにcartIDを取得します。

1
k3b

(このクラスはステートフルですか?)

はい、ステートフルです。

今ではありません...

    Class DataToCsvFileGenerator{

      public string createCsv(ResultSet data, string filePath){
         string fullFilePath = string.Empty;

         fullFilePath = this.createLocalFile(filePath);
         this.loadDataIntoFile(data, fullFilePath);

         return fullFilePath;
      }

      private string createLocalFile(string filePath){    
          filePath=//... logic to create file    
      }

      private void loadDataIntoFile(ResultSet data, string filePath){    
          //function uses filePath to load data    
      }
    }
1
radarbob

あなたの特定のケースでは、それは@radarbobが言ったように行われるべきです。

しかし、より一般的な方法で答えると、私のプロジェクトではほとんどのサービスが生のデザインについて話す場合はステートフルですが、実際には私がDIフレームワーク(私の場合はSpring)を使用していると考えると、 m他のサービスのみを注入します。それら自体は、このようにSpringによって構築されます。完了したら、フィールドの1つを変更することはありません。

したがって、設計上はステートフルですが、使用方法では、ステートレスオブジェクトと同じように動作します。

例:

public class PeopleService{
    private RightsService rightsService;
    //+setter to init with spring
}

RightsServiceを変更する可能性があるため、これはステートフルです。変更しない限り、ステートレスオブジェクトと同じ動作になります(RightsServiceが同じ動作をしていると仮定)。

注:セッターを使用する代わりに、純粋になりたい場合は、finalフィールドを使用してコンストラクターで初期化できます。このようにして、ステートレスオブジェクトを実際に作成します。

0
Walfrat