静的ファクトリーメソッドとは何ですか?


261

「静的ファクトリ」メソッドとは何ですか?


別の静的ファクトリーメソッドは、依存性注入を使用しています。
CMCDragonkai 2014年

1
@ThangPham Jason Owenの答えは、ファクトリメソッドパターンについて話していると主張しているため、誤りです。これは、実際に話している静的なファクトリメソッドパターンとは非常に異なります。したがって、実際の質問にうまく答えることはできますが、現在の状態では受け入れられないと思います。これは、無関係なパターンをもたらし、2つのパターンの違いについてすでに信じられているほどよくある混乱を招くためです。
セオドアマードック2014

@CMCDragonkai依存性注入と静的ファクトリーは違うと思います。依存関係を注入するために依存関係をインスタンス化する場合でも、静的ファクトリーが必要になることがあります。
Karan Khanna

回答:


126

データベース接続はリソースを大量に消費するため、データベースへの直接アクセスは提供しません。したがってgetDbConnection、制限を下回った場合に接続を作成する静的なファクトリメソッドを使用します。それ以外の場合は、「予備」接続を提供しようとし、接続がない場合は例外で失敗します。

public class DbConnection{
   private static final int MAX_CONNS = 100;
   private static int totalConnections = 0;

   private static Set<DbConnection> availableConnections = new HashSet<DbConnection>();

   private DbConnection(){
     // ...
     totalConnections++;
   }

   public static DbConnection getDbConnection(){

     if(totalConnections < MAX_CONNS){
       return new DbConnection();

     }else if(availableConnections.size() > 0){
         DbConnection dbc = availableConnections.iterator().next();
         availableConnections.remove(dbc);
         return dbc;

     }else {
         throw new NoDbConnections();
     }
   }

   public static void returnDbConnection(DbConnection dbc){
     availableConnections.add(dbc);
     //...
   }
}

私が正しく理解している場合、availableConnections.add(db)をメソッドreturnDbConnection(DbConnection db)に追加できますか?
Haifeng Zhang

@haifzhan、それは本当に完全であることを意図していませんが、大丈夫です。
Matthew Flaschen、2014年

@MatthewFlaschenはまた、接続が返されている間にtotalConnectionsをデクリメントする必要がありますか?
ローリングストーン

@Sridhar、いいえ、存在する接続の数です(MAX_CONNSを超えて作成されないように追跡されます)。循環している数ではありません。
Matthew Flaschen、2015年

@MatthewFlaschenメソッドは、DbConnectionがCloseableの場合、sonarcubeによってblocker-bugとしてキャッチされます。
Awan Biru

477

静的Factory Methodパターンは、カプセル化するオブジェクトを作成する方法です。ファクトリメソッドがなければ、クラスのコンストラクタを直接呼び出すだけですFoo x = new Foo()。このパターンでは、代わりにファクトリメソッドを呼び出します Foo x = Foo.create()。コンストラクターはプライベートとしてマークされているstaticため、クラス内からしか呼び出せず、ファクトリーメソッドは、最初にオブジェクトがなくても呼び出すことができるようにマークされています。

このパターンにはいくつかの利点があります。1つは、ファクトリーが多くのサブクラス(またはインターフェースのインプリメンター)から選択してそれを返すことができることです。このようにして、呼び出し元は、潜在的に複雑なクラス階層を認識または理解する必要なく、パラメーターを介して必要な動作を指定できます。

別の利点は、MatthewとJamesが指摘したように、接続などの限られたリソースへのアクセスを制御することです。これは、再利用可能なオブジェクトのプールを実装する方法です。オブジェクトの構築、使用、破棄の代わりに、構築と破棄が高価なプロセスである場合は、一度構築してリサイクルする方が理にかなっています。ファクトリメソッドは、インスタンス化されている既存の未使用のインスタンス化オブジェクトがある場合はそれを返し、オブジェクト数が下限しきい値を下回っている場合は1つを構築するか、例外をスローするかnull、上限しきい値を超えている場合に返します。

