その理由は、クラスの不変条件を満たすために必要な状態をオブジェクトの構築中に提供する必要があるためです。そのため、「必須」プロパティの値をコンストラクター パラメーターとして提供する必要があります。あなたの質問は、オブジェクトがプロパティで状態を設定することによって特徴付けられるという誤った仮定に基づいています。これはいくつかの理由で間違っています。そのいくつかは次のとおりです。
- ほとんどではないにしても、多くの OO 言語にはプロパティがありません: Java、C++、...
- 使用するものは形式的にのみオブジェクトであり、実際には単純なレコードであり、オブジェクト指向ではありません。たとえば、メソッドのない C++ 構造体と同じです (セッターとメソッドについては、下部のメモを参照してください)。
クライアントがオブジェクトのインスタンスを作成できるようにすることは、後で必須状態の正しい値を設定するだけで、デバッガーと一緒に何時間も費やすことになります。
User
姓と名を常に設定する必要があるという不変条件をいくつか考えてみましょう。
class User {
public User(string first, string last) { ... }
public User(string first, string last, uint age) : this(first, last) { ... }
}
// client code:
var user = new User("john", "doe");
var user2 = new User("Clint", "Eastwood", 82);
コンパイラは、不変条件を満たさない限り、誰もオブジェクトをインスタンス化できないことを保証します。
それをあなたのアプローチと比較してください:
class User {
public User(string first, string last) { ... }
public User(uint age) { ... }
[Mandatory] public string FirstName { get; set; }
[Mandatory] public string LastName { get; set; }
}
// client code:
var actor = new User(82); // << invalid
actor.FirstName = "Clint";
actor.LastName = "Eastwood"; // << valid
このアプローチにより、より多くのコードが生成され、オブジェクトが有効な状態にない期間 ( ~ の間) が許容され<< invalid
ます。<< valid
一部のプロパティ セッターが例外をスローした場合はどうなりますか? 壊れたオブジェクト インスタンスが浮かんでいます。セッターのコードがスローできないこともコンパイラーが検証すると思いますか? それは可能だと思いますか?それに加えて、インスタンスをインスタンス化するすべてのクライアントUser
は、必須プロパティとは何かを確認し、それらすべてを確実に設定する必要があります。これにより、カプセル化が効果的に解除されます。
IMO、プロパティ セッターは、ゲッターとは異なり、まれである必要があります。このようなクラスでは、FirstName/LastName のセッターは使用せず、getter のみを使用する必要があると思います。SetName(string first, string last)
名前の変更を本当に許可したい場合は、代わりにメソッドが必要です。理由は次のとおりです。
// lets rename actor
actor.FirstName = "John";
actor.LastName = "Wayne";
最後の行がスローされた場合、私が聞いたことのない俳優のジョン・イーストウッドが残ります。これactor.SetName("John", "Wayne")
ではありえない。
さらに、指定する順序で依存関係を持つプロパティについてはどうでしょうか。
obj.ErrorCode = 123; // imagine that error code must be != 0
obj.ErrorMsg = "foo"; // in order to be allowed to set error code
持つ代わりに、そのための属性も導入しますobj.SetErrorInfo(123, "foo")
か? これにより、メソッド呼び出しとは異なり、順序が実装の詳細によって引き起こされるため、プロパティがカプセル化を破ることが明らかになります。
多くの場合、C# などの言語では、必要な状態または依存関係はコンストラクターで提供されますが、オプションの状態はプロパティを介して設定できます。ただし、言語をオブジェクト指向にするのはプロパティや継承ではありません。