2016-05-22 38 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加入ALIST

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

爲super和subclass創建一個Factory-Method,並將構造函數設爲私有,強制每個想要實例使用factory方法的人。工廠方法是一種返回完全構造的實例的方法。一旦實例被完全構造(在工廠方法中調用構造函數之後),將該實例添加到列表中,這樣沒有線程可以獲得未完成/未完成的實例。

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

您能否澄清一下在'create'方法'final'中做對象引用的意義? –

+0

這確保放入列表的實例和返回的實例相同。它不能在任何時候重新分配。 – HopefullyHelpful

1

通過從HopfullyHelpful採取一些設計決策,我結束了最好的喜歡下面的設計:

​​