ウィキペディアの記事にあるように、複数のファクトリメソッドでも、同様の引数タイプの異なる解釈が可能です。通常、コンストラクターの名前はクラスと同じです。つまり、特定の署名を持つコンストラクターは1つしか持てません。ファクトリーはそれほど制約されていません。つまり、同じ引数タイプを受け入れる2つの異なるメソッドを持つことができます。

Coordinate c = Coordinate.createFromCartesian(double x, double y)

そして

Coordinate c = Coordinate.createFromPolar(double distance, double angle)

Rasmusが指摘するように、これは読みやすさを向上させるためにも使用できます。


32
静的なファクトリーメソッドは、Design Patterns [Gamma95、p。107]。この項目で説明する静的ファクトリメソッドには、デザインパターンに直接相当するものはありません。
Josh Sunshine

この答えに対する私にとっての見返りは、プール可能なオブジェクトへの参照です。これがまさにファクトリー・メソッド・パターンの使い方です。オブジェクトのライフサイクルの制御に役立つファクトリメソッドが用意されています。「作成」は、プールからオブジェクトをプルするか、プールが空の場合は新しいインスタンスを作成します。「破棄」は、将来の再利用のためにプールにオブジェクトを返します。
MutantXenu 2013年

2
この投稿で「ファクトリー・メソッド・パターン」と言っているところはどこでも、「静的なファクトリー・メソッド・パターン」を実際に使用しているはずです。間違った用語を使用しています。また、あなたが話しているパターンとは異なるパターンでウィキペディアの記事にリンクしています。Factoryメソッドパターンは、ファクトリオブジェクトを受け入れることにより、単一のアルゴリズムがインターフェイスのインスタンスを生成および処理できるように、ファクトリインターフェイスを実装するいくつかのファクトリオブジェクトを使用する必要があるため、おそらく「ファクトリインターフェイス」パターンと呼ばれるべきでした。特定の必要なサブクラスを生成できます。
セオドアマードック2014

8
@TheodoreMurdockに同意します。間違った用語を使用しています。あなたが話しているのは、ジョシュア・ブロッホの「静的ファクトリー法」ですが、GoFの「ファクトリー法パターン」という用語を使用しています。他の人が誤解しないように編集してください。
emeraldhieu 2014

1
コンストラクタはプライベートである必要はないことに注意してください。クラスは、パブリック静的ファクトリメソッドとコンストラクタの両方を提供できます。
Kevin

171

注意!「静的ファクトリー・メソッドは、ファクトリー・メソッド・パターンと同じではありません」(c)効果的なJava、Joshua Bloch。

ファクトリメソッド:「オブジェクトを作成するためのインターフェイスを定義しますが、インターフェイスを実装するクラスにインスタンス化するクラスを決定させます。ファクトリメソッドにより、クラスはインスタンス化をサブクラスに遅延させることができます」(c)GoF。

「静的ファクトリメソッドは、クラスのインスタンスを返す単純な静的メソッドです。」(c)効果的なJava、Joshua Bloch。通常、このメソッドは特定のクラス内にあります。

違い:

静的ファクトリメソッドの重要なアイデアは、オブジェクトの作成を制御し、それをコンストラクタから静的メソッドに委任することです。作成するオブジェクトの決定は、メソッドの外で行われる抽象ファクトリの場合と同じです(一般的なケースですが、常にではありません)。一方、ファクトリメソッドの重要な(!)アイデアは、クラスのどのインスタンスをファクトリメソッド内に作成するかの決定を委任することです。たとえば、クラシックシングルトンの実装は、静的ファクトリメソッドの特殊なケースです。一般的に使用される静的ファクトリメソッドの例:

  • valueOf
  • getInstance
  • newInstance

new A()とA.newInstance()の違いを教えてください。A.newInstanceの内部で何をすべきか?
シェン

69

読みやすさは、静的なファクトリメソッドによって改善できます。

比較する

public class Foo{
  public Foo(boolean withBar){
    //...
  }
}

//...

