Fragen über setter- Methoden und List

Guten Abend euch Allen,

**

  1. abstrakte Klasse Artikel
    Diese Klasse soll als abstrakte Klasse deklariert werden. Die Klasse soll private Instanzvariablen zum Speichern der Marke, des Namens, der Version, des Startpreises (in Euro) und aller Gebote (in Euro) sowie entsprechende Zugriffsmethoden besitzen. Eine Methode getHoechstesGebot() soll das höchste Gebot auf einen Artikel zurückliefern.*
    Zusätzlich soll es eine konkrete Methode getPreis() geben, die den Preis den ein Bieter auf einen Artikel zahlen muss, berechnet. Der Preis eines Artikels wird an Hand des höchsten Gebots minus einem Rabatt wie folgt berechnet: Für Software erhält man einen Rabatt, der von der Anzahl der abgegebenen Gebote abhängt (pro Gebot einen Rabatt von 1%, höchstens 10%), während man für einen Computer einen Rabatt abhängig von der Austattung bekommt (10% Grundrabatt minus 1% pro angegebenen Ausstattungspaket - abhängig vom höchsten Gebot). Zu diesem Zweck soll eine abstrakte Methode getRabatt() zur abstrakten Klasse Artikel hinzugefügt und innerhalb von getPreis() verwendet werden.*

  2. Klassen Software und Computer
    Es sollen zwei konkrete (nicht-abstrakte) Unterklassen Software und Computer von der abstrakten Klasse Artikel abgeleitet werden. Die Unterklasse Computer hat zusätzliche Instanzvariablen für Prozessor, Arbeitsspeicher, und Austattung sowie entsprechende Zugriffsmethoden. Die Ausstattung soll in einem String-Array gespeichert werden. Die Unterklasse Software hat eine zusätzliche Instanzvariable für die Sparte sowie eine entsprechende Zugriffsmethode. Beide Klassen sollen die Methode getRabatt() implementieren. Implementieren Sie zusätzlich die Methode toString() in geeigneter Art und Weise (Ausgabe aller Attribute)

**

Ich muss nicht 100% auf diese Aufgabestelung halten. Ich möchte möglichst sinnvoll programmieren und an die Ratschläge halten was ich vorher in Forum bekommen habe

@Klasse Artikel.java - Ich habe setter Methoden desswegen nicht implementiert, weil man mir hier gesagt hat, dass ich nur dann implementieren soll, wenn die Instanze veränderbar sind, ausser bids. Sollte setter Methode von bids machen ?

public abstract class Artikel {

	private String marke;
	private String name;
	private String version;
	private double startpreis;
	private List<Double> bids;

	public Artikel(String marke, String name, String version,
			double startpreis, List<Double> bids) {
		this.marke = marke;
		this.name = name;
		this.version = version;
		this.startpreis = startpreis;
		this.bids = bids;
		
	}

	String getMarke() {
		return marke;
	}

	String getName() {
		return name;
	}

	String getVersion() {
		return version;
	}

	double getStartpreis() {
		return startpreis;
	}

	

	List<Double> getBids() {
		return bids;
	}

	public double hoechsteBid() {
		double bid = 0;
		Iterator<Double> bidIter = bids.iterator();
		while (bidIter.hasNext()) {
			if (bid < bidIter.next()) {
				bid = bidIter.next();
			}
		}

		return bid;
	}

	public void setzeBid(double bid){
		this.bids.add(bid);
	}
	
	public abstract double rabat();

	public double getPreis() {
		return hoechsteBid() - rabat();
	}
}

@Software.java - braucht man für Sparte setter methode. Wie ich verstanden habe Sparte ist eine Beschreibung und Beschreibung ändert man auch nicht oder?

public class Software extends Artikel {
	private String sparte;

	public Software(String marke, String name, String version,
			double startpreis, List<Double> bids, String sparte) {
		super(marke, name, version, startpreis, bids);
		this.sparte = sparte;

	}

