Objektorientierung

Ljonja2107

Mitglied
Moin ich hätte mal eine Frage.
Ich habe eine Abstrakte Klasse, welche Fahrzeug heißt.
Ebenfalls habe ich eine Klasse PKW, welche natürlich unter den "Regeln" von Fahrzeug erstellt wird (Konstruktor, Methoden etc.)
Außerdem gibt es die Klasse Farbe, welche wie der Name schon sagt, den PKW später lackieren soll mit einer setFarbe Methode.
Nun möchte ich das ganze aber Objektorientiert gestalten und deswegen soll es in der Main Methode später nicht pkw.farbe.setFarbe("grün") heißen sondern pkw.setFarbe("grün") und irgendwie bekomme ich das nicht hin.

Java:
abstract class Fahrzeug {
    protected String marke;
    protected double preis;
    protected int kmStand;
    Farbe farbe;

    protected Motor motor = new Motor();
    protected Sitz sitz = new Sitz();
    protected Rad rad = new Rad();
    protected double gesamtGewicht;

    protected Fahrzeug(String marke, double preis, int kmStand, double gesamtGewicht) {

        this.marke = marke;
        this.preis = preis;
        this.kmStand = kmStand;
        this.gesamtGewicht = gesamtGewicht;

    } public void setFarbe(Farbe farbe) {
        this.farbe = farbe;
    }

Java:
package Fahrzeuge;
public class Farbe  {
    String farbe;
    String farbEffekt;

    public void setFarbe(String farbe) {
        this.farbe = farbe;
    }

    public void setFarbEffekt(String farbEffekt) {
        this.farbEffekt = farbEffekt;
    }

    public String getFarbe() {
        return this.farbe;
    }

    public String getFarbEffekt() {
        return this.farbEffekt;
    }

}

Ich stehe völlig auf dem Schlauch...
PS: offensichtlich habe ich die anderen getter und setter jetzt nicht großartig hinzgefügt.
 

Ljonja2107

Mitglied
also wenn ich
Java:
System.out.println(pkw.farbe.getFarbe());
aufrufe (so wie ich es eigentlich nicht wollte)
dann kommt null.
Wenn ich
Code:
System.out.println(pkw.getFarbe());
aufrufe, dann bekomme ich nur die Speicherreferenz.
 

KonradN

Super-Moderator
Mitarbeiter
Ich überlege gerade: Ist es evtl. so, dass es Verwirrungen gibt, weil die Bezeichner schlecht gewählt wurden?

Du hast "Farbe" hier doppelt verwendet: Zum einen hast Du eine Klasse Farbe, die dann wieder ein Attribut Farbe hast. Ja, was Farbe denn nun? Ist es ein Farbton? Ist es der Farbton mit einem Farbeffekt? Das würde ich sauber trennen - dann hätte die Farbe hat einen Farbton und einen (Farb-)Effekt. Das Auto hat eine Farbe. Oder wäre es eher die Lackierung? Und dann wird es deutlich:

Beim Auto kannst Du Dir die Lackierung geben lassen und da hast Du dann die Farbe und den Farbeffekt.
 

KonradN

Super-Moderator
Mitarbeiter
also wenn ich
Java:
System.out.println(pkw.farbe.getFarbe());
aufrufe (so wie ich es eigentlich nicht wollte)
dann kommt null.
Dann hast Du in der Frabe, die Du da gespeichert hast, schlicht keinen Wert hinterlegt. Hast Du die Instanz mit einem Konstruktor erzeugt und da einen Wert hinterlegt? Prüfe da einmal den Code!

Wenn ich
Code:
System.out.println(pkw.getFarbe());
aufrufe, dann bekomme ich nur die Speicherreferenz.
Du bekommst den Klassennamen@Hashcode. Das ist keine Speicherreferenz (Eine konkrete Implementation einer VM könnte da eine Speicherreferenz zurück geben, aber das muss nicht sein!)

Und das liegt einfach daran, dass dies die vorgegebeneImplementation von toString in Object ist. Wenn Du eine andere Darstellung haben willst, dann musst Du in Deiner Klasse toString überschreiben. Also hier konkret: Du musst toString in Frabe überschreiben.
 

Ljonja2107

Mitglied
Ich überlege gerade: Ist es evtl. so, dass es Verwirrungen gibt, weil die Bezeichner schlecht gewählt wurden?

Du hast "Farbe" hier doppelt verwendet: Zum einen hast Du eine Klasse Farbe, die dann wieder ein Attribut Farbe hast. Ja, was Farbe denn nun? Ist es ein Farbton? Ist es der Farbton mit einem Farbeffekt? Das würde ich sauber trennen - dann hätte die Farbe hat einen Farbton und einen (Farb-)Effekt. Das Auto hat eine Farbe. Oder wäre es eher die Lackierung? Und dann wird es deutlich:

Beim Auto kannst Du Dir die Lackierung geben lassen und da hast Du dann die Farbe und den Farbeffekt.
Der Tipp, das ganze nochmal anders zu "worden" hat mir echt geholfen.
 

mihe7

Top Contributor
Vielleicht noch etwas tiefergehend: der Lack stellt einen Wert dar. Zwei Lacke mit gleicher Farbe und gleichem Effekt sind als identisch anzusehen, eine Unterscheidung ist nicht erforderlich. Als Wert ist der Lack auch nicht nachträglich veränderbar. Wenn man die Farbe des Autos ändern möchte, trägt man neuen Lack auf.

Einen Lack kann man also als unveränderliches Objekt betrachten, das sich so implementieren lässt:
Java:
public class Lack {
    private final String farbe;
    private final String effekt;

