Ich habe mich gefragt, was der beste (dh sauberste/sicherste/effizienteste) Weg zum Umgang mit mehreren Konstruktoren in Java ist. Besonders wenn in einem oder mehreren Konstruktoren nicht alle Felder angegeben sind:
public class Book
{
private String title;
private String isbn;
public Book()
{
//nothing specified!
}
public Book(String title)
{
//only title!
}
...
}
Was soll ich tun, wenn Felder nicht angegeben sind? Ich habe bisher Standardwerte in der Klasse verwendet, damit ein Feld niemals null ist, aber ist das eine “gute” Vorgehensweise?

Craig P. Motlin
Eine etwas vereinfachte Antwort:
public class Book
{
private final String title;
public Book(String title)
{
this.title = title;
}
public Book()
{
this("Default Title");
}
...
}

kggrad
Erwägen Sie die Verwendung des Builder-Musters. Es ermöglicht Ihnen, Standardwerte für Ihre Parameter festzulegen und auf klare und präzise Weise zu initialisieren. Zum Beispiel:
Book b = new Book.Builder("Catcher in the Rye").Isbn("12345")
.Weight("5 pounds").build();
Bearbeiten: Es beseitigt auch die Notwendigkeit mehrerer Konstruktoren mit unterschiedlichen Signaturen und ist viel besser lesbar.

Luca Touraille
Sie müssen angeben, was die Klasseninvarianten sind, dh Eigenschaften, die für eine Instanz der Klasse immer wahr sind (z. B. wird der Titel eines Buches niemals null sein oder die Größe eines Hundes wird immer > 0 sein).
Diese Invarianten sollten während der Konstruktion festgelegt und während der Lebensdauer des Objekts beibehalten werden, was bedeutet, dass Methoden die Invarianten nicht brechen dürfen. Die Konstruktoren können diese Invarianten entweder durch obligatorische Argumente oder durch Festlegen von Standardwerten festlegen:
class Book {
private String title; // not nullable
private String isbn; // nullable
// Here we provide a default value, but we could also skip the
// parameterless constructor entirely, to force users of the class to
// provide a title
public Book()
{
this("Untitled");
}
public Book(String title) throws IllegalArgumentException
{
if (title == null)
throw new IllegalArgumentException("Book title can't be null");
this.title = title;
// leave isbn without value
}
// Constructor with title and isbn
}
Die Wahl dieser Invarianten hängt jedoch stark von der Klasse ab, die Sie schreiben, wie Sie sie verwenden usw., sodass es keine endgültige Antwort auf Ihre Frage gibt.

