2011-08-11 17 views
3

私は現在、反復ソルバーを実装しています。これは、特定の問題に対する解決策を逐次的に改善することによって機能します。解はかなり大量のデータであるため、精緻化が適切に行われます。可変オブジェクトを読み込み専用オブジェクトにカプセル化する

私は、反復が行われている間にアルゴリズムを見ることができるように、単純なObserver/Observableパターンを実装しました。特に、ソルバーは、解の現在の見積もりを返すメソッド

Foo getCurrentSolution() 

を提供します。オブザーバは、現在の見積もりに基づいて、いくつかの計算を自由に行うことができます(たとえば、ソリューションが十分であり、反復を停止できるかどうかを判断するなど)。 Fooは変更可能ですが、もちろん観測者が解の現在の見積もりを変更した場合、ソルバーの反復が損なわれる可能性があります。

したがって、getCurrentSolution()は本当に防衛的なコピーを返します。しかし、これには大きな問題で時間と記憶が必要なので、getCurrentSolution()は新しいReadOnlyFoo(bar)を返します。fooは解決策の(変更可能な)現在の見積もりで、ソルバー専用です。考え方は、ReadOnlyFooFooとほとんど同じインターフェイスを持っているということです。データを変更する可能性のあるメソッドだけが「非アクティブ化」されます(例外がスローされます)。いくつかのダミークラスのすべての詳細を以下に示します。

私の質問です:このアプローチは良い方法ですか?より良いパターンがありますか?

ありがとうございます! Collectionsクラスは、それが元のリストが含まれていますが、コレクションを変更するメソッド内での例外をスローするラッパーを返しunmodifiableList(...)などでないこと実際的なアプローチだ セバスチャン

public abstract class AbstractFoo{ 
    public abstract double getValue(); 

    public abstract void setValue(final double x); 

    public abstract AbstractFoo add(AbstractFoo bar); 

    public void addToSelf(AbstractFoo bar){ 
     setValue(getValue + bar.getValue()); 
    } 
} 

public class Foo extends AbstractFoo{ 
    private double value; 

    public Foo(final double x){ 
     value = x; 
    } 

    public double getValue(){ 
     return value; 
    } 

    public void setValue(final double x){ 
     value = x; 
    } 

    public AbstractFoo add(AbstractFoo bar){ 
     return new Foo(value + bar.getValue()); 
    } 
} 

public final class FooReadOnly extends AbstractFoo{ 
    private final Foo foo; 

    public FooReadOnly(AbstractFoo foo){ 
     this.foo = foo; 
    } 

    public double getValue(){ 
     return foo.getValue(); 
    } 

    public void setValue(final double x){ 
     throw new NotImplementedException("read only object"); 
    } 

    public AbstractFoo add(AbstractFoo bar){ 
     return foo.add(bar); 
    } 

    public void addToSelf(AbstractFoo bar){ 
     throw new NotImplementedException("read only object"); 
    } 
} 

答えて

3

Iは、読み取り専用メソッドを含むインタフェースSolution、およびすべてのメソッドを含む可変クラスMutableSolutionを定義し、getCurrentSolution()方法はSolutionインスタンスを返すことになるだろう。このようにして、防御的なコピーを作成するか、またはソリューションを読み取り専用ラッパーにラップする必要はありません。

もちろん、オブザーバーは解決策をMutableSolutionにキャストできますが、これは事故ではありません。キャストから身を守りたい場合はReadOnlySolutionラッパークラスを実装し、Solutionを実装し、ラップされたMutableSolutionに委譲してください。これは、メソッドのシグネチャがオブジェクトが変更可能でないことを明確にすることを除いて、命題に似ています。

+0

それは間違いなくきれいですが、私は 'Solution'の実装を変更できないと思いますか?私はそれを 'MutableSolution'から継承させることはできません。 – Sebastien

+0

次に、getCurrentSolutionによって返される読み取り専用メソッドのみを持つインターフェースを定義し、このインターフェースを実装し、変更可能オブジェクトに委譲するクラスを定義します。 –

+0

私は他の選択肢に満足していないので、私はこのために行くつもりだと思う。どうもありがとう。 – Sebastien

1

+0

私はそれを知らなかった。私はそれを調べます。誰かがこの問題を引き起こしました。ラップされたオブジェクトに新しいミューテータを追加すると、この方法はもはや安全です。 – Sebastien

+0

右。この問題は私のソリューションにはありません。 –

1

私はそれをしません。共通のインタフェース(実際の実装に存在する可能性もあります)のAbstractFooを使用する場合、現在のインスタンスが変更可能かどうかは事前に分かりません。したがって、ユーザーは未チェックの例外をスローする危険があります。

そして、不変オブジェクトの場合、変更不可能なものはまったく例外ではありません。言い換えれば、私はFooReadOnlyのインスタンスを修正しようとしたことを知らせるために執行猶予を使用しません。

少なくとも我々がテストできるように、我々はオブジェクトを変更することができれば、私は、抽象クラスAbstractFooに抽象メソッドboolean isModifiable()を追加すると思います。その場合、例外をスローする必要はありません。変更メソッドの実装は単純に何もできません。

+0

+1は例外に関する提案です。 – Sebastien

+0

私は依然として、開発者が契約を尊重していないことを明確にするために、例外をスローするメソッドを作成します。isModifiableがfalseの場合、setterメソッドを呼び出さないでください。私は標準のjava.lang.UnsupportedOperationExceptionを使用します。 –

+0

たとえば、 'Iterator'のような' UnsupportedOperationException'トリックが好きではありませんでした。あるメソッドから 'Iterator'のインスタンスを受け取り、それを使って要素を削除したいとしましょう:* this * iteratorが要素の削除をサポートしているかどうかを調べるためにチェックされていない例外を'試行 'し 'catch'する必要があります。 )JREのすべてのコード行が傑作であり、コピーする価値があるわけではありません; –

0

なぜこのような強化されたソリューションですか? 1つのクラスとreadOnlyブール値属性を持たないのはなぜですか?次に、各セッターについてcheckWriteable()を実行します。

+0

'readOnly'だけでなく' immutable'のフラグもなければなりません。彼らは同じことを意味するものではありません。解決策の現在の状態を知り、すぐに使用したいコードは、将来変更されるオブジェクトへの読み取り専用のラッパーで満足できますが、現在の状態のスナップショットを必要とするコードでは、既に不変であることが分かっていない限り*与えられたオブジェクト*。多くの図書館で、オブジェクトが不変かどうかを報告するためのサポートがほとんどないのは残念です。 – supercat

関連する問題