クラスでコンストラクタをプライベートにすることの用途は何ですか?


134

コンストラクタをクラスでプライベートにする必要があるのはなぜですか?常にコンストラクターを公開する必要があるので。

回答:


129

プライベートコンストラクターが必要になるいくつかの理由:

  1. コンストラクターは、クラス自体の内部の静的ファクトリーメソッドからのみアクセスできます。シングルトンもこのカテゴリに属する​​ことができます。
  2. 静的メソッドのみを含むユーティリティクラス

9
ユーティリティクラスのプライベートコンストラクターを作成する手間すらしませんでした。
Petesh

16
@Patesh:それはあなたの決定です。その他と私は、1行のプライベートコンストラクターを除外するよりも、ユーティリティクラスのインスタンス化を回避したいと考えています。
ナンダ

1
一部のプログラミング言語(特にJava)では、継承も防止されます
dfa

9
@dfa:継承を防ぐにはfinal、クラスレベルにする必要があります。このため、プライベートコンストラクタを配置してもほとんど役に立ちません。
nanda

3
@Will:リフレクションを使用する場合は不可。コンストラクターをプライベートとして宣言することは、インスタンス化(リフレクションの禁止)を防ぐことを目的としていますが、サブクラス化を防ぐことは意図ではなく、副作用です。このための適切なツールは、クラスを宣言することfinalです。これは、SunがStringクラスに対して行ったことであり、拡張すべきではない合理的なAPIのチャンクです。
BobMcGee 2010年

96

プライベートコンストラクターを提供することで、このクラス以外の場所にクラスインスタンスが作成されないようにします。このようなコンストラクターを提供するには、いくつかの使用例があります。

A.クラスインスタンスはstaticメソッドで作成されます。次に、staticメソッドはとして宣言されpublicます。

class MyClass()
{
private:
  MyClass() { }

public:
  static MyClass * CreateInstance() { return new MyClass(); }
};

B.クラスはシングルトンです。つまり、プログラムに存在するクラスのインスタンスは1つだけです。

class MyClass()
{
private:
  MyClass() { }

public:
  MyClass & Instance()
  {
    static MyClass * aGlobalInst = new MyClass();
    return *aGlobalInst;
  }
};

C.(次期C ++ 0x標準にのみ適用)いくつかのコンストラクターがあります。それらのいくつかは宣言されpublic、他は宣言されていprivateます。コードサイズを削減するために、パブリックコンストラクターはプライベートコンストラクターを「呼び出し」、次にすべての作業を実行します。あなたのpublicコンストラクタは、このように呼ばれている委任コンストラクタを:

class MyClass
{
public:
  MyClass() : MyClass(2010, 1, 1) { }

private:
  MyClass(int theYear, int theMonth, int theDay) { /* do real work */ }
};

D.オブジェクトのコピーを制限したい(たとえば、共有リソースを使用しているため):

class MyClass
{
  SharedResource * myResource;

private:
  MyClass(const MyClass & theOriginal) { }
};

E.クラスはユーティリティクラスです。つまり、staticメンバーのみが含まれます。この場合、プログラムでオブジェクトインスタンスを作成する必要はありません。


3
ほとんどの場合、オブジェクトのコピーを防止する必要があります。したがって、プライベートコピーコンストラクターの実装は提供しません。
frast

google c ++スタイルガイドから(リストにないが一般的な別の例)-> コンストラクタで作業する必要がある場合「ファクトリ関数を検討して[コンストラクタをプライベートにする]」(角括弧内のテキストは私が書いたものです) )
Trevor Boyd Smith

12

別のフレンドクラス/関数がユーザーに禁止された方法でオブジェクトを構築できるようにする「バックドア」を残すこと。頭に浮かぶ例は、イテレータを構築するコンテナ(C ++)です。

Iterator Container::begin() { return Iterator(this->beginPtr_); }
// Iterator(pointer_type p) constructor is private,
//     and Container is a friend of Iterator.

テリー、これは十分違いますか?;)
Emile Cormier、2014年

いい答えだ。これは、ユーザーができないことを達成するための1つの手段であるため、リフレクションについて触れないでください。
BobMcGee 2010年

@ボブ:私は主にC ++の人で、リフレクションは実際にはC ++の語彙にはないので、あなたはそれについて私に啓蒙する必要があります。;)
Emile Cormier

3
誰もこれを読むつもりはありませんが、ここに行きます:私はこれについて何回か反対投票されました。動揺や何かではないが、(学習のために)なぜこれが悪いのか知りたいのですが?コンテナのデータにアクセスするために必要なデータを使用して、イテレータを他にどのように構築できますか?
Emile Cormier、2010年