Lawrence Dol
Sie sollten immer ein gültiges und legitimes Objekt konstruieren; und wenn Sie keine Konstruktorparameter verwenden können, sollten Sie ein Builder-Objekt verwenden, um eines zu erstellen, und das Objekt erst dann aus dem Builder freigeben, wenn das Objekt vollständig ist.
Zur Frage der Verwendung von Konstruktoren: Ich versuche immer, einen Basiskonstruktor zu haben, auf den sich alle anderen beziehen, der sich mit “weggelassenen” Parametern zum nächsten logischen Konstruktor durchkettet und am Basiskonstruktor endet. So:
class SomeClass
{
SomeClass() {
this("DefaultA");
}
SomeClass(String a) {
this(a,"DefaultB");
}
SomeClass(String a, String b) {
myA=a;
myB=b;
}
...
}
Wenn dies nicht möglich ist, versuche ich, eine private init() -Methode zu haben, auf die alle Konstruktoren zurückgreifen.
Und halten Sie die Anzahl der Konstruktoren und Parameter klein – maximal 5 von jedem als Richtlinie.
Es könnte sich lohnen, die Verwendung einer statischen Factory-Methode anstelle von Konstruktor in Betracht zu ziehen.
ich sage stattdessenaber offensichtlich kannst du das nicht ersetzen der Konstrukteur. Was Sie jedoch tun können, ist, den Konstruktor hinter einer statischen Factory-Methode zu verstecken. Auf diese Weise veröffentlichen wir die statische Factory-Methode als Teil der Klassen-API, verstecken aber gleichzeitig den Konstruktor und machen ihn privat oder paketieren privat.
Es ist eine relativ einfache Lösung, insbesondere im Vergleich zum Builder-Muster (wie in Joshua Blochs Effektive Java 2. Auflage – Vorsicht, Gang of Four’s Designmuster ein völlig anderes Entwurfsmuster mit demselben Namen definieren, was etwas verwirrend sein könnte), was das Erstellen einer verschachtelten Klasse, eines Builder-Objekts usw. impliziert.
Dieser Ansatz fügt eine zusätzliche Abstraktionsebene zwischen Ihnen und Ihrem Kunden hinzu, stärkt die Kapselung und erleichtert spätere Änderungen. Es gibt Ihnen auch Instanzkontrolle – da die Objekte innerhalb der Klasse instanziiert werden, entscheiden Sie und nicht der Client, wann und wie diese Objekte erstellt werden.
Schließlich erleichtert es das Testen – indem es einen dummen Konstruktor bereitstellt, der den Feldern nur die Werte zuweist, ohne Logik oder Validierung durchzuführen, ermöglicht es Ihnen, einen ungültigen Zustand in Ihr System einzuführen, um zu testen, wie es sich verhält und darauf reagiert. Das ist nicht möglich, wenn Sie Daten im Konstruktor validieren.
Viel mehr darüber können Sie im (bereits erwähnten) Joshua Bloch nachlesen Effektive Java 2. Auflage – es ist ein wichtiges Werkzeug in der Werkzeugkiste aller Entwickler und kein Wunder, dass es das Thema des 1. Kapitels des Buches ist. 😉
Nach deinem Beispiel:
public class Book {
private static final String DEFAULT_TITLE = "The Importance of Being Ernest";
private final String title;
private final String isbn;
private Book(String title, String isbn) {
this.title = title;
this.isbn = isbn;
}
public static Book createBook(String title, String isbn) {
return new Book(title, isbn);
}
public static Book createBookWithDefaultTitle(String isbn) {
return new Book(DEFAULT_TITLE, isbn);
}
...
}
Welchen Weg Sie auch wählen, es ist eine gute Praxis, einen zu haben hauptsächlich Konstruktor, der einfach blind alle Werte zuweist, auch wenn er nur von anderen Konstruktoren verwendet wird.

Scott Stanchfield
Einige allgemeine Tipps für Konstrukteure:
Der Gesamtfluss ergibt sich wie folgt:
- Bewegen Sie sich in der Oberklassenhierarchie ganz nach oben zu Objekt
- während nicht getan
- init-Felder
- Ausführen von Konstruktorkörpern
- auf die Unterklasse herunterfallen
Versuchen Sie als nettes Beispiel für das Böse herauszufinden, was das Folgende ausgeben wird, und führen Sie es dann aus
package com.javadude.sample;
/** THIS IS REALLY EVIL CODE! BEWARE!!! */
class A {
private int x = 10;
public A() {
init();
}
protected void init() {
x = 20;
}
public int getX() {
return x;
}
}
class B extends A {
private int y = 42;
protected void init() {
y = getX();
}
public int getY() {
return y;
}
}
public class Test {
public static void main(String[] args) {
B b = new B();
System.out.println("x=" + b.getX());
System.out.println("y=" + b.getY());
}
}
Ich werde Kommentare hinzufügen, die beschreiben, warum das obige so funktioniert, wie es funktioniert … Einiges davon mag offensichtlich sein; manches nicht…

Steve Kuo
Eine weitere Überlegung: Wenn ein Feld erforderlich ist oder einen begrenzten Bereich hat, führen Sie die Überprüfung im Konstruktor durch:
public Book(String title)
{
if (title==null)
throw new IllegalArgumentException("title can't be null");
this.title = title;
}
10141400cookie-checkBeste Möglichkeit, mehrere Konstruktoren in Java zu handhabenyes
Es hängt davon ab, ob alle Felder einen Wert enthalten müssen?
– CodeMonkey
24. Februar 2009 um 14:16 Uhr
Ich mag es nicht, wenn Leute Fragen stellen und dann keine Antworten akzeptieren.
– Anton Krug
19. November 2015 um 0:49 Uhr