2016-05-22 4 views
4

Ich habe eine Situation, wo ich immer ein gewisses Stück Code ausführen müssen, die sich auf dem Objekt hängtImmer Verfahren nach Konstruktor in Java ausführen

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); 
     } 
    } 
} 

Das Problem ist die folgende. In diesem Beispiel verwende ich this im Konstruktor. Wenn ein anderer Thread versucht, über someX.getAList auf das Objekt zuzugreifen, kann dies dazu führen, dass dieser Thread auf das Objekt zugreift, bevor der Konstruktor beendet wurde.

Man könnte es machen, so dass das Objekt den AList von someFunc hinzugefügt wird

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; 
    } 
} 

Das Problem ist, dass B und C ist auch an anderer Stelle instanziert werden könnte und dass jedes Mal ein B oder C erstellt sie müßten auf die angegebene Weise hinzugefügt werden. Ich möchte nicht, dass das Objekt dem AList hinzugefügt wird, sondern die Verantwortung des Benutzers, aber der Klasse. Ich möchte auch nicht, dass der Benutzer eine Init-Funktion aufrufen muss, die dies für sie tut. Auf der anderen Seite möchte ich keine Nebenläufigkeitsprobleme.

Gibt es einen Weg oder ein Muster, das es ermöglicht, dies zu implementieren?

Golang hat so etwas wie defer, mit dem Sie einen Code ausführen können, nachdem die Funktion/Methode/Konstruktor ausgeführt wurde.

Antwort

9

Erstellen Sie stattdessen eine Factory-Methode für die Super- und Unterklasse, und machen Sie die Konstruktoren privat, sodass alle, die eine Instanz haben möchten, die Factory-Methode verwenden müssen. Eine Factory-Methode ist eine Methode, die eine vollständig konstruierte Instanz zurückgibt. Sobald die Instanz vollständig aufgebaut ist (nachdem der Konstruktor in der Factory-Methode aufgerufen wurde), fügen Sie die Instanz zur Liste hinzu, so dass kein Thread eine unvollständige/nicht finalisierte Instanz erhalten kann.

Der Sinn der Factory-Methode besteht darin, den gesamten Initialisierungscode von allen Nicht-Initialisierungscodes zu isolieren, um den Zugriff auf nicht initialisierte Felder zu vermeiden. Auch kann es als Selektor für Benutzer dienen, automatisch eine passende (Teil-) Art Rückkehr, ohne angegeben werden müssen. (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); 
     } 
    } 
} 

Der Kredit für den Konstruktor Code geht zu coolcats iteration of my answer, ich habe versucht, Vermeiden Sie das Einfügen von Code in die geschützten Konstruktoren und arbeiten Sie stattdessen mit einer init() -Methode, die eine große unelegante Umgehung für die letzten Felder erforderte.

+0

Vielen Dank für Ihre Eingabe. Obwohl Ihre endgültige Version ein wenig übertrieben ist, haben Sie mir eine Idee gegeben, wie ich meinen Code strukturieren möchte, den Sie in meiner eigenen eingereichten Antwort sehen können. –

+0

Könntest du bitte klarstellen, was es bedeutet, einen Objektverweis innerhalb 'create' Methoden' final' zu machen? –

+0

Dadurch wird sichergestellt, dass die in die Liste und die zurückgegebene Instanz identisch ist. Es kann zu keinem Zeitpunkt neu zugewiesen werden. – HopefullyHelpful

1

Durch einige Designentscheidungen von HopfullyHelpful nehmen ich am Ende mit Vorliebe die folgenden Design am besten:

public abstract class A{ 

    protected A(X x){ 
     //constructor with all inits 
    } 
    protected A publish(X x) { 
     x.getAList("stuff").add(this); 
     x.getAList("otherstuff").add(this); 
     return this; 
    } 
} 

class B extends A{ 
    protected B(X x){ 
     super(x); 
     //constructor with all inits 
    } 
    protected B publish(X x) { 
     super.publish(x); 
     return this; 
    } 
    public static B create(X x) { 
     return new B(x).publish(x); 
    } 
} 

class C extends A{ 
    protected C(X x){ 
     super(x); 
     //constructor with all inits 
    } 
    protected void publish(X x) { 
     super.publish(x); 
     x.getAList("otherstuff").remove(this); 
     x.getAList("morestuff").add(this); 
     return this; 
    } 
    public static C create(X x) { 
     return new C(x).publish(x); 
    } 
} 

class SomeClass{ 
    private X someX; 

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