2009-05-18 7 views
11

利点は何ですか?そして、いつ静的コンストラクタを使用するのが適切ですか?なぜ "new"を使用する代わりにCreateメソッドを使用するのですか?

public class MyClass 
{ 
    protected MyClass() 
    { 
    } 

    public static MyClass Create() 
    { 
     return new MyClass(); 
    } 
} 

とちょうど私が最初のアプローチを見ることができる公共のコンストラクタを有する

MyClass myClass = new MyClass(); 

を使用してオブジェクトを作成することとは対照的に、次に

MyClass myClass = MyClass.Create(); 

を介して、クラスのインスタンスを作成することは有用ですCreateメソッドがクラスが実装するインタフェースのインスタンスを返した場合、呼び出し側は特定の型ではなくインタフェースのインスタンスを作成します。

答えて

15

これはファクトリパターンであり、しばしばサブクラスを生成するために使用できますが、静的メソッドのパラメータによってどちらが決定されるかを決定できます。

新しいオブジェクトが常に必要なわけではない場合、たとえばプール実装で使用することもできます。

オブジェクトのすべてのインスタンスをキャッシュするか、作成時に登録する必要がある場合にも使用できます。これは、クライアントがそのことを忘れることを確実にします。

もちろん、シングルトンパターンの一部とパーセルです。

+1

私はこの答えに追加します。この答えを完成させるか、少なくとも「キャッシュされた、あるいはそうでなければ登録された答えの部分」に及ぶと思われる「単純な作成以上のこと」に関するロバート・ポールソンの答え。 –

1

このパターンは、通常Singleton patternで使用されます。これは、通常、オブジェクトが使用するリソースのために、プログラムの使用中に一度だけインスタンス化されるべきクラスまたはファサードがある場合に便利です。

How to in C#

+2

シングルトンパターンは同じオブジェクトへの参照を返しますが、ファクトリパターンはデータを共有できる複数のインスタンスを作成します。 –

+1

BillyONealが述べたように、これはシングルトンパターンではありません。シングルトンは、クラスのインスタンスを1つだけ強制的に作成します。シングルトンパターンを使用したい場合の良い例は、1つしか存在しない設定クラスの場合です。 –

+0

あなたはどちらも正しいですし、彼のコードが必ずしもシングルトンを伝えるわけではありませんが、彼の元の質問はファクトリとシングルトンの両方を使用する静的な構築*の使用を中心にしています。 –

1

あなたがこれを行う可能性がありますさまざまな理由は、例えば、常に(シングルトンオブジェクトを含む)の固定オブジェクトプールからインスタンスを返す、またはあなたが言うように、インターフェースのインスタンスを返すようにするために、あります。

しかし、明確な理由がない場合は、しないでください。

2

複数のクラスインスタンスが同じ初期化データブロックを共有する場合に役立つかもしれません。これはOOPファクトリパターンです。

例として、データベースに接続するクラスがあります。接続は1つだけ必要であり、クラスのすべてのインスタンスで共有できます。

http://en.wikipedia.org/wiki/Factory_pattern

Billy3

+0

これはファクトリメソッドを必要としません。これは静的な接続変数で実現できます。 –

+0

真。しかし、それはOPのコードがどのように書かれているかではありません。 –

1

このアプローチは、そうでない場合は、このアプローチは異例で、シングルトンのためにのみ使用一般です。あなたがしようとしていることを理解するまでは使用しないでください。

+0

ありがとうジョン、私は、どのように、いつ、なぜシングルトンを使用するのか知っていますが、私はシングルトンではないこれを使用するコードサンプルを見てきたと確信しています...もちろん、 :-) –

+0

何も使わないでください。シングルトンまたは静的コンストラクタの作成パターン。私は前者(シングルトンを避ける)に同意するが、そうでなければ反対する。ビルダー/工場のパターンは非常に標準的であり、OPはパターンの使用を理解するために理由を尋ねています。 –

1

これは、プライベートコンストラクタを使用している場合、MyClassを最終的に強制する優れた方法です。そうすれば、コンストラクタがスーパーのコンストラクタにアクセスできないため、サブクラスを作成できません。

もう1つの利点は、コンストラクタのパラメータが1つある場合です。次に、名前付き引数をエミュレートして作成に名前を付けることができます。

public static MyClass createWithDays(int days) { 
... 
} 

今、これはシングルトンではありませんnew MyClass(5)MyClass.createWithDays(5)

8

を比較作成...それがあった場合、同じインスタンスを毎回返します。