    public Lack(String farbe, String effekt) {
        this.farbe = farbe;
        this.effekt = effekt;
    }

    public String farbe() { return farbe; }
    public String effekt() { return effekt; }

/* nur der Vollständigkeit halber, für das Problem nicht relevant:

    @Override
    public boolean equals(Object obj) {
        if (obj == null || obj == this || !(obj instanceof Lack)) {
            return obj == this;
        }
        Lack lack = (Lack) obj;
        return Objects.equals(farbe, lack.farbe) && Objects.equals(effekt, lack.effekt);
    }

    @Override
    public int hashCode() {
        return Objects.hash(farbe, effekt);
    }

*/

    @Override
    public String toString() {
         return "Lack[farbe=" + farbe + ", effekt=" + effekt + "]";
    }
}

Ab Java 16 reicht es,
Java:
public record Lack(String farbe, String effekt) {}
zu schreiben.

Das Fahrzeug kann nun über eine Lackierung verfügen, die sich durch Neulackierung ändern lässt:
Java:
public abstract class Fahrzeug {
    private Lack lackierung;

    // ...
    public Lack lackierung() { return lackierung; }
    public void lackiere(Lack lack) { lackierung = lack; }
    // ...
}

Dementsprechend kannst Du nun z. B. schreiben
Java:
// der Übersichtlichkeit halber, die Lacke in Variablen ablegen
Lack weiss = new Lack("weiss", "perleffekt");
Lack grauMetallic = new Lack("grau", "metallic");

// PKW mit weissem Lack bauen
Fahrzeug meinAuto = new PKW(weiss);
System.out.println("Lackierung meines Autos: " + meinAuto.lackierung());

// PKW umlackieren
meinAuto.lackiere(grauMetallic);
System.out.println("Lackierung meines Autos: " + meinAuto.lackierung());

Ausgabe:
Code:
Lackierung meines Autos: Lack[farbe=weiss, effekt=perleffekt]
Lackierung meines Autos: Lack[farbe=grau, effekt=metallic]
 
Zuletzt bearbeitet:

mihe7

Top Contributor
Du meinst wg. equals und hashCode? Ja, das kann man weglassen und ist nur der Vollständigkeit halber im Code. Der wesentliche Punkt ist, dass man hier den Lack des Autos ändert und nicht die Farbe des Lacks.
 

KonradN

Super-Moderator
Mitarbeiter
Und evtl. auch noch etwas von meinem Senf, den ich wie immer gerne dazu gebe:
Es gibt einige Dinge, die meinen als Anfänger ggf. nicht direkt interessieren oder an die man als Anfänger, wenn man selbst Code schreibt, denkt.
Aber ich bin davon überzeugt, dass es Sinn macht, dennoch immer wieder den Hinweis zu geben! Es zeigt dann Ideen auf, die man ggf. erst einmal übernimmt ohne den Anspruch, diese Idee dann in Zukunft selbst anwenden zu können oder zu erkennen, wann dies angewendet werden sollte.

Das, was @mihe7 erwähnt hat, war teilweise auch etwas, bei dem ich auch schon überlegt hatte, dies mit einzubauen.

der Lack stellt einen Wert dar
Es ist sinnvoll, hier die Gedanken zu verstehen. Es gibt Elemente, die sind "Werte". Die kann man also nicht verändern.

Eine 3 ist und bleibt eine 3. Du kannst die 3 nicht verändern. Aber natürlich kannst Du den Wert 3, der in einer Variable gespeichert wird, ersetzen. Also wenn in myVar eine 3 gespeichert ist, dann kann man sagen: myVar = 5. Dann wird die 3 durch die 5 ersetzt.

Daraus ermöglichst dann Dinge, die später sehr hilfreich und nützlich sein können. Ich will da nicht zu tief drauf eingehen, aber evtl. hast Du ein paar Standardfarben, zwischen denen ein User wählen kann. Also sowas wie: "rot"/"metallic", "grau"/"metallic", "schwarz"/"metallic". Diese Standardfarben hast Du in Form einer Enumeration und da bekommst Du dann auch die Instanz von "Lackierung" oder wie die Klasse heisst.
Nun kannst Du diese Lackierungen in mehreren Fahrzeugen setzen. Das bedeutet, dass eine Instanz Lackierung "rot"/"metallic" in vielen Fahrzeugen verwendet wird. Wenn Du nun bei dieser einen Instanz die Farbe ändern könntest, dann wären alle Fahrzeug-Instanzen, die diese Instanz von Lackierung hatten, betroffen. Solche Probleme (oder Nebeneffekte) kann man komplett vermeiden. Das aber wirklich nur als kleines anschauliches Beispiel. Das geht noch deutlich tiefer, z.B. bei der Verwendung als Key in einer HashMap oder bei der Nutzung in Streams.
 

Samka

Mitglied
Code:
abstract class Fahrzeug {

