2010-11-30 2 views
8

最近、私は、オブジェクトモデルとその結果の条件と副作用で、読み書き可能な依存関係の問題を大幅に減らすために、不変のオブジェクトを過度に使用すると主張しています。管理(一種の機能プログラミング - エスク)インターフェイスを使用して読み書きの問題を分ける最も良い方法は?

この習慣は、作成/構築時に値を提供される読み取り専用オブジェクトを作成し、外部呼び出し側が公開プロパティーにアクセスするためのパブリックgetterのみを使用できるようにしました。保護された内部および専用のセッターを使用すると、オブジェクトモデルへの書き込みよりも内部制御を維持できます。

インターフェイスを作成してオブジェクトモデルにAPIを作成するとき、私は不変性について同じ問題を検討し始めました。たとえば、私のインターフェースにパブリックゲッターだけを提供し、それを設定者に任せて、その設定をどのように扱うかを決定することができます。

public interface IValuableItem { 
    decimal Amount {get;} 
    string Currency {get;} 
} 

私は私が提供しなければならないかを不思議に着いしかし:

私が話しているの実装のための「読み取り専用」のインターフェースの例は、(単なるデモンストレーション用)この貴重なアイテムです(そしてもしあれば)を許可し、同じインタフェース内でこれらの操作を結合してその不変性を「汚す」ことがないようにします。

私の頭の上から、次の考えが頭に浮かんできました。私が賛否両論だと思っていることをそれぞれ提供することなく、とは何ですか?このコンセプトを管理するための業界で共通のコーディング方法がありますか?

// companion writer 
public interface IValuableModifier { 
    decimal Amount {set;} 
    string Currency {set;} 
} 

又は

// explicit methods to enforce importance of or deviance in the programming 
public interface IValuableModifier { 
    void SetAmount(decimal val); 
    void SetCurrency(string cur); 
} 

又は