これは工場出荷時のパターンです。別にそれは、このようなMyClass.Createとして「staticファクトリメソッド」を有する、シングルトンだときからでき

public static MyClass Create() 
{ 
    if(OS == Windows) 
     return new MyDerivedClassForWindows(); 
    else if(OS == Linux) 
     return new MyDerivedClassForLinux(); 
    etc.... 
} 
+0

あなたはMyClassまたはIMyClassを返しますか... MyClassはインターフェイスではなく、IMyClassは(私はそれがただの規約ですが、あなたの意見がわかります)と仮定します。 –

+0

IMyClassが返されます。 Macの方々はMyClassから派生したくないかもしれませんが(別にするため)、私のサンドボックスでプレイしたいのであれば、少なくともIMyClassを実装する必要があります。 – ratchetr

1

:私は普通のインタフェースではないクラスでこれを行うだろうので、私はここにストレッチする必要がありますが、不自然な例は以下のようになりますMyClass.Createを実装している人がMyClassのサブクラスを返す場合などに便利です。たとえば、テスト中にMyClassWithExtraTestingFunctionalityサブクラスのインスタンスを返すことができます。または、コンフィグレーションオプションに応じてMyClassBeingRemotedOverTheNetworkサブクラスのインスタンスを返します。

0

これは、フレームワーク、クラスまたはその他の設定でWHERE thオブジェクトが実際に作成されます。新しいコンストラクター・アプローチを使用すると、ローカルに作成されます。このアプローチを使用すると、サービス呼び出しによってリモートで作成され、返される可能性があります。これはCSLA frameworkのRocky Lhotkaが取っているアプローチです。

1

その他の回答の多くは、このアイデアが役立つ可能性のある特定の機会をカバーしています。インスタンス作成をカプセル化するという考え方は、Spring、Castleなどの多くのIoCフレームワークで使用されています。アイデアは、インスタンスの作成を集中化することで、アプリケーションの構成をカスタマイズして、異なるオブジェクトセットを使用できるようにすることです。一般的な例はロギングです。設定を変更することで、状況に応じてロギングクラスの異なるインスタンスを生成するようにロガーファクトリに指示できます。

このアイデアを適用すると、非常に緩やかに結合されたシステムになる可能性があります。このシステムは、配備後または実行時にも簡単に変更できます。ただし、別のレベルの間接指定があると、複雑さが増します。

3

Guid.NewGuid()静的メソッドで示される別の理由は、型が構造体の場合です。この場合、CLRでは、デフォルトのパラメータのないコンストラクタが、すべてのフィールドがデフォルト値に初期化された新しいインスタンスを作成する必要があります。 Guidの場合は、次のようになります。

Guid g = new Guid();

は、Guid.Emptyになります。明らかに、Guid.NewGuid()メソッドはそれを行う方法ですので、ランダム化された新しいGuidを作成する機能が必要です。

+0

Guidクラスは命名法ではあまり意味がありません。既存のデータからGuidsを作成するだけのコンストラクタではなく、新しい(ランダム)Guidを作成する唯一の方法はNewGuid()です。あなたの答えは現実を守りますが、なぜその質問に答えません。 Guidクラスでの命名が不適切であるにもかかわらず、Guid.NewGuid()が新しいGuid()とは異なる理由について考える必要があります。 –

1

静的コンストラクタは、コンストラクタに明示的な名前を付けるための良い方法です。 デフォルトのパラメータにも便利です。

例:Myclass.create(); 新しいMyClassののintead(defaultParam1、defaultParam2 ...)

ジョシュア・ブロックはeffective Java(項目1)

4

あなたが本当にノーマルを使用して上の任意の利点を持っていないでしょう投稿した特定の例では、それについて語りますコンストラクタ。

Singletonパターンシングルトンパターンはあなたがからオブジェクトの複数のインスタンスを防ぎたいときに使用することができます

:2つの共通パターンは、オブジェクトを生成するために、このようなメソッドを使用している、しかし、がありますクラスのオブジェクト指向の側面(例えば、フィールド、プロパティ、パラメータのないメソッド)を活用したいと考えています。例:

public class MySingletonClass 
{ 
    private MySingletonClass currentInstance = null; 

    public MySingletonClass CreateInstance() 
    { 
     if (currentInstance == null) 
     { 
       currentInstance = new MySingletonClass(); 
     } 
     else 
     { 
       return currentInstance; 
     } 
    } 
} 

ファクトリパターン