	String getSparte() {
		return sparte;
	}

	public double rabat() {

		double rabat = 0;
		if (getBids().size() < 10) {

			rabat = getStartpreis() * getBids().size() * 0.01;

		} else {
			rabat = getStartpreis() * getBids().size() * 0.1;
		}
		return rabat;
	}

	@Override
	public String toString() {
		StringBuilder bidsBuilder = new StringBuilder();

		Iterator<Double> iter = getBids().iterator();
		while (iter.hasNext()) {
			bidsBuilder.append(iter.next()).append(", ");
		}
		return "Name - " + getName() + "
" + "Marke - " + getMarke() + "
"
				+ "Version - " + getVersion() + "
" + "Sparte - "
				+ getSparte() + "
" + bidsBuilder.toString() + "
"
				+ "Preis - " + getPreis();
	}
}

@Computer- es macht schon sinn setter Methoden von Prozessor und Arbeitspeicher zu machen oder?
Sollte ich setter für aussstatung machen oder public void ausstattunHinzufuegen(String ausstatung) methode wäre sinnvoller?

public class Computer extends Artikel {

	private String prozessor;
	private int arbeitsspeicher;
	private List<String> ausstattung;

	public Computer(String marke, String name, String version,
			double startpreis, List<Double> bids, String prozessor,
			int arbeitsspeicher, List<String> ausstattung) {

		super(marke, name, version, startpreis, bids);

		setProzessor(prozessor);
		setArbeitsspeicher(arbeitsspeicher);
		this.ausstattung = ausstattung;

	}

	String getProzessor() {
		return prozessor;
	}

	void setProzessor(String prozessor) {
		this.prozessor = prozessor;
	}

	int getArbeitsspeicher() {
		return arbeitsspeicher;
	}

	void setArbeitsspeicher(int arbeitsspeicher) {
		this.arbeitsspeicher = arbeitsspeicher;
	}

	List<String> getAusstattung() {
		return ausstattung;
	}

	public void ausstattunHinzufuegen(String ausstatung) {
		this.ausstattung.add(ausstatung);
	}

	public double rabat() {

		return hoechsteBid() * 0.1 - ausstattung.size() * 0.01;
	}

	@Override
	public String toString() {
		StringBuilder ausstatungBuilder = new StringBuilder();
		Iterator<String> austatungIter = ausstattung.iterator();
		while (austatungIter.hasNext()) {
			ausstatungBuilder.append(austatungIter.next()).append(", ");
		}

		StringBuilder bidsBuilder = new StringBuilder();
		Iterator<Double> bidsIter = getBids().iterator();
		while (bidsIter.hasNext()) {
			bidsBuilder.append(bidsIter.next()).append(", ");
		}

		return "Marke - " + getMarke() + "
" + "Name - " + getName() + "
"
				+ "Version - " + getVersion() + "
" + "Prozessor - "
				+ getProzessor() + "
" + "Arbeitspeicher - "
				+ getArbeitsspeicher() + "
" + "Ausstatung - "
				+ ausstatungBuilder.toString() + "
" + "Bids - "
				+ bidsBuilder.toString() + "
" + "Preis - " + getPreis();
	}
}

Allerletzte Frage : Ihr habt mir empfohlen statt ArrayList List zu nehmen. Ich wollte nur schauen wie genau StringBuilder Arbeitet und eine Test.java Klasse geschrieben und ich konnte nicht Instanz von List ausstattung erzeugen. Ich meine das mit new

Lg Anni

List ist ein Interface, lies hierzu auch den Artikel unter Openbooks. Rheinwerk-Bücher kostenlos online lesen. Ein Service des Rheinwerk Verlags oder generell zu Schnittstellen.

Ich weiß zwar nicht wer oder wo gesagt wurde dass du List statt ArrayList verwenden sollst, aber vermutlich war das anders gemeint als du aufgenommen hast:

List<…> … = new ArrayList…
anstelle
ArrayList<…> … = new ArrayList…

