2012-04-27 10 views
2

Javaで可変と不変のノードを作成したいのですが、どちらも変更可能なものを除いてすべて同じでなければなりません。どのように基本クラスと2つの派生クラスの変更可能で不変なクラスを実装するのですか?可変クラスと不変クラス

+0

これはどのような「ノード」ですか?文脈とは何ですか?これらのクラスは継承のために公開されるべきですか?セッタークラスがなくても –

答えて

4

可変クラスと不変クラスの違いは、不変クラスにはセッターや内部状態を変更するその他のメソッドがないことです。状態はコンストラクタでのみ設定できます。

親クラスImmutableを呼び出すことは悪い考えです。なぜなら、これはサブクラスがあるときはもはや真ではないからです。名前は誤解を招きます:

ImmutableNode node = new MutableNode(); 
((MutableNode)node).change(); 
+0

のクラスは、リフレクションを使用して変更できます。最終変数だけが不変性を保証します – birdy

+0

@myx:フィールド*は、不変クラスでfinalとマークする必要があることに同意します。しかし、彼のサブクラス化のアイデアは不可能なので、ここではうまくいかない。変更可能なクラスは、最終フィールドを変更することもできません。正直言って私は最初にmutabilityのために継承を使うという考えは嫌いです。継承を使用せずにコードを共有するには、他の方法があります。インターフェイスと構成。 –

+2

@myx --- bzzztt。リフレクションによって最終変数を変更することはできますが、コンパイル時定数式としての資格を持つ静的最終フィールドは例外です。しかし、リフレクションを介してプライベート変数や最終変数を変更することは、BAD BADプラクティスとみなされます。これは、必死の最後の手段としてのみ実行する必要があります。 –

1

変更不可能なクラスは、一度作成した内容では変更できません。不変オブジェクトは、状態を変更できないオブジェクトです。

Javaのimmutableクラスの一般的な例は、Stringクラスです。

4

あなたは可変1、可変

public class MutableBase extends Base{ 
    public void setFoo(){} 
} 

immmutable 1を設定できるようにする必要が保護された変数

public class Base{ 
    protected int foo; 
} 

で単一の基本クラスを作成するだけですができるようにする必要があります変数を1回だけ設定する

public class ImmutableBase extends Base{ 
    public ImmutableBase(int foo){ 
      this.foo = foo; 
    } 
} 

ほとんどの不変のクラスには、t彼はの中でのインスタンスを変更せずに変数を変更します。文字列は、これは、あなたがこの程度のクールな事はあなたが少ない制御/心配各インスタンスの内部の上にあなたのクラスのユーザーに与えることである。この

public ImmutableBase add(int bar){ 
    return new ImmutableBase(this.foo+bar); 
} 

ような何かをしたいかもしれませんありません。 Javaではすべてがオブジェクト参照によって渡されるため、StringまたはImmutableBaseの周りを渡す場合、変更することを心配する必要はありません。

+0

コンパイルエラー。このようにすれば、 'foo'はプライベートにすることはできません。 –

+0

@StephenC - whoops、ありがとう – dfb

+0

フィールドを宣言すると、それは最終的に自己になりますか? – nabil

1

不変であるためには、それはfinal宣言されなければならず、またsetter メソッドを持ってはいけません。最終的な宣言は、それを拡張することができず、追加の変更可能なプロパティが追加されることを保証します。

class Base { 
    protected int var1; 
    protected int var2; 

    public getVar1() {return var1;} 
    public getVar2() {return var2;} 
    } 

    class Mutable extends Base { 
     public setVar1(int var1) {this.var1 = var1} 
     public setVar2(int var2) {this.var2 = var2} 
    } 

    final class Immutable extends Base { //final to avoid being extended and then implement the setters 

    } 

これは少しできますか?しかし、なぜこのようなシナリオが必要でしょうか?

+0

フィールドを宣言して最終的には自己宣言しませんか? – nabil

+0

彼は可変バージョンを望んでいるので?フィールドが最終的な場合は設定できませんが、変更可能なバージョンではフィールドを設定する必要があります。 – maress

+0

'final'クラス' Foo'だけが 'Foo'のインスタンスが本当に悪意ある変更可能な' Foo'のインスタンスにならないことを「保証」することができますが、継承可能な、抽象クラスであっても、不変として指定されているクラス(変更可能な派生クラスが「壊れた」とみなされる)を意味します。例えば、いくつかの文脈では、 'ImmutableMatrix'抽象クラスを定義すると便利です。その派生クラスには、' ImmutableArrayMatrix'(行列と同じサイズの配列を基にしたもの)、 'ImmutableConstantMatrix'(... – supercat

1

もう1つの方法は、UnmodifiableListと同じ戦略を使用することです。まず、型を指定するインタフェースを作成します。

interface List<T>{ 
    List<T> add(T t); 
    T getAt(int i); 
    ... 
} 

次に、あなたは、すべてのビジネス・ロジックを使用して変更可能なクラスを実装:

public class MutableList<T> implements List<T>{ 
    @Override 
    List<T> add(T t){ ... } 

    @Override 
    T getAt(int i){ ... } 

    ... 
} 

そして最後に、可変1のビューであるためにあなたの不変クラスを作成します。同じインターフェイスを実装しますが、表示されたオブジェクトにすべてのreadメソッド呼び出しを委譲し、Exceptionを使用して書き込みアクセスを禁止します。

public class UnmodifiableList<T> implements List<T>{ 
    //This guy will do all hard work 
    private List delegate; 

    public UnmodifiableList(List<? extends T> delegate){ 
     this.delegate = delegate; 
    } 

    //Forbidden mutable operation: throw exception! 
    @Override 
    List<T> add(T t){ 
     throw new UnsupportedOperationException("List is unmodifiable!"); 
    } 

    //Allowed read operation: delegate 
    @Override 
    T getAt(int i){ 
     return delegate.getAt(i); 
    } 

    ... 
} 

このアプローチは、あなたが一度だけのビジネスロジックを実装する利点を有し、第1 imutableオブジェクトにそれを回す前に、独自の方法や妥当性チェックを使用してオブジェクトを構築することができます。

+0

潜在的に変更可能なオブジェクトの読み取り専用ビューを提供するオブジェクトと、自身を作成し​​、変更する可能性のある任意のコンテキストで公開しないオブジェクトの読み取り専用ビューを提供するオブジェクトの区別に注意することが重要です。 「変更不可能な」という用語は、その点で少し曖昧です。私は、 "ReadableFoo"のような用語は、読み込み可能で、直接変更することはできないが、他の手段で変更することができるものを指しています。 "ImmutableFoo"は決して変更されないことが保証されているものを指します。 "Unmodifiable"は奇妙な中盤のようです。 – supercat

+0

はい、そうです。元のリストの所有者は内容を変更する可能性があり、その内容はビューに公開されます。一方で、ビューははるかに効率的で、計算上およびメモリ上で効率的です。正しいツールは何が使用されているかに依存し、残念ながら質問者はそれに関する多くの情報を提供しませんでした... –

関連する問題