2017-05-05 4 views
0

Ich erstelle gerade ein großes Projekt für meine Firma, mit vielen Datenstrukturen und Shizle. Und ich suche nach einer guten Lösung für mein folgendes Problem:Alternative zum Konstruktor zurückgeben null

Da Java keine Möglichkeit hat, dass ein Konstruktor null zurückgibt (zumindest meine Forschung sagte das), brauche ich eine gute Alternative dazu.

Lassen Sie uns sagen, dass ich den folgenden Code haben (nur ein Beispiel Das eigentliche Projekt komplexer ist.):

public abstract class SuperClass 
{ 
    public SuperClass(Element element) 
    { 
     if(element != null) 
      readElement(element); 
    } 

    public abstract void readElement(Element element); 
} 

public class Foo extends SuperClass 
{ 
    private Bar bar1; 
    private Bar bar2; 
    private Bar bar3; 
    //... 

    public Foo(Element element) 
    { 
     super(element); 
    } 

    @Override 
    public void readElement(Element element) 
    { 
     this.bar1 = new Bar(element.getChild("bar1")); 
     this.bar2 = new Bar(element.getChild("bar2")); 
     this.bar3 = new Bar(element.getChild("bar3")); 
     //... 
    } 
} 

public class Bar extends SuperClass 
{ 
    private String value; 

    public Bar(Element element) 
    { 
     super(element); 
    } 

    @Override 
    public void readElement(Element element) 
    { 
     this.value = element.getChildText("value"); 
    } 
} 

die Element.getChild (String name) Funktion von jdom2 ist (XML-Parser), verwendet zum Lesen von XML-Dateien. Es kann und wird null zurückgeben, wenn ein Kind mit dem angegebenen Namen nicht gefunden wurde. Ich habe mein Projekt auf der Grundlage dieses Beispiels geschrieben, dummerweise denkend, dass wenn die benannte Funktion null zurückgibt, die Variable (hier zum Beispiel bar1) ebenfalls null wäre. Aber da die benannte Funktion mit einem "neuen Balken (...)" umhüllt ist, wird sie nicht null sein, stattdessen wird es ein leeres Objekt sein. Aber ich will und brauche die "leeren" Variablen, um null zu sein, also kann ich diese leicht überspringen, wenn ich durch alle Datenstrukturen in meinem Projekt iteriere. würde ich das zurückgegebene Objekt aus dem „getChild (...)“ Funktion in eine lokale Variable „lElement“ speichern und dann etwas wie:

if(lElement != null) 
    bar1 = lElement; 

aber ich habe über 50 verschiedene Datenstrukturen, wie sie in meinem Beispiel und mehr als genug Variablen in ihnen, die durch die Funktion "readElement (...)" initialisiert werden. Diese Idee würde viel zu viel Bearbeitung und wahrscheinlich sogar eine angemessene Menge an Leistung erfordern. Auch scheint es etwas ... "hässlich" für mich. Zumindest für diese Menge an Variablen. Ich brauche also etwas, was keinerlei Auswirkungen auf die Performance hat und so einfach ist, dass der Konstruktor null zurückgibt. Ich würde es vorziehen, nicht zu viel Code in diesen Funktionen zu ändern. Ich hatte auch die Idee, die Datenstruktur auf Null setzen zu lassen, wenn "Element element" gleich Null ist, aber nach kurzer Recherche wurde diese Idee sofort gelöscht ^^. Ein Objekt, das sich selbst löscht, funktioniert nicht und ist sowieso nicht logisch.

So grundlegend konnte ich dieses Problem selbst beheben. Aber wahrscheinlich wäre es nicht der effizienteste Weg. Sowohl bei der Bearbeitung des Codes als auch bei der Code-Performance. Deshalb frage ich euch, wie Sie dieses Problem lösen würden. Ich denke nicht nur an zwei einfache Datenstrukturen wie in meinem Beispiel, sondern an 50 Klassen, die dieses System nutzen.

Ich hoffe, Sie können mir helfen, und ich entschuldige mich für jedes schlechte Englisch. Ich komme aus Deutschland ^^. Ich habe jetzt seit über 5 Jahren in Java programmiert ("professionell" seit letztem Jahr), also ist es ein bisschen peinlich für mich, dieses Problem nicht früher gedacht zu haben. Aber jetzt ist es zu spät, um etwas völlig anderes wiederzufinden.

Vielen Dank im Voraus!

+0

Anstatt "null" zurückzugeben, sollten Sie eine (Laufzeit-) Ausnahme auslösen. Die Rückgabe von 'null' zwingt Sie dazu, Ihren Code mit * null'-Checks * zu überladen, was noch hässlicher ist. –

+0

