2009-05-14 5 views
6

だから私が得た値を設定するために、クラス内のフィールドまたはプロパティを使用する必要があります:私はコードの一部を超える同僚との友好引数に

public sealed class NewObject 
{ 
    private string _stuff = string.Empty; 

    public string Stuff 
    { 
     get { return GetAllStuff(); } 
    } 

    private string GetAllStuff() 
    { 
     //Heavy string manipulation of _stuff 
    } 

    public NewObject(string stuffToStartWith) 
    { 
     _stuff = stuffToStartWith; 
    } 

    public static NewObject operator +(NewObject obj1, NewObject obj2) 
    { 
     if (obj1 == null) 
      throw new ArgumentNullException(); 

     if (obj2 == null) 
      throw new ArgumentNullException(); 

     NewObject result = new NewObject(string.Empty); 
     result._stuff = String.Concat(obj1._stuff, obj2._stuff); 

     return result; 
    } 
} 

引数は、演算子のオーバーライドを超えていました。私の同僚は、コンストラクタ以外のプライベートフィールドの値を設定するのがプログラミングのベストプラクティスではないと感じています。私の同僚が提案した解決策は、Stuffプロパティの名前をAllStuffにリファクタリングし、getsetアクセサを持つプロパティStuffを追加し、オペレータオーバーライドで新しいStuffプロパティを使用することでした。

public static NewObject operator +(NewObject obj1, NewObject obj2) 
    { 
     if (obj1 == null) 
      throw new ArgumentNullException(); 

     if (obj2 == null) 
      throw new ArgumentNullException(); 

     NewObject result = new NewObject(string.Empty); 
     result.Stuff = String.Concat(obj1.Stuff, obj2.Stuff); 

     return result; 
    } 

私はそれに似ています。私はクラスの外でプロパティを読み取り専用に保つので、最初の方法が優れていると感じています。私の質問は、どのようにオブジェクト指向設計のベストプラクティスですか?

答えて

7

あなたはプロパティにprivate set(プロパティの構文を使用できるようにしながら可視性または不足を保持します)を与えることができますが、実際にはその点には対応していません。

クラス内では、変数は公正なゲームだと言います。継承されたクラスを含む外部のどこでも、プロパティはgetsetであるべきですが、宣言クラス内で私はプライベートメンバーを割り当てることができます。

2

あなたは右

誤る...詳しく説明するなら、あなたのプライベート変数は、あなたがあなた下さいとしてやっています。他の人がオブジェクトの値を変更する操作(特に+のような操作)を行った場合、コンストラクターの外で値を変更することは間違いありません。彼らの全体のポイントはプライベートであることを忘れないでください。

あなたはそれが不変場合を除き...

更新
より多くの私はそれについて考え、より多くの私はあなたの同僚は、「一定の」ものと「プライベート」変数を混乱さ信じている - または多分2つの概念をマージします。あなたの友人が暗示しているように見えますが、プライベート変数がオブジェクトの生涯を通して同じままでなければならない理由はありません。 constは変更されず、プライベートはオブジェクトに対してのみ、2つの非常に明確なパターンです。そして変数が絡み合っている(のchar *とlenを持っていること、文字列オブジェクトを考えると、でなければならない - あなたのオブジェクトは単なる文字列以上のものを持って突然場合

アップデート2
はまた、彼のデザインは、離れて落ちます一緒に維持される)。最後に、ユーザーがオブジェクトの内部変数に対処しなければならないことがあります。オブジェクトをオブジェクトとし、それ自身の内部値を保持し、単一のエンティティをユーザに提示する。

+0

@cyber:これはもっとOPの問題ではないと思います。彼の同僚は、コンストラクタやプロパティの実装の外で直接的にプライベート変数を変更しないことを提唱していたように私には聞こえました。私は彼がオブジェクトの生活のために同じ値を保つことを主張していたとは思わない。 –

1

私は彼のアプローチの利点が何であるか分かりません。

0

私は個人的にpublic読み取り専用プロパティを設定しなければなりませんので、私が代わりにprivateフィールドとpublic-getprivate-setプロパティの自動実装privateプロパティを使用して、まったくのフィールドを持っていないことを好みます。
プロパティにコードを追加する必要がある場合は、プロパティアクセサーの内部でフィールドを使用し、getterとsetterをコンストラクタを含むどこにでも使用します。
readonlyフィールドが必要な場合でもフィールドを使用する必要がありますが、C#4.0では読み取り専用プロパティが導入されます。