2
@EmileCormier、私はC ++を学習している人々が何度も何度も言われるので、不当に反対票を投じたと思います:「友達の宣言を避ける」。このアドバイスはfriend、それが正当化されていない場所で使用する可能性のある経験の浅いC ++プログラマーを対象としているようです-そしてそれが悪い考えである多くの場合があります。悲しいことに、メッセージはあまりによく受け取られており、多くの開発者は、時々のの使用がfriend受け入れられるだけでなく好ましいことを理解するのに十分なほど言語を習得していません。あなたの例はまさにそのような場合でした。意図的な強結合は犯罪ではなく、設計上の決定です。
evadeflow 2016年

10

みんなシングルトンの事に行き詰まってるわ。

他のもの:

  • スタック上にクラスを作成しないようにします。プライベートコンストラクタを作成し、ファクトリメソッドを介してのみポインタを返します。
  • クラスのコピーの作成の防止(プライベートコピーコンストラクター)

8

これは、一般的なコードを含むコンストラクターに非常に役立ちます。プライベートコンストラクターは、 'this(...);'を使用して他のコンストラクターから呼び出すことができます。表記。プライベート(または保護された)コンストラクターで共通の初期化コードを作成することにより、作成時にのみ呼び出されることを明示的に明らかにします。これは、単純なメソッドの場合はそうではありません。

public class Point {
   public Point() {
     this(0,0); // call common constructor
   }
   private Point(int x,int y) {
     m_x = x; m_y = y;
   }
};

3

パブリックコンストラクターを使用したくない場合があります。たとえば、シングルトンクラスが必要な場合。

サードパーティが使用するアセンブリを記述している場合、アセンブリによってのみ作成され、アセンブリのユーザーによってインスタンス化されないようにする内部クラスがいくつかある可能性があります。


3

これにより、ユーザー(プライベートコンストラクターを持つクラス)がコンストラクターの呼び出し方法を確実に制御できます。

例:クラスの静的ファクトリメソッドは、ファクトリメソッドがオブジェクトを割り当てることを選択したときにオブジェクトを返す可能性があります(シングルトンファクトリなど)。


@Skilldrick:1つの例は、クラスにヒープ割り当てのみを強制できることです。
Dirk

@dirk関係なくなったため、コメントを削除しました。
スキルドリック

3

特定のクラスのみがオブジェクトを作成できるように、プライベートコンストラクターを使用することもできます(セキュリティ上の理由から)。

それを行う1つの方法は、友達クラスを持つことです。

C ++の例:

class ClientClass;
class SecureClass 
{
  private:
    SecureClass();   // Constructor is private.
    friend class ClientClass;  // All methods in 
                               //ClientClass have access to private
                               // &   protected methods of SecureClass.
};

class ClientClass
{
public:
    ClientClass();
    SecureClass* CreateSecureClass()
     { 
           return (new SecureClass());  // we can access 
                                        // constructor of 
                                        // SecureClass as 
                                        // ClientClass is friend 
                                        // of SecureClass.
     }
};

注:注:SecureClassのコンストラクターを呼び出すことができるのは、ClientClass(SecureClassのフレンドであるため)だけです。


2

2

ユーザーがこのクラスのインスタンスを作成したくない場合、またはこのクラスを継承するクラスを作成したくない場合java.lang.math、このパッケージのstaticすべての関数はです。すべての関数はのインスタンスを作成せずに呼び出すことができるmathため、コンストラクターは静的として通知されます。


1

プライベートの場合、それを呼び出すことはできません==>クラスをインスタンス化することはできません。シングルトンのように、場合によっては便利です。

ここに議論といくつかの例があります


1

同じ問題についてあなたから質問がありました。

他のユーザーにインスタンスの作成を許可したくない場合は、制限されたスコープ内でコンストラクターを維持してください。実用的なアプリケーション(例)は、シングルトンパターンです。


1

あなたはいけません、コンストラクタをプライベートにします。限目。保護することで、必要に応じてクラスを拡張できます。

編集:あなたはこれにどれだけの反対票を投げても、私はそれを支持しています。 あなたはコードの将来の開発の可能性を遮断しています。他のユーザーやプログラマーが本当にクラスを拡張すると決心している場合は、コンストラクターをソースまたはバイトコードで保護されるように変更するだけです。あなたは彼らの生活を少し難しくする以外に何も成し遂げなかったでしょう。コンストラクタのコメントに警告を含め、そのままにしておきます。