bzw in Methoden immer das Interface angeben und keine Klasse der Implementierung dieser. Gründe wieso man so verfahren sollte gibt es einige (ich würde ja jetzt zum anderen Forum verlinken wenn es gehen würde :P). Einer der Gründe ist, falls du dich später doch für eine andere Implementierung entscheidest (z.B. LinkedList anstelle ArrayList), musst du kaum Code anfassen, denn in den meisten Fällen reicht es aus zu wissen dass es sich um eine Liste handelt.

ja vielleicht haben die das gemeint

perfekte Erklärung. Danke

Ja, haben wir.:wink:

:slight_smile:

Heute hat man mir empfohlen, dass man Setter implementieren soll, wenn wenn der Instanz ersetzbar ist. Habe ich das richtig verstanden und habe in meine Klassen richtig gemacht?
Bis jetzt habe ich getter und setter geliebt, da man nicht nachdenken musste :wink:

Heute hat man mir empfohlen, dass man Setter implementieren soll, wenn wenn der Instanz ersetzbar ist.

Sagt mir überhaupt nichts. Wo kommt die Empfehlung her? Evtl. mal Link posten, damit man das nachvollziehen kann. Ob man Setter braucht oder nicht, dafür gibt es keine allgemeingültige Regel. Nur die Empfehlung, es sich gut zu überlegen, ob man für ein Feld einen Setter anbietet. Wenn ein Feld von außen Veränderbar sein soll, dann Setter, sonst nicht. Ob ein Feld veränderbar sein soll, hängt von fachlichen Anforderungen ab.

Mal ein etwas konstruiertes Beispiel: Bei einer Klasse Person würde ich ein Geburtsdatum vielleicht eher nicht veränderbar machen wollen, da es sich während der gesamten Lebenszeit einer Person nicht ändert. Der Nachname kann (bspw. durch Heirat) geändert werden und sollte deswegen auch veränderbar sein. Das heißt jetzt aber nicht, dass ein Geburtsdatum nie und nimmer veränderbar sein darf. Es kommt auch noch darauf an, wo so eine Klasse Verwendung finden soll. Wenn sie z.B. dazu dient, die Eingaben aus einer Gui zu speichern, würde man einen Setter spendieren, der den in der GUI eingegebenen Wert setzt.

Die Formulierung „wenn wenn der Instanz ersetzbar ist“ (!?) mal ignorierend:

Man sollte eigentlich IMMER Nachdenken, wenn man code schreibt :smiley: Und man sollte sich sehr wohl überlegen, ob man setter einfügt. Oft ist es so, dass bestimmte Dinge gar nicht geändert werden können oder sollen. Sowas wie

class Person 
{
    private String birthDate;

    public Person(String birthDate) 
    {
        this.birthDate = birthDate
    }

    public String getBirthDate() { return birthDate; }

    public void setBirthDate(String d) { birthDate = d; }
}

macht ja keinen Sinn: Das Geburtsdatum einer Person kann nach dem Konstruktoraufruf (d.h. nach ihrer Geburt :smiley: ) ja nicht mehr geändert werden. Das kann uns sollte man entsprechend deutlich machen, indem man den setter eben NICHT anbietet.

Sowohl bei gettern als auch bei settern sollte man sich außerdem immer überlegen, ob man sie public, protected, private, public final oder protected final macht, aber das nur nebenbei.

Es gibt noch weitere, eher technischen Gründe, warum man über setter nachdenken sollte: SEHR viele Fehler in Programmen entstehen durch einen falschen Zustand. Irgendwo ist eine Variable ‚null‘ oder hat einen falschen Wert, weil ein setter nicht oder falsch aufgerufen wird. Jede Variable, die verändert werden kann, vergrößert den Zustandsraum um eine Dimension (!). Spätestens bei Multithreading wird klar, was das für Probleme machen kann.