// What exactly does this mean?
Foo foo = new Foo(true);
// You have to lookup the documentation to be sure.
// Even if you remember that the boolean has something to do with a Bar
// you might not remember whether it specified withBar or withoutBar.

public class Foo{
  public static Foo createWithBar(){
    //...
  }

  public static Foo createWithoutBar(){
    //...
  }
}

// ...

// This is much easier to read!
Foo foo = Foo.createWithBar();

だから私はあなたの例を実装しようとしましたが、これがどのように機能するのかわかりません。Fooクラス内の2つのプライベートコンストラクターを呼び出すことになっている2つのメソッドcreateWithBarとcreateWithoutBarはどうですか?
Essej 16

@Baxtex:はい。それぞれがプライベートコンストラクターを呼び出します。おそらく同じもの: private Foo(boolean withBar){/*..*/} public static Foo createWithBar(){return new Foo(true);} public static Foo createWithoutBar(){return new Foo(false);}
Rasmus Faber

これはあまり「スケール」ではないと思います。3つ以上のパラメーターがある場合、どのようにこのアイデアを使用し、メソッドに適切な名前を付けることができますか?
Dherik、2016年

@Dherik:次に、おそらく代わりにビルダーパターンを使用する必要があります。new FooBuilder()。withBar()。withoutFoo()。withBaz()。build();
Rasmus Faber

21
  • コードを明確にすることができるコンストラクタとは異なり、名前があります。
  • 呼び出しのたびに新しいオブジェクトを作成する必要はありません。必要に応じて、オブジェクトをキャッシュして再利用できます。
  • 戻り値の型のサブタイプを返すことができます-特に、実装クラスが呼び出し元に知られていないオブジェクトを返すことができます。これは、静的なファクトリメソッドの戻り値の型としてインターフェイスを使用する多くのフレームワークで非常に貴重で広く使用されている機能です。

http://www.javapractices.com/topic/TopicAction.do?Id=21から


18

それはすべて、保守性に要約されます。これを配置する最善の方法は、newキーワードを使用してオブジェクトを作成するときは常に、作成しているコードを実装に結合することです。

ファクトリパターンを使用すると、オブジェクトの作成方法と、オブジェクトの操作方法を分離できます。コンストラクターを使用してすべてのオブジェクトを作成する場合、基本的には、オブジェクトを使用するコードをその実装にハードワイヤリングします。オブジェクトを使用するコードは、そのオブジェクトに「依存」しています。これは表面上は大したことではないように思えるかもしれませんが、オブジェクトが変更された場合(コンストラクターのシグネチャを変更したり、オブジェクトをサブクラス化したりすることを考えてください)、前に戻ってあらゆる場所に配線し直す必要があります。

今日の工場では、多くのボイラープレートコードを必要とするため、依存性注入を使用することに賛成しています。Dependency Injectionは基本的にはファクトリーと同等ですが、オブジェクトを宣言的に接続する方法を(構成またはアノテーションを介して)指定できます。


3
工場は救済が必要だと言っていますか?;)
ジョンファレル

4
ははは!この日と年齢では、誰でも救済措置を使用できると思います... :)
cwash 2009年

11

クラスのコンストラクターがプライベートの場合、クラスのオブジェクトをその外部から作成することはできません。

class Test{
 int x, y;
 private Test(){
  .......
  .......
  }
}

上記のクラスのオブジェクトを外部から作成することはできません。したがって、クラスの外部からx、yにアクセスすることはできません。次に、このクラスの使用は何ですか?
これがAnswer:FACTORYメソッドです。
上記のクラスに以下のメソッドを追加します

public static Test getObject(){
  return new Test();
}

これで、このクラスのオブジェクトを外部から作成できるようになりました。方法のように...

Test t = Test.getObject();

したがって、プライベートコンストラクターを実行してクラスのオブジェクトを返す静的メソッドはFACTORYメソッドと呼ばれ
ます。


1
なぜそれを「解決策」と呼ぶのですか?プライベートコンストラクターの宣言は「問題」ではなく、設計パターンです。
Ojonugwa Jude Ochalifu