それがユーティリティクラスである場合、より単純で、より正確で、よりエレガントなソリューションは、クラス全体を「静的final」にマークして拡張を防止することです。コンストラクタをプライベートにマークするだけでは何の効果もありません。熱心なユーザーは、常にリフレクションを使用してコンストラクターを取得できます。

有効な用途:

  • protected コンストラクターの1つの良い使い方は、静的ファクトリーメソッドの使用を強制することです。これにより、インスタンス化を制限したり、高価なリソース(DB接続、ネイティブリソース)をプールして再利用したりできます。
  • シングルトン(通常は適切ではありませんが、必要な場合があります)

2
私の経験では、絶対的な真実はありません。状況によっては、gotoを使用することもできます。悪い方法と邪悪な方法がありますが、マーシャルクラインが言うように、場合によっては、悪の少ない方から選択する必要があります。 parashift.com/c++-faq-lite/big-picture.html#faq-6.15 プライベートコンストラクターに関しては、これらは必要であり、ユーザーにとっても悪くはありません。それは、サブクラスを含め、誰もそれを使用するべきではないことを意味します。
daramarak、2014年

後藤は本当の地位を持っていますが、コンストラクターをプライベートにマークすることは、あなたに道を譲る以外に何も得ません。理由をより詳しく説明するために投稿を編集しました。
BobMcGee

一部のクラスをコピーしたり、デフォルトの構成を作成することは意味がありません。C ++では、プライベートctorを定義せずに宣言することによってこれを示します(これはoperator =にも共通です)。

Java JITやGWTなどの最適化コンパイラーは、実際にはプライベートコンストラクターを使用します。インスタンス化のスコープを制限し、コードのインライン化/プルーニングをより適切に実行します。
Ajax

1

コンストラクタは、シングルトンを実装する必要がある場合や、クラスのオブジェクト数を制限する必要がある場合など、何らかの目的でプライベートです。たとえば、シングルトン実装では、コンストラクターをプライベートにする必要があります

#include<iostream>
using namespace std;
class singletonClass
{


    static int i;
    static singletonClass* instance;
public:


    static singletonClass* createInstance()
    {


        if(i==0)
        {

            instance =new singletonClass;
            i=1;

        }

        return instance;

    }
    void test()
    {

        cout<<"successfully created instance";
    }
};

int singletonClass::i=0;
singletonClass* singletonClass::instance=NULL;
int main()
{


    singletonClass *temp=singletonClass::createInstance();//////return instance!!!
    temp->test();
}

ここでも、オブジェクトの作成を10までに制限する場合は、次のコマンドを使用します。

#include<iostream>
using namespace std;
class singletonClass
{


    static int i;
    static singletonClass* instance;
public:


    static singletonClass* createInstance()
    {


        if(i<10)
        {

            instance =new singletonClass;
            i++;
            cout<<"created";

        }

        return instance;

    }
};

int singletonClass::i=0;
singletonClass* singletonClass::instance=NULL;
int main()
{


    singletonClass *temp=singletonClass::createInstance();//return an instance
    singletonClass *temp1=singletonClass::createInstance();///return another instance

}

ありがとう


1

複数のコンストラクタを持つことができます。C ++は、明示的に指定しない場合、デフォルトのコンストラクターとデフォルトのコピーコンストラクターを提供します。いくつかのパラメーター化されたコンストラクターを使用しないと構築できないクラスがあるとします。多分それは変数を初期化しました。ユーザーがコンストラクターなしでこのクラスを使用する場合、問題が発生することはありません。一般的なルールとして、デフォルトの実装が有効でない場合は、デフォルトコンストラクタとコピーコンストラクタの両方をプライベートにし、実装を提供しないでください。

class C
{
public:
    C(int x);

private:
    C();
    C(const C &);
};

コンパイラーを使用して、ユーザーが無効なデフォルトのコンストラクターでオブジェクトを使用できないようにします。


2
デフォルトのコンストラクタを指定せずにデフォルト以外のコンストラクタを指定すると、デフォルトのコンストラクタは存在しません。それを作成してプライベートにする必要はありません。
TT_ 2014

0

Effective Javaから引用すると、プライベートコンストラクターを持つクラスに、定数を(静的な最終フィールドとして)定義するユーティリティクラスを含めることができます。

編集:コメントによると、これはJavaでのみ適用される可能性があるものであり、この構造が他のOO言語(たとえばC ++)で適用可能/必要であるかどうかはわかりません)

以下の例:

public class Constants {
    private Contants():

    public static final int ADDRESS_UNIT = 32;
    ...
}