Die allgemeine Empfehlung, die manchmal gegeben wird, ist: Minimize mutability. D.h. mache an der Klasse so wenig veränderbar, wie möglich. Was man nicht ändern können MUSS, sollte man auch nicht ändern können KÖNNEN. (Wird auch in letzter Konsequenz manchmal als „Immutable Pattern“ o.ä. bezeichnet)

(Das zuuu religiös zu befolgen kann aber auch krampfig werden. Manchmal ist ein setter schon OK :D)

P.S: Wenn du dich fragst, warum ich das „BirthDate“ als „String“ und nicht als „Date“ anskizziert habe: Ja, das hängt genau damit zusammen :wink:

EDIT: Person, Geburtsdatum… gibt’s zu nillehammer, du hast bei mir einen Keylogger installiert. Oder ich bei dir :smiley:

@Marko13: Ich nehm da immer einen long für die millis.

…Wird echt Zeit, dass hier mehr Fragen kommen, damit wir uns nicht immer gegenseitig bekappeln ::crazy

[QUOTE=nillehammer]
Mal ein etwas konstruiertes Beispiel: Bei einer Klasse Person würde ich ein Geburtsdatum vielleicht eher nicht veränderbar machen wollen, da es sich während der gesamten Lebenszeit einer Person nicht ändert. Der Nachname kann (bspw. durch Heirat) geändert werden und sollte deswegen auch veränderbar sein. Das heißt jetzt aber nicht, dass ein Geburtsdatum nie und nimmer veränderbar sein darf. [/QUOTE]

genauso wurde mir heute in Forum gesagt und diese Überlegungen habe ich auch gemacht

Ich hoffe, dass ich nicht nerve mit meine viele Fragen

Ich hoffe, dass ich nicht nerve mit meine viele Fragen

Ganz und garnicht. Das merkst Du daran, dass Du hier von zwei Leuten gleichzeitig betreut wirst. Von so einem Betreuer-Betreuten-Verhältnis können Kitas nur träumen :o

Nochmal zu den Settern:
Setter die direkt auf die Variable zugreifen sollte man Grundsätzlich vermeiden.
Codebeispiel Am Schlechtesten:

public class Auto {
	public int weight;
	public String colour;
	public String name;
	public Auto(int w, String c, String n) {
		weight = w;
		colour = c;
		name = n;
	}
}

Juhu, man kann die Variablen von Außen unbegrenzt verändern.
Codebeispiel Schlecht:

public class Auto {
	private int weight;
	private String colour;
	private String name;

	public Auto(int w, String c, String n) {
		weight = w;
		colour = c;
		name = n;
	}
	public void setWeight(int w) {
		weight = w;
	}
	public void setColour(String c) {
		colour = c;
	}
	public void setName(String n) {
		name = n;
	}
}

Direkte Setter, nicht schön.
Codebeispiel Gut:
Auto.java

	private int weight;
	private Colour colour;
	private String name;
	private final int MIN_WEIGHT = 200;
	private final int MAX_WEIGHT = 2000;
	private final int MIN_NAME_LENGTH = 5;
	private final int MAX_NAME_LENGTH = 50;
	/**
	 * 
	 * @param w Gewicht des Autos
	 * @param c Farbe des Autos
	 * @param n Name des Autos
	 */
	public Auto(int w, Colour c, String n) {
		weight = w;
		colour = c;
		name = n;
	}
	public void setWeight(int w) {
		if (w < MIN_WEIGHT) {
			throw new IllegalArgumentException("Argument is less than min Weight(Min weight:" + MIN_WEIGHT + ")");
		}
		if (w > MIN_WEIGHT) {
			throw new IllegalArgumentException("Argument is greater than max Weight(Max weight:" + MAX_WEIGHT + ")");
		}
		weight = w;
	}
	public void setColour(Colour c) {
		//Keine Validierung nötig, da nur festgelegte Werte möglich
		colour = c;
	}
	public void setName(String n) {
		if (n == null) {
			throw new IllegalArgumentException("Argument can't be null!");
		}
		if (n.length() < MIN_NAME_LENGTH) {
			throw new IllegalArgumentException("Argument is not long enough! (Min length: " + MIN_NAME_LENGTH + ")");
		}
		if (n.length() > MAX_NAME_LENGTH) {
			throw new IllegalArgumentException("Argument is too long! (Max length: " + MAX_NAME_LENGTH + ")");
		}
		name = n;
	}
	public int getWeight() {
		return weight;
	}
	public Colour getColour() {
		return colour;
	}
	public String getName() {
		return name;
	}
}