Vielleicht ist es eine unglückliche Wahl, eine abstrakte Methode in einem Konstruktor aufzurufen. Siehe auch [dies] (http://stackoverflow.com/questions/15327417/is-it-ok-to-call-abstract-method-from-constructor-in-java) SO Frage. –

+0

@Timothy Die Verwendung von Ausnahmen würde mich zwingen, meinen Code mit try/catch zu überladen, was meiner Meinung nach sogar noch schlimmer aussieht. Ich möchte nicht, dass alle Variablen übersprungen werden, wenn der erste den Nullzeiger bekommt. – Apahdos

Antwort

0

Konstruktoren definieren die Initialisierung eines beliebigen Objekts. Daher könnten sie niemals Werte zurückgeben.

Ich würde argumentieren, dass das Fehlen einer hasElement-Methode ein wesentlicher Konstruktionsfehler ist, aber dennoch, wenn Sie darauf bestehen, null zurückzugeben, können Sie.

In jedem Fall sollten Sie Generika und Methodenreferenzen nutzen (> = Java 8).

Sie könnten die Wrap-Methode im Codebeispiel für Ihre Anforderungen verwenden (Verwenden von Vererbung, um Unterklassen das Lesen von untergeordneten Elementen zu erleichtern).

public void readElement(Element element) { 
    this.bar1 = wrap(element.getChild("bar1"), Bar::new); 
    this.bar2 = wrap(element.getChild("bar1"), Bar::new); 
    this.bar3 = wrap(element.getChild("bar1"), Bar::new); 
} 

protected <T> T wrap(Element element, Function<Element, T> elem) { 
    if (element == null) { 
     return null; // Not a good value 
    } 
    return elem.apply(element); 
} 
+0

hmm. Ich habe noch nie mit einer solchen Wrap-Methode gearbeitet. Was genau macht die Funktion <>? Ich schreibe nicht eine neue Funktion für jedes Mal, wenn ich wrap (...) verwende, indem ich eine neue lokale Klasse der Funktion <..>? Weil die Funktion <...> eine Schnittstelle zu sein scheint. Auch (nicht ganz wissen, was Sie mit der Funktion hasElement() meinen) Ich habe so etwas nicht hinzugefügt, weil ich dachte, dass es zu viel Leistung und Programmieraufwand kosten könnte, den Null-Check jedes Mal zu initialisieren ... – Apahdos

+0

... eine Variable. Wie ich bereits sagte, mit mehr als 50 verschiedenen Datenstrukturen mit jeweils bis zu 10 verschiedenen Variablen (von denen einige Listen sind), wäre es ziemlich anstrengend, "if (hasElement (...) {...}" zu verwenden. Jedes Mal – Apahdos

+0

Ich benannte die Methode wrap aufgrund seiner Funktionalität.Wraping das angegebene Element in einem anderen Typ (T). Sie schreiben keine neue Funktion aufgrund der Tatsache, dass Sie den Konstruktor der Klasse übergeben können (Balken: hasElement sollte innerhalb von jdom implementiert worden sein, so dass du die Zuweisung mit element.hasChild ("foo") vereinfacht haben könntest. new Baz (element.getChild ("foo")): null Das ist nichts, was du hättest – manf

0

Eine Alternative zu den null zurückgebenden Konstruktoren ist null.

Obwohl Sie nicht

class SomeClass { 
    public SomeClass(Node node) { 
     if (node.isEmpty()) return null; // Does not compile 
     ... 
    } 
} 

schreiben können, können Sie dies mit Sicherheit schreiben:

class SomeClass { 
    private SomeClass(Node node) { 
     // Self-check: this should never happen 
     if (node.isEmpty()) { 
      throw new IllegalArgumentException("node"); 
     } 
     ... 
    } 
    public static SomeClass makeFromNode(Node node) { 
     if (node.isEmpty()) { 
      return null; 
     } 
     return new SomeClass(node); 
    } 
} 

Ersetzen Konstruktor mit Aufrufen an makeFromNode Anrufe lassen Sie Situationen verarbeiten, wenn der Knoten null in einer einfachen und gleichförmig ist Weg.

+1

Ah das ist eigentlich eine nette Art, es zu tun. Es wird ziemlich anstrengend sein, alle meine Anrufe zu ändern, aber es wird tatsächlich nichts an der Leistung ändern und scheint (zumindest denke ich es) den geringsten Aufwand zu erfordern, die Anrufe zu ändern, da ich eine erstklassige Klasse habe Ich kann die statische Funktion hinzufügen. Vielen Dank! Wieder etwas Neues gelernt ^^ – Apahdos

+0

Ah ... warte. Es könnte nicht so einfach sein. Ich habe viele verschiedene Datenstrukturen, die so genannt werden. Sie alle haben unterschiedliche Getter. Also müsste ich die Methode für jede einzelne Klasse manuell erstellen, da (in meinem Beispiel des ursprünglichen Posts) Superclass keine Funktionen hat, Bar aber zB eine getValue() Methode ... Fehle ich hier etwas, oder kann ich Ihre Methode nicht in eine Superklasse schreiben lassen, also muss ich sie nicht für jede Klasse manuell machen? – Apahdos

+0

@Apahdos Statische Methoden sind nicht überschreibbar, daher würde die Methode in der Basisklasse den Konstruktor aus der Basisklasse aufrufen, was nicht gewünscht ist. Wenn Sie nicht alle Klassen durchsuchen und diese Änderung vornehmen möchten, können Sie eine separate Klasse "MyClassFactory" mit statischen Methoden für jede Unterklasse erstellen, die Sie erstellen möchten. Sie benötigen jedoch eine Methode pro Klasse. – dasblinkenlight