EDIT_1:もう一度は、以下の説明はJavaで適用されます(とブックから参照して、効果的なJavaの

以下のようなユーティリティクラスのインスタンス化は、有害ではありませんが、インスタンス化するように設計されていないため、何の目的にも役立ちません。

たとえば、定数クラスのプライベートコンストラクターがないとします。以下のようなコードチャンクは有効ですが、Constantsクラスのユーザーの意図をうまく伝えていません

unit = (this.length)/new Constants().ADDRESS_UNIT;

のようなコードとは対照的

unit = (this.length)/Constants.ADDRESS_UNIT;

また、プライベートコンストラクターは、定数 (たとえば)クラスの設計者の意図をよりよく伝えていると思います。

コンストラクターが提供されない場合、Javaはデフォルトのパラメーターなしのパブリックコンストラクターを提供します。インスタンス化を防ぐことが目的の場合は、プライベートコンストラクターが必要です。

最上位クラスを静的にマークすることはできず、最終クラスでさえインスタンス化することができます。


2
しかし、C ++では、このためのクラスは必要ありません。オブジェクト内のデータに依存しないものがある場合は、それをフリー関数およびフリー変数として記述します。カプセル化したいですか?名前空間を使用します。
daramarak、2014年

@daramarak:ありがとう、C ++の経験はありません。これはJavaにのみ適用されることを反映するように回答を更新しました
sateesh

2
オブジェクトが静的変数をカプセル化しているだけの場合、なぜインスタンス化を制限するのですか?なぜコンストラクタについて何かを指定するのですか?インスタンス化されても害はありません。静的および最終クラスを宣言すると、同様の結果が得られるようです。
BobMcGee

@BobMcGee、コメントありがとうございます。これにより、投稿した内容についてより深く考える(そして参照する)ことができました。プライベートコンストラクターの有用性についての推論を追加するために、回答を編集しました。
sateesh

0

ユーティリティクラスはプライベートコンストラクタを持つことができます。クラスのユーザーは、これらのクラスをインスタンス化できません。

public final class UtilityClass {
    private UtilityClass() {}

    public static utilityMethod1() {
        ...
    }
}

1
ユーティリティクラスがインスタンス化されている場合、なぜ重要なのですか?フィールドのないオブジェクトを作成し、数バイトのメモリを消費するだけです。
BobMcGee 2010年

インスタンス化できると、あいまいなAPIが作成されます。クラスを状態のないユーティリティクラスとして設計し、その状態を維持したい場合。パブリックコンストラクターでクラスをサブクラス化できます。いくつかのユーティリティメソッドのサブクラスはばかげています。
gpampara 2010年

@BobMcGee:機能するクラスを設計することと、他の人が使用するクラスを設計することは明らかに異なります。API開発に携わっている人(Sunの人やGoogleコレクションの人など)は、ユーティリティクラスのプライベートコンストラクターは役に立たないと言って、誰でも殺します。
nanda

@gpampara:クラスをfinalと宣言すると、サブクラス化を防ぐことができます。これは、SunがStringクラスに対して行ったことです。@Nanda:ユーティリティクラスは、定義されたコンストラクタを必要としません。拡張可能にしたくない場合は、「final」を使用して拡張可能でないことを宣言してください。
BobMcGee

1
@BobMcGee:Sunの例を見てみたいと思います。次に、Sunのユーティリティクラスコレクションdocjar.com/html/api/java/util/Collections.java.htmlを確認してください。それは確かにプライベートコンストラクタを使用しています。
nanda

0

クラスが自由にインスタンス化されないようにする必要がある場合があります。例としてシングルトン設計パターンを見てください。一意性を保証するために、誰にもインスタンスを作成させることはできません:-)


0

重要な用途の1つは、SingleTonクラスです。

class Person
{
   private Person()
   {
      //Its private, Hense cannot be Instantiated
   }

   public static Person GetInstance()
   {
       //return new instance of Person
       // In here I will be able to access private constructor
   }
};

クラスにも静的メソッドしかない場合にも適しています。つまり、誰もクラスをインスタンス化する必要はありません


シングルトンは「アンチパターン」であると多くの人が考えており、それを適用する決定は軽く行われるべきではないことに注意すべきです。一般的な代替策は、依存性注入です。
Michael Aaron Safyan、2010年

SingleTonはアンチパターンではありません。ただし、パターンの過剰使用(その使用に関する知識の欠如のため)は良くありません。GOFパターンの1つであることに注意してください。
SysAdmin 2010年

0

それは本当に明らかな理由の1つです。オブジェクトを作成したいのですが、コンストラクタ内で(インターフェイスの観点から)作成するのは現実的ではありません。

Factory例は私が発揮させ、非常に明白であるNamed Constructorイディオムを。