1
更新しました。とにかくありがとう
Santhosh

こんにちは@Santhosh私が心配しているのは、プライベートコンストラクターをパブリックにしないでください。サブクラスを作成したくない場合は問題ありませんが、プライベートコンストラクタを作成するつもりがない場合はStatic Factory Method、パブリックコンストラクタよりも優れている点はありますか?
シェン

9

私が知っていることについて、この投稿にいくつかの光を追加すると思いました。この手法は、で広く使用されていますrecent android project。代わりにcreating objects using new operatorを使用static methodしてクラスをインスタンス化することもできます。コードリスト:

//instantiating a class using constructor
Vinoth vin = new Vinoth(); 

//instantiating the class using static method
Class Vinoth{
  private Vinoth(){
  }
  // factory method to instantiate the class
  public static Vinoth getInstance(){
    if(someCondition)
        return new Vinoth();
  }
}

静的メソッドは条件付きオブジェクトの作成をサポートします:コンストラクターを呼び出すたびにオブジェクトが作成されますが、そうしたくない場合もあります。ある条件のみをチェックしてから、新しいオブジェクトを作成したいとします。条件が満たされていなければ、毎回Vinothの新しいインスタンスを作成することはありません。

効果的なJavaから取った別の例。

public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
}

このメソッドは、ブールプリミティブ値をブールオブジェクト参照に変換します。このBoolean.valueOf(boolean)メソッドは、オブジェクトを作成することはないことを示しています。能力static factory methods繰り返しから同じオブジェクトを返すためには、invocationsクラスがインスタンスがいつでも存在するものを厳密に制御を維持することができます。

Static factory methods異なり、ということですconstructors、彼らは返すことができるobjectいずれかのsubtype彼らの戻り値の型のを。この柔軟性のアプリケーションの1つは、APIがクラスをパブリックにすることなくオブジェクトを返すことができることです。この方法で実装クラスを非表示にすると、非常にコンパクトなAPIになります。

Calendar.getInstance()は上記の優れた例であり、ロケールa BuddhistCalendarJapaneseImperialCalendarまたはデフォルトで1に応じて作成されますGeorgian

私が考えることができるもう1つの例はSingleton pattern、コンストラクターをプライベートにして、getInstance使用可能なインスタンスが常に1つしかないことを確認する独自のメソッドを作成することです。

public class Singleton{
    //initailzed during class loading
    private static final Singleton INSTANCE = new Singleton();

    //to prevent creating another instance of Singleton
    private Singleton(){}

    public static Singleton getSingleton(){
        return INSTANCE;
    }
}

4

ファクトリメソッドは、オブジェクトのインスタンス化を抽象化するメソッドです。一般に、ファクトリは、インターフェイスを実装するクラスの新しいインスタンスが必要であることがわかっているが、実装するクラスがわからない場合に役立ちます。

これは、関連するクラスの階層を操作するときに役立ちます。この良い例は、GUIツールキットです。各ウィジェットの具象実装のコンストラクターへの呼び出しをハードコードするだけで済みますが、あるツールキットを別のツールキットに交換したい場合は、変更する場所がたくさんあります。ファクトリを使用することで、変更が必要なコードの量を削減できます。


ファクトリーがインターフェース型を返し、処理している具象クラスではないと仮定します。
ビル・リンチ

1
この回答は、静的なファクトリメソッドではなく、ファクトリメソッドの設計パターンに関するものです。静的ファクトリメソッドは、クラスのインスタンスを返す単純なパブリック静的メソッドです。詳細については、Effective Javaの第2章を参照してください。
Josh Sunshine

4

Staticファクトリに由来する利点の1つは、そのAPIがクラスをパブリックにすることなくオブジェクトを返すことができることです。これは非常にコンパクトなAPIにつながります。Javaでは、これは約32のクラスを非表示にするコレクションクラスによって実現され、コレクションAPIを非常にコンパクトにします。


2

静的ファクトリメソッドは、1つのインスタンスだけが使用する具象クラスを返すようにする場合に適しています。