工場出荷時のパターンは、具象クラスの抽象作成する絶好の機会です。たとえば、いくつかのXMLがあると仮定し、XMLでどのノード(NodeA、NodeB、NodeC)が表示されているかによって、処理するクラスが異なります。例:

public class MyXmlProcessorFactory 
{ 
    public static IMyXmlProcessor GetMyXmlProcessor(XmlDocument document) 
    { 
     XmlNode rootNode = document.DocumentElement; 

     if (rootNode.SelectSingleNode("NodeA") != null) 
     { 
       return new NodeAMyXmlProcessor(); 
     } 
     else if (rootNode.SelectSingleNode("NodeB") != null) 
     { 
       return new NodeBMyXmlProcessor(); 
     } 
     else if (rootNode.SelectSingleNode("NodeC") != null) 
     { 
       return new NodeCMyXmlProcessor(); 
     } 
     else 
     { 
       return new DefaultMyXmlProcessor(); 
     } 
    } 
} 
3

あなたは正しいです。これはシングルトンパターンではありません。ファクトリーパターンです。

作成の使用()の代わりに、新しいができますあなたは

は、この例を取るため、ユーザーがより多くの明快さを与える方法に意味のある名前を付けることができます:

public class User 
{ 
    public int id; 
    public string userName; 
    public string password; 
    public string role; 

    private User() { } 

    public static User CreateByCredentials(string uid, string pwd) 
    { 
     User user = new User(); 
     user.userName = uid; 
     user.password = pwd; 
     return user; 
    } 

    public static User CreateById(int id) 
    { 
     User user = new User(); 
     user.id = id; 
     return user; 
    } 

} 

このアプローチには2つの利点があります。 :(。これは、またはすべての場合に便利であってもなくてもよい)

  1. 我々はコンストラクタで行うことは不可能であるヌルオブジェクトを返すことができ
  2. オブジェクトを作成する方法がたくさんある場合は、より意味のある関数名を付けることができます。この例では、User.CreateByCredentials(文字列ユーザー名、文字列パスワード)& User.CreateById(int id)があります。コンストラクタのオーバーロードで同じ機能を実現できますが、まれに同じ明快さで実現できます。
2

より正式に、それは通常、あなたはあなたがオブジェクトを作成するときに簡単な構造以上のものをやりたいReplace Constructor with Factory Method

と呼ばれています。

つまり、ファクトリメソッドを使用すると、よりシンプルなコンストラクタを使用して、コードでより多くの作成オプションを使用できるようになります。

私はまた、これは遅延ロードの場合に使用することができブックRefactoring:Improving the Design of Existing Code (Fowler)

0

をお勧めします。あなたは何らかの理由でオブジェクトを周りに置いておきたいが、必要でない限り実際のコンストラクタに含まれるすべての重い持ち上げをしたくない。したがって、別々のメソッドCreateを作成し、重労働の準備ができたら呼び出します。また

@Rashmiパンディットは書きました:あなたの応答へ

public static User CreateByCredentials(string uid, string pwd) 
    { 
     .... 
    } 

    public static User CreateById(int id) 
    { 
    ... 
    } 

は、あなただけの代わりに、二つの異なる作成方法を作成する別のメソッドのシグネチャを持つオーバーロードコンストラクタを使用することはできませんか?

+0

レイジーロードは、生成パターンによって影響を受けません。コードの読みやすさの観点から、@ Rashmiのコードは、新しいUser(文字列、文字列)または新しいUser(int)のコンストラクタが非常に直感的ではない、自己文書化です。 –

0

コンストラクタを使用する場合は、コンストラクタの初期化のみを使用できます。

public void Example() 
    { 
     var person = new Person 
         { 
          GivenName = "John", 
          FamilyName = "Smith", 
          Address = new Address 
              { 
               Street = "Wallace", 
               Number = 12 
              }, 
          PhoneNumbers = new List<PhoneNumber> 
               { 
                new PhoneNumber 
                 { 
                  Number = 1234234, 
                  AreaCode = 02 
                 }, 
                new PhoneNumber 
                 { 
                  Number = 1234234, AreaCode = 02 
                 } 
               } 
         }; 
    } 

    internal class PhoneNumber 
    { 
     public int AreaCode { get; set; } 

     public int Number { get; set; } 
    } 

    internal class Address 
    { 
     public int Number { get; set; } 

     public string Street { get; set; } 
    } 

    internal class Person 
    { 
     public Address Address { get; set; } 

     public string GivenName { get; set; } 

     public string FamilyName { get; set; } 

     public List<PhoneNumber> PhoneNumbers { get; set; } 
    } 
} 
関連する問題