4

だから私はHybris、Springなどを使ったウェブプロジェクトを持っています。

自動生成されるいくつかのクラスがあります。フィールドを設定するために、自動生成され、別のクラスからいくつかのメソッドを継承する1つのモデルクラスがあるとしましょう。

単体テストを作成する場合、Builder パターンを使い始めると便利ですか? というのも、私は Employee(int id, String name) などのコンストラクターを持っていないため、それらを設定するための継承されたメソッド (setId(int id) など) しか持っていません。

たとえば、このモデルの Builder クラスを作成する場合、メソッド .withId(int id) および .withName(String name) と、setter メソッドを実行する build() メソッドを用意します。

したがって、最終的に私のテストクラスでは次のようになります。

EmployeeBuilder eb = new EmployeeBuilder();
Employee emp = eb.withId(123)
                 .withName("John")
                 .build();

しかし、私はすでにセッターメソッドを持っているので、私は通常持っています:

Employee emp = new Employee();
emp.setId(123);
emp.setName("John");

では、この場合、努力する価値は本当にあるのでしょうか? それとも、私が本当に理解していないことがありますか?

ありがとう!

4

4 に答える 4

6

あなたの質問に答える前に、ビルダーパターンについて説明したいと思います。

ビルダー パターンは通常、オーバーロードされたコンストラクターが多数ある場合に使用されます (コンストラクター アンチパターンのテレスコーピング)。例えば

public class Employee {

   public Employee(String firstName, String lastName){
       ...
   }

   public Employee(String firstName, String lastName, Sex sex){
       ...
   }


   public Employee(String firstName, String lastName, String salutation) {
       ...
   }
}

この場合、クライアント コードは、そのデータに応じて呼び出すコンストラクタを決定する必要があります。firstNameがあり、をlastName呼び出す必要がある場合new Employee(firstName, lastName)。しかない場合は、firstNameを呼び出す必要がありEmployee(String firstName)ます。そのため、クライアント コードには多数の if/then/else が含まれている可能性があります。例えば

Employee employee = null;
if(firstName != null && lastName != null && sex != null){
    employee = new Employee(firstName, lastName, sex);
} else if(firstName != null && lastName != null && salutation != null){
    employee = new Employee(firstName, lastName, salutation );
} else {
  .....
}

Employeeこの例のクラスの設計には、firstNameおよびlastNameの必須属性が含まれていEmployeeます。これは、すべてのコンストラクターがそれらを必要とするためです。属性sexと属性saluationはオプションです。クライアント コードがどのコンストラクターを呼び出すかを決定する場合、これは決定プロセスがクライアント コード全体で繰り返されることも意味します。たとえば、クライアントがfirstNamelastNamesexおよびsalutationどのコンストラクタを呼び出す必要があるかを知っている場合は? または?new Employee(firstName, lastName, sex)_new Employee(firstName, lastName, saluation)

コンストラクターの解決をカプセル化するには、ビルダー パターンを使用することをお勧めします。

public class EmployeeBuilder {

      public EmployeeBuilder(String firstName, String lastName){

      }

      public void setSex(Sex sex){ ... }

      public void setSalutation(Salutation salutation){ ... }

      public Employee build(){
          if(salutation != null){
             return new Emplyoee(firstName, lastName, salutation);
          } else if(sex != null){
             return new Emplyoee(firstName, lastName, sex); 
          } else {
             return new Emplyoee(firstName, lastName);
          }
      }
}

これにより、クライアント コードが読みやすくなり、コンストラクター呼び出しの決定がカプセル化されます。例えば

EmployeeBuidler employeeBuilder = new EmployeeBuilder(firstName, lastName);

Sex sex = ...; 
String salutation = ...;

employeeBuilder.setSex(sex);
employeeBuilder.setSalutation(salutation);

Employee employee = employeeBuilder.build();

質問に戻る

では、この場合、努力する価値は本当にあるのでしょうか?

単体テストEmployeeでは、いくつかの属性を持つオブジェクトを作成し、他の属性をデフォルト値に設定する必要がある場合があります。この場合、ビルダーパターンを使用することをお勧めします。たとえば、明確にするためにビルダーに名前を付けEmployeeDefaultValuesBuilderます。

Employee他の従業員オブジェクト (テンプレート) に基づいてを作成することもできます。この場合、別のコンストラクターを に追加しEmployeeBuilderます。例えば

public EmployeeBuilder(Employee template){
  // initialize this builder with the values of the template
}

したがって、構築ロジックをカプセル化するか、読みやすさを向上させる場合は、努力する価値があります。

于 2015-10-20T08:49:17.067 に答える
4

Builder パターンは次の場合に役立ちます。

  • 不変クラス。ここではそうではありません。
  • わずかな違いで同じものを多数構築する必要がある場合。ここでもそうではありません。
  • 「流暢な」API を作成します。
  • 複雑なビルドを必要とする複雑なオブジェクトがある場合。

では、この場合、努力する価値は本当にあるのでしょうか?

あなたが投稿したものを考えると、私はノーと言います。

最後に、 Project LombokGoogle Autoなどの適切な API を使用すれば、必要な作業はわずかです。(また、ビルダーを使用して伸縮コンストラクターのアンチパターンを非表示にしている場合、パターンを悪用していると思いますが、ちょっと...)

于 2015-10-20T09:17:22.483 に答える
2

Builder パターンは、次の 2 つの場合に役立ちます。

  • 結果のオブジェクトは不変です(すべてのフィールドは ですfinal)-ビルダーは、多くの引数を持つコンストラクターよりも優れています。
  • 作成されたオブジェクトが有効であり、矛盾するオブジェクトが作成されないようにする必要があります。たとえば、longitudeフィールドが設定されていても設定されていlatitudeない場合、build() メソッドからエラーをスローできます。
于 2015-10-20T08:51:32.190 に答える