たとえば、データベース接続クラスでは、データベース接続を作成するクラスを1つだけにすることができます。そのため、MysqlからOracleに切り替える場合は、1つのクラスのロジックを変更するだけで、残りのアプリケーションは新しい接続を使用します。

データベースプーリングを実装する場合は、アプリケーションの他の部分に影響を与えることなく実行されます。

それは目的であるあなたが工場に対して行うかもしれない変更からアプリケーションの残りを保護します。

それが静的である理由は、いくつかの限られたリソース(ソケット接続またはファイルハンドルの数)を追跡したい場合、このクラスは、何個が渡されて戻されたかを追跡できるため、限られたリソース。


2

プライベートコンストラクターを使用した静的ファクトリメソッドの利点の1つ(インスタンスが外部で作成されないようにするには、外部クラスでオブジェクトの作成を制限する必要があります)は、インスタンス制御クラスを作成できることです。また、インスタンス制御クラスは、プログラムの実行中に2つの等しい個別のインスタンスが存在しないことを保証します(a.equals(b)は、a == bの場合のみ)。つまり、equalsメソッドの代わりに==演算子を使用してオブジェクトの等価性を確認できます、Effective javaによると。

静的ファクトリメソッドが繰り返し呼び出されて同じオブジェクトを返すことができるため、クラスはいつでも存在するインスタンスを厳密に制御できます。これを行うクラスはインスタンス制御されていると言われます。インスタンス制御クラスを作成する理由はいくつかあります。インスタンス制御により、クラスは、それがシングルトン(アイテム3)またはインスタンス化不可能(アイテム4)であることを保証できます。また、不変クラス(アイテム15)は、2つの等しいインスタンスが存在しないことを保証できます:a == bの場合に限り、a.equals(b)クラスがこのことを保証する場合、そのクライアントは、equals(Object)メソッドの代わりに==演算子を使用できます。これにより、パフォーマンスが向上する可能性があります。列挙型(アイテム30)はこの保証を提供します。

効果的なJavaから、Joshua Bloch(アイテム1、6ページ)


1

静的

キーワード 'static'で宣言されたメンバー。

ファクトリメソッド

新しいオブジェクトを作成して返すメソッド。

Javaで

プログラミング言語は「静的」の意味に関連していますが、「工場」の定義には関連していません。


@Victor応答には引数を含める必要はありません。事実は十分であるはずです:論争の的である場合、それらは議論または引用によって支持することができます。ここで物議を醸しているものがあることに気づいていません。
ローンの侯爵2014年

私は、答えが短すぎて、最初、2番目、3番目の見た目がよく理解されていないので、とにかくOPに尋ねる必要があると述べました。気にしないで、気が変わって反対投票を削除しようとしましたが、できません。
ビクター

@Victor「短すぎる」を定義します。本当の答えは、単に「はい」、「いいえ」、「どちらでもない」、または「両方」である場合があります。「短すぎる」は完全に主観的です。元のコメントがまだわかりません。定義をサポートするために引数は必要ありません。定義により。回答を編集したので、反対投票を削除できるようになりました。
ローン侯爵2014

もちろん主観的です...すべてのスタックオーバーフローの回答は主観的です。実際、それらは著者レベルの知識に関連しており、回答します。私はあなたの答えを本当に理解していません、おそらく短いものでした。
ビクター

@Victor Rubbish。事実は主観的ではなく、事実または公理から推論的に導き出せる問題でもありません。一方、「短すぎる」は主観的なものであり、私はすでに対処しています。この答えは、本質的に同じであるので、この1あなたがコメントしていません、。コメントは曖昧なままです。
ローン侯爵

1

Java実装には、java.util.Arraysjava.util.Collectionsのユーティリティクラスが含まれています。どちらにも静的なファクトリメソッド、その例、および使用方法が含まれています。

また、java.lang.Stringクラスには、このような静的なファクトリメソッドがあります

  • String.format(...), String.valueOf(..), String.copyValueOf(...)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.