Complex複素数を表すことができるクラスがあるとしましょう。

class Complex { public: Complex(double,double); .... };

問題は、コンストラクターが実数部と虚数部を期待するか、それともノルムと角度(極座標)を期待するかです。

インターフェイスを変更して簡単にすることができます。

class Complex
{
public:
  static Complex Regular(double, double = 0.0f);
  static Complex Polar(double, double = 0.0f);
private:
  Complex(double, double);
}; // class Complex

これはNamed Constructorイディオムと呼ばれます。クラスを最初から作成するには、使用するコンストラクターを明示的に指定する必要があります。

それは多くの建設方法の特別なケースです。デザインパターンは、ビルド対象にする方法のかなりの数を提供:BuilderFactoryAbstract Factory、...とプライベートコンストラクタは、ユーザが適切に制約されていることを確認します。


0

よく知られている用途に加えて…

メソッドオブジェクトパターンを実装するには、次のように要約します。

「プライベートコンストラクタ、パブリック静的メソッド」
「実装用オブジェクト、インターフェース用関数」

オブジェクトを使用して関数を実装し、オブジェクトが(メソッド呼び出しによる)1回限りの計算以外では役に立たない場合は、Throwaway Objectがあります。オブジェクトの作成とメソッドの呼び出しを静的メソッドにカプセル化して、この一般的なアンチパターンを防ぐことができます。

z = new A(x,y).call();

…(名前空間付きの)関数呼び出しに置き換えます。

z = A.f(x,y);

呼び出し側は、内部でオブジェクトを使用していることを認識したり気にかけたりする必要がなく、よりクリーンなインターフェイスを提供し、オブジェクトがぶら下がったり、オブジェクトが誤って使用されたりすることによるガベージを防ぎます。

たとえば、メソッド、、および全体で計算を分割するfoo場合barzorkたとえば、関数の内外に多くの値を渡さずに状態を共有する場合は、次のように実装できます。

class A {
  public static Z f(x, y) {
    A a = new A(x, y);
    a.foo();
    a.bar();
    return a.zork();
  }

  private A(X x, Y y) { /* ... */ };
}

このメソッドオブジェクトパターンは、Smalltalk Best Practice Patterns、Kent Beck、34〜37ページに記載されており、リファクタリングパターンの最後のステップであり、次のように終了します。

  1. 元のメソッドを、元のメソッドのパラメーターとレシーバーで構築された新しいクラスのインスタンスを作成し、「計算」を呼び出すメソッドで置き換えます。

これは、他の例とは大きく異なります。クラスは(ユーティリティクラスとは異なり)インスタンス化可能ですが、インスタンスは(シングルトンなどを含むファクトリメソッドとは異なり)プライベートであり、エスケープすることはないため、スタック上に存在できます。

このパターンは、オブジェクトが低レベルの実装を簡略化するために使用されているが必ずしも外部に公開されていないボトムアップOOPで非常に役立ちます。また、高レベルのインターフェイスで頻繁に表示され、開始されるトップダウンOOPと対照的です。


0

オブジェクトのインスタンスを作成する方法とタイミング(および数)を制御する場合に便利です。

とりわけ、パターンで使用されます:

Singleton pattern
Builder pattern

プライベートコンストラクターは不変オブジェクトでどのように役立ちますか?不変性とは、作成後のオブジェクトへの変更を防ぐことですが、プライベートコンストラクターでは作成を防ぎます。
Nils von Barth 2015年

0

プライベートコンストラクターを使用すると、ドメイン主導の設計に直面して可読性/保守性を向上させることもできます。「Microsoft .NET-エンタープライズ向けのアプリケーションの構築、第2版」から:

var request = new OrderRequest(1234);

「ここには2つの問題があります。まず、コードを見ると、何が起こっているのかほとんどわかりません。OrderRequestのインスタンスが作成されていますが、なぜ、どのデータを使用していますか?1234は何ですか?これが2番目の問題につながります。制限付きコンテキストのユビキタス言語に違反しています。この言語はおそらく次のようなものです:顧客は注文リクエストを発行でき、購入IDを指定できます。その場合、新しいOrderRequestインスタンスを取得するためのより良い方法があります: "

var request = OrderRequest.CreateForCustomer(1234);

どこ

private OrderRequest() { ... }

public OrderRequest CreateForCustomer (int customerId)
{
    var request = new OrderRequest();
    ...
    return request;
}

私はこれをすべての単一のクラスに推奨しているわけではありませんが、上記のDDDシナリオでは、新しいオブジェクトの直接作成を防ぐことは完全に理にかなっていると思います。

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