回答:
プライベートコンストラクターが必要になるいくつかの理由:
final
、クラスレベルにする必要があります。このため、プライベートコンストラクタを配置してもほとんど役に立ちません。
final
です。これは、SunがStringクラスに対して行ったことであり、拡張すべきではない合理的なAPIのチャンクです。
プライベートコンストラクターを提供することで、このクラス以外の場所にクラスインスタンスが作成されないようにします。このようなコンストラクターを提供するには、いくつかの使用例があります。
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
メンバーのみが含まれます。この場合、プログラムでオブジェクトインスタンスを作成する必要はありません。
別のフレンドクラス/関数がユーザーに禁止された方法でオブジェクトを構築できるようにする「バックドア」を残すこと。頭に浮かぶ例は、イテレータを構築するコンテナ(C ++)です。
Iterator Container::begin() { return Iterator(this->beginPtr_); }
// Iterator(pointer_type p) constructor is private,
// and Container is a friend of Iterator.
friend
、それが正当化されていない場所で使用する可能性のある経験の浅いC ++プログラマーを対象としているようです-そしてそれが悪い考えである多くの場合があります。悲しいことに、メッセージはあまりによく受け取られており、多くの開発者は、時々のの使用がfriend
受け入れられるだけでなく好ましいことを理解するのに十分なほど言語を習得していません。あなたの例はまさにそのような場合でした。意図的な強結合は犯罪ではなく、設計上の決定です。
これは、一般的なコードを含むコンストラクターに非常に役立ちます。プライベートコンストラクターは、 'this(...);'を使用して他のコンストラクターから呼び出すことができます。表記。プライベート(または保護された)コンストラクターで共通の初期化コードを作成することにより、作成時にのみ呼び出されることを明示的に明らかにします。これは、単純なメソッドの場合はそうではありません。
public class Point {
public Point() {
this(0,0); // call common constructor
}
private Point(int x,int y) {
m_x = x; m_y = y;
}
};
特定のクラスのみがオブジェクトを作成できるように、プライベートコンストラクターを使用することもできます(セキュリティ上の理由から)。
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のフレンドであるため)だけです。
次に、プライベートコンストラクターの使用例をいくつか示します。
同じ問題についてあなたから質問がありました。
他のユーザーにインスタンスの作成を許可したくない場合は、制限されたスコープ内でコンストラクターを維持してください。実用的なアプリケーション(例)は、シングルトンパターンです。
あなたはいけません、コンストラクタをプライベートにします。限目。保護することで、必要に応じてクラスを拡張できます。
編集:あなたはこれにどれだけの反対票を投げても、私はそれを支持しています。 あなたはコードの将来の開発の可能性を遮断しています。他のユーザーやプログラマーが本当にクラスを拡張すると決心している場合は、コンストラクターをソースまたはバイトコードで保護されるように変更するだけです。あなたは彼らの生活を少し難しくする以外に何も成し遂げなかったでしょう。コンストラクタのコメントに警告を含め、そのままにしておきます。
それがユーティリティクラスである場合、より単純で、より正確で、よりエレガントなソリューションは、クラス全体を「静的final」にマークして拡張を防止することです。コンストラクタをプライベートにマークするだけでは何の効果もありません。熱心なユーザーは、常にリフレクションを使用してコンストラクターを取得できます。
protected
コンストラクターの1つの良い使い方は、静的ファクトリーメソッドの使用を強制することです。これにより、インスタンス化を制限したり、高価なリソース(DB接続、ネイティブリソース)をプールして再利用したりできます。コンストラクタは、シングルトンを実装する必要がある場合や、クラスのオブジェクト数を制限する必要がある場合など、何らかの目的でプライベートです。たとえば、シングルトン実装では、コンストラクターをプライベートにする必要があります
#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
}
ありがとう
複数のコンストラクタを持つことができます。C ++は、明示的に指定しない場合、デフォルトのコンストラクターとデフォルトのコピーコンストラクターを提供します。いくつかのパラメーター化されたコンストラクターを使用しないと構築できないクラスがあるとします。多分それは変数を初期化しました。ユーザーがコンストラクターなしでこのクラスを使用する場合、問題が発生することはありません。一般的なルールとして、デフォルトの実装が有効でない場合は、デフォルトコンストラクタとコピーコンストラクタの両方をプライベートにし、実装を提供しないでください。
class C
{
public:
C(int x);
private:
C();
C(const C &);
};
コンパイラーを使用して、ユーザーが無効なデフォルトのコンストラクターでオブジェクトを使用できないようにします。
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はデフォルトのパラメーターなしのパブリックコンストラクターを提供します。インスタンス化を防ぐことが目的の場合は、プライベートコンストラクターが必要です。
最上位クラスを静的にマークすることはできず、最終クラスでさえインスタンス化することができます。
ユーティリティクラスはプライベートコンストラクタを持つことができます。クラスのユーザーは、これらのクラスをインスタンス化できません。
public final class UtilityClass {
private UtilityClass() {}
public static utilityMethod1() {
...
}
}
重要な用途の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
}
};
クラスにも静的メソッドしかない場合にも適しています。つまり、誰もクラスをインスタンス化する必要はありません
それは本当に明らかな理由の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
イディオムと呼ばれます。クラスを最初から作成するには、使用するコンストラクターを明示的に指定する必要があります。
それは多くの建設方法の特別なケースです。デザインパターンは、ビルド対象にする方法のかなりの数を提供:Builder
、Factory
、Abstract Factory
、...とプライベートコンストラクタは、ユーザが適切に制約されていることを確認します。
よく知られている用途に加えて…
メソッドオブジェクトパターンを実装するには、次のように要約します。
「プライベートコンストラクタ、パブリック静的メソッド」
「実装用オブジェクト、インターフェース用関数」
オブジェクトを使用して関数を実装し、オブジェクトが(メソッド呼び出しによる)1回限りの計算以外では役に立たない場合は、Throwaway Objectがあります。オブジェクトの作成とメソッドの呼び出しを静的メソッドにカプセル化して、この一般的なアンチパターンを防ぐことができます。
z = new A(x,y).call();
…(名前空間付きの)関数呼び出しに置き換えます。
z = A.f(x,y);
呼び出し側は、内部でオブジェクトを使用していることを認識したり気にかけたりする必要がなく、よりクリーンなインターフェイスを提供し、オブジェクトがぶら下がったり、オブジェクトが誤って使用されたりすることによるガベージを防ぎます。
たとえば、メソッド、、および全体で計算を分割するfoo
場合bar
、zork
たとえば、関数の内外に多くの値を渡さずに状態を共有する場合は、次のように実装できます。
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ページに記載されており、リファクタリングパターンの最後のステップであり、次のように終了します。
- 元のメソッドを、元のメソッドのパラメーターとレシーバーで構築された新しいクラスのインスタンスを作成し、「計算」を呼び出すメソッドで置き換えます。
これは、他の例とは大きく異なります。クラスは(ユーティリティクラスとは異なり)インスタンス化可能ですが、インスタンスは(シングルトンなどを含むファクトリメソッドとは異なり)プライベートであり、エスケープすることはないため、スタック上に存在できます。
このパターンは、オブジェクトが低レベルの実装を簡略化するために使用されているが必ずしも外部に公開されていないボトムアップOOPで非常に役立ちます。また、高レベルのインターフェイスで頻繁に表示され、開始されるトップダウンOOPと対照的です。
オブジェクトのインスタンスを作成する方法とタイミング(および数)を制御する場合に便利です。
とりわけ、パターンで使用されます:
Singleton pattern
Builder pattern
プライベートコンストラクターを使用すると、ドメイン主導の設計に直面して可読性/保守性を向上させることもできます。「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シナリオでは、新しいオブジェクトの直接作成を防ぐことは完全に理にかなっていると思います。