さらに、以下のコードを使用することで、この問題を回避できました。

public static NewObject operator +(NewObject obj1, NewObject obj2) 
{ 
    return new NewObject(String.Concat(obj1.Stuff, obj2.Stuff)); 
} 

私れる好ましい実装では、このようなものになるだろう。

public sealed class NewObject 
{ 
    private String Stuff { get; set; } 

    // Use a method instead of a property because the operation is heavy.  
    public String GetAllStuff() 
    { 
     // Heavy string manipulation of this.Stuff. 
     return this.Stuff; 
    } 

    // Or lets use a property because this.GetAllStuff() is not to heavy. 
    public String AllStuff 
    { 
     get { return this.GetAllStuff(); } 
    } 

    public NewObject(String stuffToStartWith) 
    { 
     this.Stuff = stuffToStartWith; 
    } 

    public static NewObject operator +(NewObject obj1, NewObject obj2) 
    { 
     // Error handling goes here. 

     return new NewObject(String.Concat(obj1.Stuff, obj2.Stuff); 
    } 
} 
+0

「読み取り専用プロパティ」の意味を誤解していますか?今、私はセッターなしでプロパティをコーディングすることができます。これは読み取り専用です... –

2

一般的な問題は契約ポリシーと関連があります。

(パブリックセット)プロパティの概念は、それが呼び出されると、状態の変化の意味概念に加えて、他のアクションがとられることがあります。たとえば、セッターを呼び出すと、イベントが発生したり、周辺機器を起動したりすることがあります。

あなたの同僚は、このプロパティを使用しないことによって、契約をサイドステップしていて、イベントは発生しないと言っています。

だからここにあなたがビューの同僚の視点から行う必要があります。

this.Prop = CalculateSomeValue(); 
if (this.Prop < kPropMin) { 
    this.Prop = kPropMin; 
} 
else if (this.Prop > kPropMax * 2) { 
    this.Prop = kPropMax * 2; 
} 
this.Prop = this.Prop/2; 

は今、これは不自然なケースですが、私はちょうど取得に3回が可能ヘビー級プロパティを打つとアップしましたセットで3回、それらの1つは違法かもしれません(kHighLimit/2に設定)。私はこれを回避するには、ローカルを使用し、セットを正確に一度最後に呼び出します。しかし、私はむしろフィールドで混乱するだろう。

もっと良いアプローチは、それを実用的に取ることです:あなたがクラスの中のプロパティを使うのは、セットやgetのすべての副作用を呼び出す場合だけです。そうでなければ、プロパティの精神に従ってください。

- 明確化 - は、財産の精神に従うのが私のセットのプロパティは、このようになっていることを言わせてで:私は汚れた細部の多くを因数分解してきました。この中

bool PropValueOutOfRange(int val) { 
    return val < kPropMin || val > kPropMax; 
} 

public int Prop { 
    set { 
     if (PropValueOutOfRange(value)) 
      throw new ArgumentOutOfRangeException("value"); 
     if (PropValueConflictsWithInternalState(value)) 
      throw new ArgumentException("value"); 
     _prop = value; 
     NotifyPeriperalOfPropChange(_prop); 
     FirePropChangedEvent(/* whatever args might be needed */); 
    } 
} 

が、それは私にそれらを再利用させます。だから今私はプライベートフィールド_propに触れることに自信を持っています。私はそれを私が範囲内に保ち、周辺機器に通知してイベントを起こすのと同じインフラを持っているからです。

これは私がこのコードを書くことができます:

_prop = CalculateSomeValue(); 

if (_prop < kPropMin) 
    _prop = kPropMin; 
else if (_prop > kPropMax * 2) 
    _prop = kPropMax; 

_prop /= 2; 

NotifyPeripheralOfPropChange(); 
FirePropChangedEvent(); 

私は財産の精神の範囲内で働いているので、プロパティを構築するために使用されたものと同じツールを使用しています。私は正しい範囲を維持しています(しかし、スローしないでください、私は実装者です)、周辺と火災のイベントを打つ、私はそれを慎重に、読みやすく、効率的に - 無差別にしません。

+0

+1これを読んだ後、これはおそらく私の同僚の思考プロセスだと思います。しかし、コードの紛争の目的のために、プロパティは決して何らかの理由でクラス外で変更すべきではありません。 –

+0

質問:あなたの実践的なアプローチでは、「財産の精神に従う」と言ったとき、プロパティがクラス外で決して変更されない場合は、フィールドを使って上記のように更新することを意味しますか? –

関連する問題