// companion writer that inherits the original interface 
public interface IValuableModifier : IValuableItem { //... 

又は

// Let a concrete class choose one and/or the other. 
class Concrete : IValuableModifer, IValuableItem { //... 

又は

等..
それ以外の不変なプログラミングモデルで書くのを手伝ってもらい、それを適度に柔軟に保つことができます。

+0

'set'アクセサのみを提供する' public'または 'protected'プロパティを持つクラスはコード解析の警告を発します[CA1044:プロパティは書き込み専用ではありません](https://msdn.microsoft.com/ ja-jp/library/ms182165.aspx)。 – DavidRR

答えて

9

setterを持ちますがgetterはありません)。しかし、それを実装するオブジェクトには、任意の純関数コードで使用できる不変バージョンのインタフェースもあります。

+0

+1:* setterを持っていてgetterを持たないインターフェースを持つのは意味がないと思う* - 同じものに対して正当な理由がない限り。 –

+0

@KMån - 私は同意します。私は数回インターフェイスを設定しようと試みましたが、ほとんどの場合、どこかで「取得能力」を少し必要とするため、価値がありません。上記の 'IMutableValuable'は、変更可能で不変なインターフェースを継承することで作成できますが、YAGNIです。 – Kit

+0

@KMån:オブジェクトの複雑な評価が独自の評価中にオブジェクトの状態に依存しないように、評価中の副作用を回避し、機能的な意味を強要したいときに正当化される可能性があります。そのような場合、読み取り専用アクセスなしで書き込み専用インタフェースを提供することが正当化されるかもしれない。しかし、特に適切に設計することは容易ではありません。通常は、メソッドを適切に指定する必要があります。通常は、メソッドを参照する必要があります。 – Hibou57

1

私は3番目と4番目の選択肢を組み合わせることが、変更可能な&不変型を実装するより良い方法だと考えています。

Public interface ImmutableItem { 
    decimal Amount {get;} 
    string Currency {get;} 
} 

Public interface MutableItem: ImmutableItem { 
    decimal Amount {set;} 
    string Currency {set;} 
} 

class Concrete : ImmutableItem { 
    //Only getters 
} 


class Concrete : MutableItem { 
    //Both getters & setters 
} 

これはきれいで、それは外の世界に公開したいれる可変性の種類を決定する具体的なクラスをしましょう。

public interface IValuableItem 
{ 
    decimal Amount { get; } 
    string Currency { get; } 
} 

public interface IMutableValuable : IValuableItem 
{ 
    new decimal Amount { set; get; } 
    new string Currency { set; get; } 
} 

class Item : IMutableValuable 
{ 
    public decimal Amount { get; set; } 
    public string Currency { get; set; } 
} 

この方法であなたの可変インタフェースはフルゲッターとセッターを持っている(私はそれが持っていることは理にかなっていないと思う:私はあなたのアイデアのバリアントを使用するかもしれないと思う、このような何か

+2

アイテムが自身を不変アイテムと呼ぶ場合、消費者は変更されないと安全に仮定することができます。定義されたMutableItemはImmutableItemにキャストできるため、その仮定は成り立たない。 ImmutableItemとMutableItemの両方に継承されるReadonlyItemを持つ方がよいでしょう。 – supercat

3

あなたのオブジェクトが不変である(そしてあなたのアプリケーションを不変のデータの概念の周りにデザインする)なら、オブジェクトは本当に不変のままでなければなりません。

不変のシナリオでデータを修正するための標準的な方法は、新しいオブジェクトを作成することですので、私はこのような何かを示唆している:

public interface IValuableItem<T> 
{ 
    decimal Amount { get; } 
    string Currency { get; } 
    T CreateCopy(decimal amount, string currency); 
} 

public class SomeImmutableObject : IValuableItem<SomeImmutableObject> 
{ 
    public decimal Amount { get; private set; } 
    public string Currency { get; private set; } 

    public SomeImmutableObject(decimal amount, string currency) 
    { 
     Amount = amount; 
     Currency = currency; 
    } 

    public SomeImmutableObject CreateCopy(decimal amount, string currency) 
    { 
     return new SomeImmutableObject(amount, currency); 
    } 
} 

SomeImmutableObject obj = new SomeImmutableObject(123.33m, "GBP"); 
SomeImmutableObject newObj = obj.CreateCopy(120m, obj.Currency); 
2

は、Builderパターンを使用することを検討してください:Builderオブジェクトは、コアオブジェクトの不変インスタンスを構築します。 .NETの文字列はこのようなものです。文字列オブジェクトは不変であり、文字列オブジェクトの効率的な構築のためのStringBuilderクラスがあります。 (String + string + stringは、StringBuilderを使用した場合よりもはるかに効率が悪い)

ビルダーオブジェクトは、インタフェース自体。

不変オブジェクトがスレッド/同時実行/並列実行シナリオの多くの頭痛やデータキャッシング/データバージョン管理のシナリオを洗い流すので、システムを不変オブジェクトで実行するよう努力する価値があります。

4

ReadableFoo、ImmutableFoo、およびMutableFooには別々のインターフェイスが必要です。後者の2つは、最初から継承する必要があります。 ReadableFooには、不変であることが保証されているFooを返す "AsImmutable"メソッドが含まれていなければなりません(不変のインスタンスはそれ自身を返さなければならず、変更可能なインスタンスはそのデータを含む新しい不変のインスタンスを返さなければなりません)、おそらく "AsNewMutable"元のデータが変更可能かどうかに関係なく、同じデータを含む新しい可変インスタンスを作成します)。

ImmutableFooとMutableFooの両方を実装するクラスはありません。

+0

私はこの回答も面白いと思います。あなたは「should」と言っています - これは私がさらに読むことができる一般的な習慣や仕様に基づいていますか? –

+0

@ John K:オブジェクトが不変であると主張する場合、それを使用する人は決して変更されないことを約束します。オブジェクトが変更可能であると主張する場合、それを使用する誰もが変更を許可されることを約束します。変更しない限り、変更はオブジェクトの次回読み込み時に反映されます。私は不変で変更可能な "ModelTFordColor"クラスを持つことができると思います(黒であればいつでも色をつけることができますし、色はあなたが設定したものになります)クラスが変更可能であり不変であるための有益なシナリオを考えないでください。 – supercat

+1

@ John K:ImmutableFooとMutableFooの両方を実装できるクラスはないとは言いませんが(何もクラスがそのことを行うことを妨げるものはありません)、本当の効果がないような小さなケース両方のインタフェースを実装すると、少なくとも1つのインタフェースの契約に違反します。 – supercat

関連する問題