Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
manchmal benötige eine Variable, um anzuzeigen, ob etwas gesetzt wurde. Z.B., ob etwas ausgewählt wurde.
Dann muss ich, wenn ich die Auswahl aufheben möchte, natürlich auch diesen Wert löschen.
Also kommt so etwas hier heraus:
Java:
public void setIsSomethingSet(boolean bool) {
somethingToSet = bool;
}
Jetzt empfinde ich diese Konstruktion als komisch und das ist eigentlich oft ein Zeichen dafür, dass es falsch ist bzw. cleverer gelöst werden kann.
Kann mir jemand verraten, wie man solche Situationen am besten löst?
grundsätzlich besteht natürlich auch die Möglichkeit, in der Variablen selbst das Nicht-Gesetzt-Seit auszudrücken,
durch null-Wert oder eine bestimmte Konstante,
für primitive Datentypen sicherlich schwieriger, da gibts noch 0 oder -1, bei boolean wirds haarig 😉
Bei Booleans bietet es sich an, statt der setter-Syntax einfac zwei Methoden enable und disable zu bauen. Etwa so:
Java:
public class MyClas {
private boolean myBoolean;
/* Setter und Getter nach Bean-Konvention */
public void setMyBoolean(final boolean theBoolean) {
this.myBoolean = theBoolean;
}
public boolean getMyBoolean() {
return this.myBoolean;
}
/* Bei booleans darf der "getter" auch mit "is" beginnen, also: */
public boolean isMyBoolean() {
return this.myBoolean;
}
/* Und nun die Schalter-Methoden */
public void enableMyBoolean() {
this.myBoolean = true;
}
public void disableMyBoolean() {
this.myBoolean = false;
}
public void flipMyBoolean() {
this.myBoolean = !this.myBoolean;
}
}
public class MyClas {
private boolean myBoolean;
public boolean isMyBoolean() {
return this.myBoolean;
}
public void setMyBoolean(final boolean theBoolean) {
this.myBoolean = theBoolean;
}
mehr brauchts nicht.
selbst bei flipMyBoolean bin ich nicht so ueberzeugt, da der aufrufer keine ahnung hat in welchen Zustand sich myBoolean befindet und es gewiss zu code ala
[Java]
if (myClass.isMyBoolean()) {
myClass.flipMyBoolean();
}
[/code]
kommt (bzw mit der negation).
Ja, wenns zu so nem Code kommt, dann ist nen normaler setter sicherlich die bessere Wahl 😉
Es kommt halt wie gesagt drauf an in welchem Kontext man den boolean nutzt. Du hast aber recht, in der Regel tuts nen gewöhnlicher setter.
propra hat nach möglichen Alternativen zu der normalen Setter-Syntax gefragt. Die hab ich genannt. Was er davon benutzt (sicher nicht alles), kann er sich dann selbst aussuchen. Und flips hab ich im Zusammenhang mit GUI-Elementen, die man auf- und zuklappen kann schon selbst oft benutzt. Da ist es mir nämlich egal, wie der aktuelle Zustand ist, ich will einfach, dass er sich ändert.
Und flips hab ich im Zusammenhang mit GUI-Elementen, die man auf- und zuklappen kann schon selbst oft benutzt. Da ist es mir nämlich egal, wie der aktuelle Zustand ist, ich will einfach, dass er sich ändert.
Habe mir gerade das Gehirn zermartert, ob ich das irgendwoanders schonmal benutzt habe. Mir fällt außer GUI nichts ein. Aber ganz ausschließen möchte ich es nicht, dass es auch woanders sinnvoll sein kann.
Das ist nich cool. Mit solchen Methoden kann man sich schnell eklige Logik-Bugs einfangen. Ein Setter (bzw allgemeine jede Methode) sollte keine unerwarteten Seiteneffekte haben. Wenn ich setGroesse() aufrufe dann will ich dass sich die Größe ändert - nicht mehr, nicht weniger. Außerdem ist das redundant, wenn du zwei Variablen hast die eigentlich das selbe ausdrücken.
grundsätzlich besteht natürlich auch die Möglichkeit, in der Variablen selbst das Nicht-Gesetzt-Seit auszudrücken,
durch null-Wert oder eine bestimmte Konstante,
für primitive Datentypen sicherlich schwieriger, da gibts noch 0 oder -1, bei boolean wirds haarig
Oha, da habe ich ja was losgetreten...
Vielen Dank erst einmal.
Vielleicht machen wir es einfach etwas konkreter.
Ich habe ein Programm geschrieben, in dem es möglich ist Knoten zu zeichnen, die durch Kanten verbunden werden können.
Im konkreten Fall geht es nun darum, genau so eine Kante zu zeichnen. Die Methode
Code:
createEdge(Point p)
bekommt nur die Koordinaten eines Mausklicks übergeben. Mit Hilfe dieser wird dann aus einer Liste von ausgewählten Knoten der entsprechende Knoten ausgewählt.
Da die Methode sowohl für die Wahl des Start-, als auch Endknoten benutzt wird, habe ich die anfangs geschilderte Situation.
Die Lösung mit
Code:
flipMyBoolean()
finde ich sehr elegant, verständlicher wird aber sicherlich
Dann sollte das vielleicht nicht so sein. Ich denk du hast da ein kleines Design-Problem, und hast bestimmte Verantwortungen im Code an der falschen Stelle. Es lässt sich sicherlich auch ganz ohne diesen boolean lösen.
Dann sollte das vielleicht nicht so sein. Ich denk du hast da ein kleines Design-Problem, und hast bestimmte Verantwortungen im Code an der falschen Stelle. Es lässt sich sicherlich auch ganz ohne diesen boolean lösen.
Hm..
Bisher dachte ich eigentlich, dass es immer eine gute Idee ist, seine Methoden "so flexibel" und wiederverwendbar, wie möglich zu machen. Deshalb habe ich eine Methode geschrieben, die ich für Startknoten- und Endknotenwahl nehmen kann.
Ist es denn besser eine Methode
Code:
selectStartNode()
und eine
Code:
selectEndNode()
, ob wohl in beiden im Prinzip derselbe Code steht? Für mich wäre das dann redundanter Code, den es zu vermeiden gilt. ???:L
Ja wie, selber Code? Ist Start- und Endknoten nun das selbe für deine Logik oder nicht? Wenn nicht dann kann es ja nicht der selbe Code sein. Du hast irgendwo ein if() drin, oder? Zeig doch mal die Methode, bzw alles was man kennen muss um zu verstehen was die Logik dahinter ist.
Stichwort Strategy Pattern. Ohne deinen Code kann ich jetzt nicht sagen ob das Overkill ist oder nicht. Aber grundsätzlich sollte man if()-Statements mit Vorsicht genießen. Primitive Prüfungen sind nicht vermeidbar und auch total okay (zB bei mathematischen Vergleichen) aber wenn die Logik abhängt von einem Objekt-Zustand oder gar der Kombination mehrerer solcher, dann ist es oft sinnvoller sowas wie eben das Strategy Pattern anzuwenden. Wenn du mir deinen Code zeigst kann ich dir konkreteres sagen, ich hab das jetzt nur mal gepostet weil ich nicht weiß ob von deiner Seite aus noch was kommt
Was heißt hier unerwartet? Man könte natürlich auch ein Changelistener (was in dem vorliegenden Fall KEINES WEGS übertrieben ist^^auf das Objekt drausfsetzen, das ist doch auch nix anderes. Also in irgendeiner Form musst du dem System ja sagen, dass sich was verändert hat... oder seh ich das falsch?
Doch, das ist schon was anderes. Denn mit nem ChangeListener werde ich über die Änderung benachrichtigt (die Listener-Methode wird aufgerufen). Also weiß ich: Es hat sich etwas geändert, und jetzt muss ich so und so reagieren. Dahingegen wenn das einfach so im Setter verschluckt wird, dann wird keine Methode o.ä. aufgerufen. Der Code geht normal nach dem setter-Aufruf in der nächsten Zeile weiter, und ich hab nicht den blassesten Schimmer von der Änderung irgendeiner komischen Variable, die für mich mit dem Setter gar nix zu tun hat.
Würde ich eine Methode selectStartNode(Point location) und eine Methode selectEndNode(Point location) haben, dann wäre der Code ziemlich redundant oder sehe ich das falsch?
Ich muss sagen so ganz blick ich nicht durch. Deine createEdge-Methode tut eindeutig mehr als sie tun sollte. Wenn man ihrem Namen glauben schenkt - was der Fall sein sollte - sollte sie so aussehen:
Java:
createEdge(Node n1, Node n2)
Edge e = new Edge(n1, n2);
p.addEdge(e);
}
Und klar, jetzt musst du den Rest vom Code irgendwo anders unterbringen. Und ja, irgendwo brauchst du sicherlich eine einfache if-Prüfung, um herauszufinden ob irgendwo eine Node als Start angewählt wurde oder nicht. Aber wenn du das anders aufziehst, muss das kein boolean sein. Ich seh jetzt nicht die gesamte Klasse usw, aber intuitiv würd ich sagen brauchst du einfach 2 Instanz-Variablen edgeStartNode und edgeEndNode, und in deinen mousePressed/mouseReleased methoden setzt du diese Nodes entweder auf ne Instanz die du erzeugst, oder halt auf null. Und wenn beide != null (bei mouseReleased oder wann auch immer so ne Kante erzeugt werden sollte), rufst du die edgeNode mit diesen beiden Nodes auf. Da brauchst du keinen gesonderten boolean mehr dafür.
So nen krassen Unterschied gibt's da nicht, versteh mich nicht falsch. Ich würd jetzt auch nicht sagen dass das mit nem boolean irgendwie falsch oder doof oder sonst was wär. Ich find aber du solltest den Code mal etwas aufbröseln, und Methoden erstellen die das tun wonach sie klingen (nicht mehr und nicht weniger).
Und
Java:
private Node selectNode(Point location) {
for (Node n : p.getSelectedNodes()) {
if (n == isNodeSelected(location)) {
return n;
}
}
return null;
}
sieht auch danach aus als könnte man da am Design optimmieren. Die Methode heißt selectNode, bekommt aber keine Node sondern nen Point. Aus irgendeiner Collection zieht sie sich Nodes, und dann gibt's noch ne Methode isNodeSelected die diesen Point bekommt. Und dann returnest du diese Node? Also sorry aber für mich klingt das wie ne Methode, die eine Node auswählen soll, aber nur dann, wenn diese Node bereits ausgewählt ist.. Also irgendwie strange.
Die Methode getStartNodeSet könnte auch einen passenderen Namen vertragen 🙂
Ich vermute mal da sie in einem boolean-Kontext verwendet wird, dass die Methode die Information zurückliefert ob der StartKnoten gesetzt wurde, in dem Fall wäre isStartNodeSet() passender.
So könnte sie auch ein Set von irgendwelchen Daten des Startknotens zurückliefern 😉
Die If-Abfragen könnte man dann noch auf positive überprüfungen umstellen, indem man die Zweige von if-else vertauscht, positive Abfragen lassen sich leichter nachvollziehen als negationen.
In der Methode selectNode sieht mir auch komisch aus, das hat hdi ja auch bereits angesprochen,
Du Iterierst hier über alle selektierten Nodes und vergleichst sie dann per == Operator (nicht mit equals() !!!) mit einer Methode isNodeSelected(location). Vom Namen her erwarte ich von der Methode eher, dass sie prüft ob ein Knoten selektiert wird wenn an der Lokation geklickt wird, dann müsste der aufruft aber so aussehen : n.isNodeSelected(location). Die Methode macht offenbar also auch etwas ganz anderes als der Name vermuten lässt.
In der Hauptmethode selbst reagierst du ja auch auf einen Klick, was mir hier noch auffällt ist, dass
du einmal den selectedNode ermittelst und die lokal speicherst, aber da wo du ihn verwenden könntest (z.B. in Zeile 8) ermittelst du ihn gerade nochmal neu Anstatt dein schon berechnetes Ergebnis zu verwenden.
Kannst du evtl noch etwas mehr Code von den anderen angesprochenen Methoden zeigen?
Dann kann man die Abhängigkeiten der Methoden vielleicht besser auseinanderziehen.
Nachdem Ihr beide meinen Code so schön auseinander gepflückt habt und die ersten Tränen getrocknet sind, bin ich zu dem Entschluss gekommen das ganze noch einmal zu überarbeiten. 😀
Möchte mich aber bei Euch beiden bedanken, das Ihr euch die Mühe gemacht habt. Ich hatte ja schon das Gefühl, dass hier etwas im Argen liegt. Es handelt sich um mein erstes Projekt und da bin ich für jeden Tipp dankbar.
ich glaube nun die Ursache für mein Strukturproblem gefunden zu haben.
Mir will einfach keine sinnvolle Vorgehensweise für die Auswahl schon vorhandener Objekte einfallen.
Meine Überlegung war, dass bei jedem Klick in die Zeichenfläche erst einmal geprüft werden soll, ob ein bereits vorhandenes Objekt ausgewählt wurde. Ich weiß aber nicht, wie ich den Ablauf vernünftig umsetzten soll.
Wäre für etwas Inspiration sehr dankbar.
Ich kann mir noch immer nicht genau vorstellen was man in deinem Programm eigentlich macht. Man hat ne Zeichenfläche, und kann dort Knoten erstellen und diese mit Linien miteinander verbinden? Kann man noch mehr machen? Anders gefragt: Meinst du mit "vorhandenes Objekt" nun einen Knoten, oder kann das auch was anderes sein?
Damit meine ich auch Kanten. Ich habe ein Interface Netzelement angelegt und Kanten und Knoten implementieren dieses.
Mittlerweile bin ich auch ein kleines bisschen weiter gekommen. Ich habe nun eine Methode
Code:
isNetElementClicked()
und eine
Code:
getClickedNetElement()
hinzugefügt und die bereits vorhanden Methoden so umgeschrieben, dass sie tun, was sie sollen bzw. was man erwartet.
Trotzdem würde mich interessieren, wie Du/Ihr das lösen würdest/würdet.
Klingt doch okay. Solange die getClickedNetElement() oder die isNetElementClicked() jetzt jeweils aus nicht mehr als ein paar wenigen Zeilen besteht. Wenn du da jetzt wieder komplexere Logik drin hast stimmt noch immer was nicht im Design.
Um da was allgemeineres sagen zu können müsste man wissen wie der Aufbau deines Netzes ist, sowohl logisch als auch grafisch. Du sagst du hast Knoten und Kanten. Ich finde zB dass im Core Model sowas wie ne Kante gar nicht braucht. Die einzelnen Knoten haben ne Liste mit Referenzen auf in- und out-Knoten. Dadurch definieren sich ja die Kanten, also wenn Knoten A ne Referenz auf Knoten B hat und umgekehrt, dann ist das offensichtlich ne Verbindung = Kante. Wieso also ne Klasse Kante? Wie sehen denn deine Klassen Knoten & Kante aus? Und dieses NetElement-Interface.. nutzt du das einfach als Marker Interface? (Leeres Interface ohne Methoden)
Klingt doch okay. Solange die getClickedNetElement() oder die isNetElementClicked() jetzt jeweils aus nicht mehr als ein paar wenigen Zeilen besteht. Wenn du da jetzt wieder komplexere Logik drin hast stimmt noch immer was nicht im Design.
Um da was allgemeineres sagen zu können müsste man wissen wie der Aufbau deines Netzes ist, sowohl logisch als auch grafisch. Du sagst du hast Knoten und Kanten. Ich finde zB dass im Core Model sowas wie ne Kante gar nicht braucht. Die einzelnen Knoten haben ne Liste mit Referenzen auf in- und out-Knoten. Dadurch definieren sich ja die Kanten, also wenn Knoten A ne Referenz auf Knoten B hat und umgekehrt, dann ist das offensichtlich ne Verbindung = Kante. Wieso also ne Klasse Kante?
Ich hatte mich damals dafür entschieden, dass ich eine Klasse Kante mache, da beim Löschen eines Knoten auch alle seine ein- und ausgehenden Kanten gelöscht werden sollen.
Es wäre sicherlich auch so gegangen, wie Du es beschrieben hast. Ob es einfacher gewesen wäre, weiß ich nicht. Aber da es sich um ein Projekt mit Abgabetermin (war bereits) handelt, möchte ich jetzt nicht noch einmal alles komplett umschreiben. Die bisherigen Änderungen sind schon weitgehender als ich dachte.
Nach der Sichtung des Programms wird es noch eine Korrekturphase geben. Mal sehen, was beanstandet wird.
Wie sehen denn deine Klassen Knoten & Kante aus? Und dieses NetElement-Interface.. nutzt du das einfach als Marker Interface? (Leeres Interface ohne Methoden)