2016-05-22 4 views
4

でコンストラクタの後に、私はいつも問題は次の通りであるオブジェクト自体は常にJavaの

public abstract class A{ 
    public A(X x){ 
     //init A stuff 
     x.getAList("stuff").add(this); 
     x.getAList("otherstuff").add(this); 
    } 
} 

public class B extends A{ 
    public B(X x){ 
     super(x); 
     //init B stuff 
    } 
} 

public class C extends A{ 
    public C(X x){ 
     super(x); 
     //init C stuff 
     x.getAList("otherstuff").remove(this); 
     x.getAList("morestuff").add(this); 
    } 
} 

public class SomeClass{ 
    private X someX; 

    public A somefunc(boolean b){ 
     if(b){ 
      return new B(someX); 
     }else{ 
      return new C(someX); 
     } 
    } 
} 

に依存したコードの特定のビットを実行するために必要な状況を持っている方法を実行します。この例では、コンストラクタでthisを使用します。別のスレッドがsomeX.getAListを介してオブジェクトにアクセスしようとすると、そのスレッドはコンストラクタが終了する前にそのオブジェクトにアクセスできる可能性があります。オブジェクトがsomefuncによって連想リストに追加されますように

あなたはそれを作ることができ

public class SomeClass{ 
    private X someX; 

    public A somefunc(boolean b){ 
     A a; 
     if(b){ 
      a = new B(someX); 
      someX.getAList("stuff").add(a); 
      someX.getAList("otherstuff").add(a); 
     }else{ 
      a = new C(someX); 
      someX.getAList("stuff").add(a); 
      someX.getAList("morestuff").add(a); 
     } 
     return a; 
    } 
} 

問題はBさんとCさんも他の場所でインスタンス化することができ、そのたびBまたはCが作成されますが、彼らが必要となるということですその特定の方法で追加することができます。 AListにオブジェクトを追加するのは、ユーザーの責任ではなく、クラスの責任であることを望みます。私はまた、ユーザーがこれを行うinit関数を呼び出す必要はありません。一方、私は並行性の問題を望んでいません。

これを実装する方法やパターンはありますか?

Golangには、関数/メソッド/コンストラクタの実行後にコードを実行できるようなものがあります。

答えて

9

代わりにスーパークラスとサブクラスのファクトリメソッドを作成し、コンストラクタをプライベートにして、インスタンスを必要とするすべての人にファクトリメソッドを使用させます。ファクトリメソッドは、完全に構築されたインスタンスを返すメソッドです。インスタンスが完全に構築されたら(コンストラクタがファクトリメソッドで呼び出された後)、リストにインスタンスを追加します。その場合、スレッドは不完全/未定義のインスタンスを保持できません。

Factory-Methodのポイントは、初期化コード以外のコードからすべての初期化コードを厳密に分離して、初期化されていないフィールドへのアクセスや公開を避けることです。また、それはユーザーのためのセレクタ、自動的に指定されることなく、適した(サブ)タイプを返すとしての役割を果たすことができます。(Interesting design-patterns

abstract class A{ 
    protected A(){ 
     //constructor code goes here 
    } 
    public void afterFinalisation(final X x) { 
     x.getAList("stuff").add(this); 
     x.getAList("otherstuff").add(this); 
    } 
} 

class B extends A{ 
    protected B(){ 
     super(); 
     //constructor code goes here 
    } 
    public static B create(final X x) { 
     final B returnValue = new B(); 
     returnValue.afterFinalisation(x); 
     return returnValue; 
    } 
} 

class C extends A{ 
    protected C(){ 
     super(); 
     //constructor code goes here 
    } 
    @Override 
    public void afterFinalisation(final X x) { 
     super.afterFinalisation(x); 
     x.getAList("otherstuff").remove(this); 
     x.getAList("morestuff").add(this); 
    } 
    public static C create(final X x) { 
     final C returnValue = new C(); 
     returnValue.afterFinalisation(x); 
     return returnValue; 
    } 
} 

class SomeClass{ 
    private final X someX = new X(); 

    public A somefunc(final boolean b){ 
     if(b){ 
      return B.create(this.someX); 
     }else{ 
      return C.create(this.someX); 
     } 
    } 
} 

をコンストラクタコードのクレジットが、私がしようとしていたcoolcats iteration of my answerに行きますプロテクトされたコンストラクタにコードを入れずに、代わりにinit()メソッドを使って作業してください。最終的なフィールドには大きな不安がありました。

+0

感謝を。あなたの最終版は少し上ですが、自分のコードをどのように構造化したいのか分かりました。私のコードを自分の投稿した答えで見ることができます。 –

+0

'final'の' create'メソッドの中でオブジェクト参照を作成する点は何ですか? –

+0

これは、リストに入れられたインスタンスと返されるインスタンスが同じであることを確認します。いつでも再割り当てすることはできません。 – HopefullyHelpful

1

HopfullyHelpfulから、いくつかの設計上の決定を取ることによって、私は最高の次のデザインを好きで終わる:あなたの入力のための

​​
関連する問題