Colour.java


public enum Colour {
	BLUE, RED, GREEN, YELLOW, BLACK, WHITE
}

Liebe Grüße
@java4ever

Danke euch allen. Durch den Tipps hier wird der Weg zum programmieren erträglicher
Dank eure tipps, sollte ich Klasse Student sinnvoller programmiert haben.

public class Student {

	private String vorname;
	private String nachname;
	private String matrikelnummer;

	public Student(String vorname, String nachname, String matrikelnummer)
			throws Exception {
		// da kommt die überprüfung von matrikelnummer
		setVorname(vorname);
		setNachname(nachname);
		this.matrikelnummer = matrikelnummer.trim();
	}

	public String getMatrikelnummer() {

		String ziffern = this.matrikelnummer.substring(1);
		return ziffern;

	}

	public String getVorname() {
		return vorname;
	}

	public void setVorname(String vorname) throws Exception {
		
		//überprüfung von Vorname
		this.vorname = vorname.trim();
	}

	public String getNachname() {
		return nachname;
	}

	public void setNachname(String nachname) throws Exception {
		//überprüfung von Nachname
		this.nachname = nachname.trim();
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Student) {
			Student stud = (Student) obj;
			if (getMatrikelnummer().equals(stud.getMatrikelnummer()))

				return true;
		}

		return false;
	}

}

Der Code ist aus mehreren Gründen nicht gut (um nicht zu sagen schlecht):
public void setVorname(String vorname) throws Exception {
Deklaration einer völlig unspezifischen Exception und die auch noch checked. Try-Catch, nur um einen Wert zu setzen ist sehr umständlich. Und tatsächlich werfen tust Du sie nicht mal… Wenn überhaupt, dann siehe java4ever’s Vorschlag mit den unchecked IllegalArgumentExceptions.

this.vorname = vorname.trim();
Aufruf von trim, erstmal eine gute Idee, aber ohne Nullprüfung sehr anfällig für NullPointerExceptions (es sei denn, das ist gewünscht).

ich habe throw new Exception("FEHLERMELDUNG"); geworfen.
Dabei habe ich mich gefreut dass ich endlich was richtig verstanden und gemacht habe

		if (vorname == null || vorname.length() == 0) {
			throw new Exception("Der name darfnicht null sein");
		}
		if (!Character.isUpperCase(vorname.charAt(0))) {
			throw new Exception(
					"Der Vorname darf nur aus großbuchstaben beginnen ");
		}

		for (int i = 1; i < vorname.length(); i++) {
			char c = vorname.charAt(i);

			if (!Character.isLetter(c) && !Character.isWhitespace(c)) {
				throw new Exception(
						"Der name darf nur aus Buchstaben und Leerzeichen bestehen");
			}
		}
		this.vorname = vorname.trim();
	}

lg Anni

Man sollte mit der Exception zumindest spezifischer werden. In diesem Fall ggf. sowas wie

/**
 * Sets the name, which must start with an uppercase letter and ... etc.
 * 
 * @param vorname The name to set
 * @throws IllegalArgumentException if the name does not comply to the rules 
 */
