1

複雑なプロパティがある場合、それをインスタンス化するべきですか、それともユーザーにインスタンス化を任せるべきですか?

たとえば (C#)

A)

 class Xyz{
     List<String> Names {get; set;}
 }

使おうとしたら設定しないといけない。

...
Xyz xyz = new Xyz();
xyz.Name = new List<String>();
xyz.Name.Add("foo");
...

コードを変更した場合

B)

 class Xyz{
     public Xyz(){
         Names = new List<String>();
     }
     List<String> Names {get; }
 }

この場合、リストを読み取り専用にすることができます。

別のシナリオが発生する可能性があります。意図的に設定したくない場所だと思います。たとえば、

ハ)

 class Xyz{
     String Name {get; set;}
 }

初期化するのは悪い習慣だと思います。

そのようなシナリオの経験則はありますか?

4

6 に答える 6

3

経験則として (その規則からの例外が常に存在することを意味します)、コンストラクターでメンバーを設定します。それがコンストラクターの目的です。

オブジェクト指向の背後にあるアイデアの 1 つが抽象化であることを思い出してください。「ユーザー」 (つまり、ソース コードでオブジェクトをインスタンス化するプログラマ) にそれを要求することは、抽象化の原則に違反しています。ユーザーがオブジェクトを使用する前に考えなければならないことがもう 1 つあります。そのため、エラーの潜在的な原因がもう 1 つあります。

于 2008-10-30T13:38:23.603 に答える
2

これは私の通常の解決策です:

class XYZ 
{
   public XYZ () { Names = new List<string>(); }
   public List<string> Names { get; private set; }
}

(すべてのXmlSerializedプロパティでゲッターとセッターが必要なため、XmlSerializationでは機能しないことに注意してください。)(これをオーバーライドできますが、少しの努力で作業が多すぎるようです)。

OregonGhostが指摘したように、XmlSerializationで機能するには、これを追加する必要があります[XmlArray]

これでもカプセル化のルールに違反します。完全に正しいことを望んでいるかのように、次のようになります。

class XYZ 
{
   public XYZ () { AllNames = new List<string>(); }
   private List<string> AllNames { get; set; }
   public void AddName ( string name ) { AllNames.Add(name); }
   public IEnumerable<string> Names { get { return AllNames.AsReadOnly(); } }
}

これは、残りのほとんどすべての.Net Frameworkの設計に反するため、通常、最初のソリューションを使用することになります。

ただし、これには、XYZが名前のコレクションへの変更を追跡できるという追加の利点があり、XYZは名前のコレクションを変更できる唯一の場所です。

私はこれをいくつかのケースで実装しましたが、すべてに対して実装すると、他のプログラマーとの摩擦が大きくなりすぎます。

于 2008-10-30T13:36:07.930 に答える
2

はい、経験則があります。コード分​​析ツールは、このための良い出発点です。

問題のコードに関する経験則:

コレクション プロパティのセッターを許可するのは悪い習慣です。これは、空のコレクションをコード内の完全なコレクションと同じように扱うのが簡単だからです。コレクションに対してnullチェックを強制すると、あなたは打ちのめされます。次のコード スニペットを検討してください。

public bool IsValid(object input){
  foreach(var validator in this.Validators)
    if(!validator.IsValid(input)
      return false;
  return true;
}

このコードは、バリデータのコレクションが空かどうかに関係なく機能します。検証が必要な場合は、バリデーターをコレクションに追加します。そうでない場合は、コレクションを空のままにします。単純。コレクション プロパティを null にすることを許可すると、上記の悪臭を放つコード バージョンが生成されます。

public bool IsValid(object input){
  if(this.Validators == null) 
    return false;
  foreach(var validator in this.Validators)
    if(!validator.IsValid(input)
      return false;
  return true;
}

コード行が増え、エレガントさが低下します。

次に、コレクション以外の参照型の場合、プロパティ値を設定するかどうかを決定する際に、オブジェクトの動作を考慮する必要があります。プロパティの既定値が明確に 1 つだけ存在するかどうか。または、プロパティの null 値には有効な意味がありますか?

あなたの例では、セッターで Name 値を常にチェックし、null が割り当てられたときにデフォルトの "(No name given)" に設定したい場合があります。これにより、このオブジェクトを UI にバインドするときに簡単になる場合があります。または、有効な名前が必要なため名前が null である可能性があり、最初に名前を設定せずに呼び出し元がオブジェクトに対してアクションを実行しようとすると、名前を確認して InvalidOperationException をスローします。

プログラミングのほとんどのことと同様に、何かを行うにはさまざまな方法があり、その半分は悪いものであり、残りの半分の各方法は特定の状況でのみ有効です。

于 2008-10-30T13:39:14.320 に答える
2

コンストラクターの目的は、オブジェクトを構築することです。これ以上の「セットアップ」は必要ありません。呼び出し元が知っている情報がある場合は、それをコンストラクターに渡す必要があります。

違う:

MyClass myc = new MyClass();
myc.SomeProp = 5;
myc.DoSomething();

右:

MyClass myc = new MyClass(5);
myc.DoSomething();

これは、myc を有効な状態にするために SomeProp を設定する必要がある場合に特に当てはまります。

于 2008-10-30T14:28:50.040 に答える
1

それは本当に依存します。

クラスが null プロパティで正しく動作することになっている場合は、初期化されていないままにしておくことができます。それ以外の場合は、コンストラクターで初期化することをお勧めします。

また、建設後にプロパティを変更したくない場合は、非公開にすることができます

class Xyz
{
     public Xyz(string name)
     {
         this.Name = name;
     }
     String Name 
     {
          get; 
          private set;
     }
}
于 2008-10-30T13:38:23.027 に答える
0

可能であれば、データをカプセル化してみてください。オブジェクトをリストとして公開するには、ユーザーがクラスに関する非常に多くの詳細を知っている必要があります。たとえば、null参照の例外を回避するために、リストを最初から作成する必要があるかどうかを知る必要があります。

public class Xyz
{
   private List<String> _names = new List<String>(); // could also set in constructor

   public IEnumerable<String> Names
   {
       get
       {
           return _names;
       }
   }

   public void AddName( string name )
   {
       _names.Add( name );
   }
}

これで、List、HashTable、Dictionaryなどを使用するかどうかは関係ありません。

于 2010-08-07T16:22:47.027 に答える