    protected String marke;
    protected double preis;
    protected int kmStand;
    Farbe farbe = new Farbe();

    protected Motor motor = new Motor();
    protected Sitz sitz = new Sitz();
    protected Rad rad = new Rad();
    protected double gesamtGewicht;

    protected Fahrzeug(String marke, double preis, int kmStand, double gesamtGewicht) {

        this.marke = marke;
        this.preis = preis;
        this.kmStand = kmStand;
        this.gesamtGewicht = gesamtGewicht;
        //default values
        farbe.setFarbe("schwarz");
        farbe.setFarbEffekt("metallic");

    }
  
    public void setFarbe(Farbe farbe) {

        this.farbe.setFarbe(farbe.farbe);
        this.farbe.setFarbEffekt(farbe.farbEffekt);

    }

    public String getFarbe() {

        return (this.farbe.getFarbe() + " " + this.farbe.getFarbEffekt());
    }
Code:
package Fahrzeuge;
public class Farbe  {
    String farbe = "";
    String farbEffekt = "";

    public void setFarbe(String farbe) {
        this.farbe = farbe;
    }

    public void setFarbEffekt(String farbEffekt) {
        this.farbEffekt = farbEffekt;
    }

    public String getFarbe() {
        return this.farbe;
    }

    public String getFarbEffekt() {
        return this.farbEffekt;
    }

}

in der Main.java müsstest du jetzt wenn du eine neue Farbe erstellen willst er Farbe farbe = new Farbe(); und dann mit deinen setter also setFarbe() und setFarbEffekt() deine Werte setzen.
natürlich nicht elegant, aber falls es dich interessiert, wie man es mit hilfe von setter macht :)
 
Zuletzt bearbeitet:

KonradN

Super-Moderator
Mitarbeiter
Die Implementierung ist äußerst ungewöhnlich:
Java:
public void setFarbe(Farbe farbe) {

        this.farbe.setFarbe(farbe.farbe);
        this.farbe.setFarbEffekt(farbe.farbEffekt);

    }

    public String getFarbe() {

        return (this.farbe.getFarbe() + " " + this.farbe.getFarbEffekt());
    }

Beim Setter sollte man wirklich die Instanz setzen. Du hast hier Probleme, wenn die Klasse sich ändert. Es kommt ein Attribut hinzu und schon musst du den Setter hier auch anpassen.

Und der Getter sollte immer die Farbe zurückgeben und keine String Representation. Zumal so etwas auf keinen Fall in Fahrzeug gehört sondern wenn dann in die Klasse Farbe oder eine Klasse, die für die Darstellung von Farbe zuständig ist.
 

Samka

Mitglied
Die Implementierung ist äußerst ungewöhnlich:
Java:
public void setFarbe(Farbe farbe) {

        this.farbe.setFarbe(farbe.farbe);
        this.farbe.setFarbEffekt(farbe.farbEffekt);

    }

    public String getFarbe() {

        return (this.farbe.getFarbe() + " " + this.farbe.getFarbEffekt());
    }

Beim Setter sollte man wirklich die Instanz setzen. Du hast hier Probleme, wenn die Klasse sich ändert. Es kommt ein Attribut hinzu und schon musst du den Setter hier auch anpassen.

Und der Getter sollte immer die Farbe zurückgeben und keine String Representation. Zumal so etwas auf keinen Fall in Fahrzeug gehört sondern wenn dann in die Klasse Farbe oder eine Klasse, die für die Darstellung von Farbe zuständig ist.
Stimm ich dir au jeden Fall zu. Es war nur eine schnelle Implementierung wie man mit ihrem Code ihr Ziel erreichen hätte können. Ich persönlich bin nicht mal ein Fan von abstract classes (benutzte meist Interfaces, falls ich Mehrfachverebung brauche)
 

Ähnliche Java Themen

Neue Themen


Oben