public void setVorname(String vorname) {


....    throw new IllegalArgumentException ("Da passt was nicht")

Lies ggf. mal über Checked und Unchecked Exceptions.

um nochmal Marcos Bsp mit dem Geburtstag zu nehmen und den Sinn von Settern.

Man kann von einem Student den Vor und Nachnamen aendern ? Nachname vll wenn er/sie heiratet, aber der Vorname ? Warum sollte man den je aendern koennen/duerfen ?!

In meinen Augen ist das alles nur eine Sache des Anwendungsfalles und nicht einer realitätsgetreuen Nachstellung. Stelle ich z.B. eine API zur Verfügung, die Daten liefert und nicht verändert werden sollen, dann sind diese natürlich immutable. Verfolge ich generell das Prinzip vom immutable Objekten, dann natürlich sowieso immutable. Verwende ich die Objekte lediglich als Datencontainer im Sinne einer Bean, dann gehören da natürlich für jedes Field Getter und Setter hin, vollkommen egal, ob man in echt den Vornamen ändern würde oder nicht (was übrigens auch möglich ist und den Nachnamen kann man auch ohne Heirat ändern). Die Frage ist weniger, ob es Sinn macht die Daten zu verändern, sondern wie diese Objekte verwendet und gebraucht werden. Tippe ich alles von Hand, kann ich die unveränderlichen Daten natürlich auch mittels Konstruktor bei der Erzeugung setzen und lasse die Setter weg. Wer eine moderne IDE verwendet, der wird die Getter und Setter sowieso nicht selber schreiben, sondern generieren lassen und da ist meist der schnellste Weg gewählt, nämlich für alle Felder generieren. Verfolge ich einen eher automatisierten Weg, wie auch immer diese aussehen mag, wird das schon schwierig ohne entsprechende Setter. Man kann sich natürlich eigene Annotations schreiben, die die Parameter des Konstruktors und die Felder entsprechend markieren, aber dann bräuchte ich auch eigene AnnotationProcessor und noch einiges mehr. Viel zu umständlich, für Anfänger sowieso.

Meiner Erfahrung nach kommen in der Regel nur zwei Fälle vor:
Beans -> sind mit Settern und Gettern ausgestattet
Immutable Objekte -> keine Setter verfügbar und jegliche veränderliche Methode gibt ein neues Objekt zurück (wie z.B. String)

Irgendein Gemurkse mit irgendwelchen halben Sachen kenne ich nicht. Natürlich macht es irgendwo Sinn drüber nachzudenken, aber wie das so oft der Fall ist, ist das einfach nur Zeitverschwendung. Der zentrale Kern einer Anwendung ist die Businesslogik und die korrenzte Funktionsweise. Darüber nachzudenken, ob ein Feld unter vielleicht hunderten einen Setter bekommen soll oder nicht ist völlige Zeitverschwendung, da sind andere Dinge viel wichtiger für die man meist ohnehin zu wenig Zeit hat.

Nochmal zu den Exceptions:
Du könntest das ganze natürlich auch zu einem Methode machen, die einen INT als return Wert zurückgibt
(Erfolg, Fehler usw.)

Grüße

[QUOTE=java4ever]Nochmal zu den Exceptions:
Du könntest das ganze natürlich auch zu einem Methode machen, die einen INT als return Wert zurückgibt
(Erfolg, Fehler usw.)

Grüße[/QUOTE]

Empfehle ich eher nicht. Das ist eine Vorgehensweise aus Sprachen wie C, in denen es kein Exception-Handling gibt. Genau für sowas gibt es Exceptions und das nicht ohne Grund. Mit Fehler-Codes hat man nur unnötigen Overhead, zum Teil schwer lesbaren Code und muss die Rückgabe der Methode nur unnötig auf Erfolg prüfen und das jedes Mal. Sollte man vermeiden! Entweder wird eine Exception geworfen oder eben nicht und sollte doch eine Exception geworfen werden, so weiß man wesentlich schneller, was eigentlich Sache ist als ein vielleicht nicht einmal interpretierter Fehler-Code.

Dann sollte man aber die Exception auch fangen, und nicht vergessen :stuck_out_tongue_winking_eye: