Best Practices für Undo/Redo

Marco13

Top Contributor
Hallo

Ich bastle gerade an einem Editor (vereinfacht gesagt: Für etwas, was aus Knoten und Kanten besteht) und wollte dabei zum ersten mal eine richtige Unterstützung für Undo/Redo einbauen. Die grundlegenden Konzepte mit UndoManager und UndoableEdit sind ja recht einleuchtend. Was mich aber doch (mehr als erwartet) irritiert ist der ungeheure Planungsaufwand. DASS es aufwändig ist, war mir klar, und auch dass es praktisch unmöglich ist, so etwas nachträglich in ein bestehendes System einzubauen. Ich merke jetzt aber, dass ich viele Dinge nur für das Undo/Redo komplett anders mache, als ich es eigentlich machen würde. Die ganzen Schnittstellen scheinen sich immer mehr an dem Ziel zu orientieren, alles mit Undo/Redo behandeln zu können, und werden dadurch irgendwie un-intuitiv...

Kennt jemand gute Beispiele dazu, wie man auch kompliziertere Anwendungen mit Undo/Redo aufbaut? Die Dinge, die man mit schnellen Websuchen findet, beziehen sich meistens auf irgendwelche Trivialbeispiele. Insbesondere habe ich noch kein vernünftiges Beispiel gefunden, das zeigt, wie man sinnvoll mehrere Edits zu einem größeren Edit gruppieren kann. Der Versuch, aus den bestehenden Implementierungen z.B. rund um 'AbstractDocmument' herum schlau zu werden scheint ein ungünstiges Verhältnis zwischen Quellcode-Scrollen und Aha-Effekten zu haben...

bye
 
F

Firephoenix

Gast
Wie wäre es denn mit einem Ansatz per Command-Pattern?
Wenn jeder command ein undo() implementieren muss ist es dann sogar extrem leicht ausgeführte Befehle zu speichern oder zu gruppieren, bzw auch als Gruppe rückgängig zu machen.

[EDIT]Die 2 von dir angesprochenen Klassen scheinen aber schon stark in die Richtung zu gehen, ein besserer ansatz als ein angepasstes Designpattern fällt mir aber auch nicht ein.[/EDIT]

Gruß
 
Zuletzt bearbeitet von einem Moderator:

F.S.WhiTeY

Bekanntes Mitglied
Wenn jeder command ein undo() implementieren muss ist es dann sogar extrem leicht ausgeführte Befehle zu speichern oder zu gruppieren, bzw auch als Gruppe rückgängig zu machen.

Richtig! Man könnte das dann sogar als eine Art doppelt verkettete Liste implementieren (oder eine solche nutzen), was die vor- und rückwärts navigation erleichtern würde.
 

Marco13

Top Contributor
Hmja, über das Command Pattern stolpert man da natürlich. Es ist recht nahe liegend, und die existierenden Klassen (UndoManager & Co) haben schon Ähnlichkeiten dazu (im Prinzip kann man mit UndoableEdits auch ziemlich genau das Command Pattern in seiner einfachsten Form nachbauen).

Ich dachte auch kurz, dass es vielleicht einfacher sein könnte, das ganze from scratch minimalistisch mit eigenem Command-Pattern selbst zu schreiben. Einige der Konzepte sind wohl in beiden Fällen gewöhnungsbedürftig...

Aber es gibt auch einige Fragen, die sich in beiden Fällen stellen. Eine ist die Granularität. An einem sehr suggestiven Beispiel: Es geht, wie gesagt, um Knoten und Kanten. Nun würde man eigentlich Methoden anbieten, mit denen man
- einen Knoten selektieren kann
- einen Knoten DEselektieren kann
- eine Kante selektieren kann
- eine Kante DEselektieren kann
Wenn man nun Untersützung für Undo/Redo will, tut es da eben kein "setNodeSelected(boolean)" mehr, sondern man braucht ein Command (oder UndoableEdit - ich verwende die jetzt mal Synonym). Für jede einzene Operation? Ja, vermutlich. Und wenn man (mit einem Auswahlrechteck) 20 Knoten gleichzeitig auswählt, werden dann 20 Commands für die Auswahl eines einzelnen Knotens erstellt? (Und ggf. zusammengefasst?) Oder macht man ein Command, mit dem man eine Menge von Knoten auswählt? Und wenn mit derselben Benutzeraktion auch 40 Knoten DEselektiert wurden? Und das ganze auch für Kanten gilt? Ich bin da am Schwanken, und nicht sicher, wie die Struktur am günstigsten ist. Es reicht vom hyper-feingranularen
Java:
class NodeSelectionCommand implements Command 
{
    private Node node;
    void undo() { editor.setNodeSelected(node, false); }
    void redo() { editor.setNodeSelected(node, true); }
}
class NodeDeSelectionCommand implements Command ...
class EdgeSelectionCommand implements Command ...
class EdgeDeSelectionCommand implements Command ...
...
wo man ggf. sehr viele Commands auf unterschiedlichste Weisen gruppieren müßte, bis zum Schweizer Taschenmesser der Selektion
Java:
class SelectionCommand {
    private Set<Node> nodesAdded;
    private Set<Node> nodesRemoved;
    private Set<Edge> edgesAdded;
    private Set<Edge> edgesRemoved;
...
wo ich im Moment bin, mit einem etwas schwummrigen Gefühl im Bauch. (Das ganze auch unter Berücksichtigung der Tatsache, dass jedes Ausführen eines Commands auch die Benachrichtigung von Listenern zur Folge hat, und da so EIN "mächtigeres" Command vielleicht sinnvoller wäre...)


Zusätzlich bin ich mir bei einigen Verantworklichkeiten nicht ganz sicher. Wenn man einen ausgewählten Knoten löscht, dann ist er danach nicht mehr selektiert. Wer ist dafür verantwortlich, die Selektion aufzuheben? Wenn man das Löschen rückgängig machen will, muss das Lösch-Command ja auf jeden Fall über die vorherige Selektion bescheid wissen. Wird das mit einem Unter-Command gemacht...
Java:
class DeleteCommand implements Command {
    private NodeDeSelectionCommand deSelection; // may be null...
    ...
}
!? Spätestens wenn man von 100 Knoten 50 auswählt und davon dann 20 gelöscht werden, und dadurch vielleicht 10 Kanten wegfallen von denen 5 ausgewählt waren, wird das ja ziemlich kompliziert... ???:L Es scheint mir eben, als müßte man seine ganzen Schnittstellen und angebotenen Operationen darauf ausrichten, möglichst leicht in Commands/UndoableEdits umwandelbar zu sein (und was "möglichst leicht" ist, da taste ich mich gerade erst ran...)
 
G

Gast2

Gast
Du machst einzlene Commands und wenn du mehrere durchführen willst machst du ein CompboundCommand welches eine Liste aller anderen Commands hat. Das kann man alles generisch halten.
z.B.
CompoundCommand (EMF Javadoc)

Wenn du "nur" setter aufrufst musst nur immer den alten Wert speichern und den bei undo setzen und bei redo wieder den neuen wert.
Bei so einem "SetCommand" kannst viel mit Reflection machen. z.B.
SetCommand (EMF Javadoc)

Wie gesagt es gibt vieles schon, vielleicht kannst du davon einiges verwenden.
 
Zuletzt bearbeitet von einem Moderator:

Marco13

Top Contributor
Meine Antwort und ein Hinweis auf EMF haben sich überschnitten. Ich hatte schon gelesen, dass es im RCP-Umfeld da einiges geben soll (z.B. auch in JFace). Das von EMF sieht auf den ersten Blick strukturell sehr ähnlich (fast gleich) aus wie UndoableEdit & Co. Verwenden kann man da sicher das eine oder andere, aber über die oben angedeuteten Punkte bin ich mir trotzdem noch nicht ganz im klaren. Es erscheint etwas ungewohnt... einerseits dass alle Änderungen am Modellzustand über Commands abgebildet werden müssen, und andererseits dass das wirklich erschöpfend sein muss - also im algebraischen Sinn vollständig und abgeschlossen. Schon eine vermeintliche Kleinigkeit wie...
Java:
void removeNode(Node node)
{
    nodes.remove(node);
    selectedNodes.remove(node); // ... ein beiläufiges un-selektieren (egal ob er selektiert war oder nicht!)
    ...
macht ja sämtliche Undo/Redo-Ziele kaputt... vom dort offensichtlich noch fehlenden
Java:
    for (Edge edge : edgesThatAreConnectedTo(node))
    {
        removeEdge(edge);
    }
}
und dem, was DAS dann wiederum für Auswirkunge hat, mal ganz abgesehen :rolleyes: Insgesamt muss man anscheinend ziemlich viel Wissen über das Modell in die Undo/Redo-Funktionalität stecken - und dann noch aufpassen, dass das beides nicht inkonsistent wird...
 
G

Gast2

Gast
Meine Antwort und ein Hinweis auf EMF haben sich überschnitten. Ich hatte schon gelesen, dass es im RCP-Umfeld da einiges geben soll (z.B. auch in JFace).
Nein EMF ist davon vollkommen losgekoppelt.

EMF bietet auf Modelebene Undo/Redo an d.h. du rufst einfach einem ChangeCommand deine Modell Änderungen auf und musst das undo/redo dazu nicht mehr implementieren. Hat nichts mit der UI oder sonstigem zu tun.

Ich verstehe noch nicht ganz was du mit deinem Selektieren/Deselektieren erreichen willst? Habe ich noch nie gesehen dass es dafür Undo/Redo gibt, kenn ich zumindest keinen UseCase oder eine sonstige Anwendung.
Das wäre ein undo/redo auf einen UI zustand. Aber ein undo/redo macht man meistens wenn sich was geändert hat (Model) und die Änderung ruckgängig machen will.


Klar ist jede Modeländerung muss dann über ein Command gehen.
 
Zuletzt bearbeitet von einem Moderator:
S

Spacerat

Gast
Was meinst du eigentlich mit Verantwortlichkeiten? Es gibt diese Commands und das Objekt an dem sie ausgeführt werden. Sinnvollerweise speichert man die einzelnen Commands mit allen zugehörigen Daten in der Reihenfolge, in der man sie ausführt. Undo führt man dann vom Ende der Liste bis zum Anfang aus und Redo halt in die Richtung, in der man sie zuvor ausgeführt hat. So kann es eigentlich kaum passieren, dass plötzlich etwas selektiert wird, was zuvor gelöscht wurde. Deswegen müssen sich diese Commands untereinander auch nicht über Listener verständigen bzw. durch das Objekt über Änderungen informiert werden. Erst wenn man so eine Liste als Makro implementiert, können zwischendrin Schritte entfernt oder hinzugefügt werden, die einzelnen Commands solcher Makros sollten dann aber zumindest Exceptions werfen, wenn etwas nicht stimmt (z.B. bei Selektierung nicht vorhandenen Inhalts).
BTW.: Listener heisst Zuhörer und nicht Täter. Das bedeutet, dass Listener höchstens auf Änderungen reagieren, jedoch nie versuchen sollten etwas Rückgängig zu machen.
@SirWayne: Den Usecase hat man z.B. bei 3D-Editoren (C4D, 3DS usw.). Wenn man z.B. viele dicht beieinander liegende Punkte oder Kanten mit einer Art "Pinsel" gleichzeitig selektieren will und sich nach einer bereits heiden Arbeit dabei mal kurz verhaspelt.
 
Zuletzt bearbeitet von einem Moderator:
B

bygones

Gast
ich wuerde nicht jegliche Aktion/Command in deinem Editor dann ein neues Interface oder sonstiges aufbrummen die dann beschreiben wie undo/redo geht.

Du brauchst im Grunde ja nur einen Manager der Events verwaltet, ein Event kann redo/undo und alle Commands die eben undo/redo unterstuetzen sollen feuern bei einer Aktion ein solches Event. Der Manager nimmt diese dann auf und kann diese dann eben undo/redo-en.

was ist denn so besonders dass bei einer selektieren man undo/redo machen will ? Ich wuerde intuitiv dies nicht also solche Aktion sehen.

Generell wuerde ich es so sagen:

Jede Aktion die undo/redo unterstuetzen soll feuert ein Event mit den Infos wie dies geschieht. Der Manager sammelt diese und ueber ihn kann dann die eigentlich undo/redo aktion ausgefuehrt werden.

Muessen Aktionen gesammelt werden um ein "atomares" Undo/redo zu erlauben, so helfen Strukturen wie javax.swing.undo.CompoundEdit (allg siehe javax.swing.undo package).

Keine Ahnung ob und wie EMF das kann, einfach macht oder so.

und dem, was DAS dann wiederum für Auswirkunge hat, mal ganz abgesehen :rolleyes: Insgesamt muss man anscheinend ziemlich viel Wissen über das Modell in die Undo/Redo-Funktionalität stecken - und dann noch aufpassen, dass das beides nicht inkonsistent wird...
genau gesehen braucht die Undo/Redo Funktionalitaet an sich kein Wissen ueber das Modell, wann man wie welche Events feuert bedarf etwas wissen, aber auch das find ich nicht so schlimm, wenn man granulare Aktionen hat und dann eben per Gruppierung diese zusammenbringt
 
Zuletzt bearbeitet von einem Moderator:
G

Gast2

Gast
Keine Ahnung ob und wie EMF das kann, einfach macht oder so.

EMF hat ein CommandStack auf dem du Command ausführst.
CommandStack (EMF Javadoc)

Und wie gesagt gibt es schon einiges Commands dazu.
org.eclipse.emf.edit.command (EMF Javadoc)

Am einfachsten ist man benutzt das ChangeCommand das kann man dann alles an seinem Model ändern. Durch die typisierte Reflection API und eigene Notfication Framework kann EMF selber seine undo/redo Aktionen bauen.


@SirWayne: Den Usecase hat man z.B. bei 3D-Editoren (C4D, 3DS usw.). Wenn man z.B. viele dicht beieinander liegende Punkte oder Kanten mit einer Art "Pinsel" gleichzeitig selektieren will und sich nach einer bereits heiden Arbeit dabei mal kurz verhaspelt.

Okay trotzdem sehe ich das Problem von Marco nicht =)
 
S

Spacerat

Gast
@bygones: Un-/Redo sind keine Aktionen, die irgendwo unterstützt werden müssen, für dahinführende Aktivitäten Events eindeutig die falsche Wahl. Das bedeutet nicht, dass bei Änderungen keine Events gefeuert werden dürfen.
Mal ein simples Beispiel, womit man z.B. "<BufferedImage>.setRGB()" (eine Methode von der wir wissen, dass sie keine "verwendbaren" Events feuert) aufzeichnen, rückgangig machen und rückgängig machen widerrufen kann.
Java:
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;


public class MakroImage {
	private final List<Command<?>> steps = new ArrayList<>();
	private final BufferedImage toWorkOn;
	private int step = -1, size;

	public MakroImage(BufferedImage toWorkOn) {
		if(toWorkOn == null) {
			throw new NullPointerException();
		}
		this.toWorkOn = toWorkOn;
	}

	public int setRGB(int x, int y, int rgb) {
		Command<Integer> c = new Command<Integer>() {
			private int savedColor, setColor, x , y;

			@Override
			public Integer execute(Object ... args) {
				if(args.length < 3) {
					throw new RuntimeException("invalid number of arguments");
				}
				for(Object o : args) {
					if(!(o instanceof Integer)) {
						throw new RuntimeException("invalid type");
					}
				}
				x = (Integer) args[0];
				y = (Integer) args[1];
				setColor = (Integer) args[2];
				savedColor = toWorkOn.getRGB(x, y);
				redo();
				return savedColor;
			}

			@Override
			public void undo() {
				toWorkOn.setRGB(x, y, savedColor);
			}

			@Override
			public void redo() {
				toWorkOn.setRGB(x, y, setColor);
			}
		};
		if(step < size) {
			steps.add(c);
			size = steps.size();
			step = size - 1;
		} else {
			steps.set(step++, c);
			steps.set(step, null);
			size = step;
		}
		return c.execute(x, y, rgb);
	}

	public void undo() {
		if(step < 0) {
			return;
		}
		steps.get(step--).undo();
	}

	public void redo() {
		if(step >= size) {
			return;
		}
		steps.get(step++).redo();
	}
}

interface Command<T> {
	T execute(Object ... args);
	void undo();
	void redo();
}
Den Code hab' ich mal ungetestet gepostet, kann sein, dass ich mich evtl. bei den Zählern "size" und "step" oder gar beim "Stack" allgemein verhauhen hab', aber Hauptsache, das Prinzip wird deutlich.

Okay trotzdem sehe ich das Problem von Marco nicht =)
Ich auch nicht. Könnte daran liegen, dass es nicht wirklich eines gibt, wo er eines sieht. ;)
Spacerat hat gesagt.:
So kann es eigentlich kaum passieren, dass... usw.
 
Zuletzt bearbeitet von einem Moderator:

homer65

Top Contributor
Habe sowas in meinen IconEditor eingebaut. Der zugehörige Quelltext ist im IconEditor.jar, was von der Download Seite von MyOggRadio runtergeladen werden kann.
Wenn ich mich recht erinnere, funktioniert das in etwa so:
Das zu editierende ist ein Icon. Alles was ein Icon verändert muß das Interface Operation implementieren. Dann speichert man jede Operation in eine ArrayList. Um nun Undo oder Redo zu machen braucht man nichts als das zu Anfang gesicherte Icon und die Liste mit den Operation.
 

Marco13

Top Contributor
Was meinst du eigentlich mit Verantwortlichkeiten?

Nun, der Fall dass man etwas löscht und dabei die Selektion dieses Objektes aufgehoben werden muss, war eben so ein Beispiel. Die durchgeführte Aktion ist "Delete". Also erstellt man ein DeleteCommand, und das ruft
model.delete(node);
auf. IN dieser Methode wird aber z.B. auch die Selektion aufgehoben. Wenn man das Delete rückgänig macht, z.B. durch
model.add(node);
dann ist der Knoten danach nicht ausgewählt. Das DeleteCommand müßte also auch über die Selektion bescheid wissen. Wäre das dann
Java:
void execute() {
    if (model.isSelected(node)) {
        // Wird bei model.remove intern automatisch gemacht,
        // aber damit man es rückgängig machen kann...:
        subCommand = createSubCommandToUnselect(node);
    }
    model.remove(node);
}
void undo() {
    model.remove(node);
    if (sumCommand != null) subCommand.undo();
}
? Aber üblicherweise ist "model" nur ein Interface, und man weiß im Zweifelsfall nicht, was bei einem "remove(node)" alles NOCH passiert....

Vielleicht geht es nur um die allgemeine (SEHR offensichtliche, aber doch schwierig zu beantwortende) Frage, wie man den Systemzustand "kapselt", und sicherstellt, dass ALLE (auch indirekten) Folgen einer Aktion rückgängig gemacht werden. Ab einer bestimmten Komplexität kommt sowas wie Memento IMHO auch nicht mehr in Frage. Man bewegt sich durch die Methodenaufrufe u.U. durch einen sehr komplexen Zustandsraum.

@bygones: Ich kann mir nicht vorstellen, dass dieses Kapseln und Konservieren des Systemzustandes möglich ist, NUR indem man auf Events hört. Spacerat hat da ja ein Beispiel gepostet.

@Spacerat Vielleicht sehe ich (mal wieder) ein Problem, wo keines ist ;) Ich will das ganze aber nicht zuuu sehr problematisieren, man findet da sicher eine Lösung, und vermutlich muss ich es nur ein, zwei mal "falsch" implementieren, um zu sehen, wie es richtig gegangen wäre.
Ich hatte ja auch nur nach Best Practices gefragt, bzw. nach Beispielen, die über solche trivialen wie deins ( :bae: ) hinausgehen. Dass man ein "list.add(x)" oder "image.setRGB(...)" leicht rückgängig machen kann, ist klar. Aber stell dir vor, du würdest jetzt in die BufferedImage-Doku schauen, und dort eine Methode sehen wie
int getLastSetRGB(...)
die die zuletzt mit setRGB gesetzte Farbe zurückliefert: Dann wäre dein Undo schon "kaputt" bzw. unzureichend, und im schlimmsten Fall könnte so eine Aktion dann gar nicht rückgängig gemacht werden. Aber das liegt dann wohl in der Verantwortung desjenigen, der das Modell entwirft. Die einzig sinnvolle "übergeordnete" Gegenmaßnahme, die mir demnach jetzt einfallen würde, wäre, das gesamte Modell explizit auf undo/redo auszurichten, indem man ganz gezielt die Methoden entsprechend "paarweise" anbietet, aber das könnte im Einzelfall dann doch schwierig werden...
 
B

bygones

Gast
die Wahl des Worts "Events" war anscheinend falsch...

@Spacerat:
dein makroImage ist jetzt doch alles... manager, ausfuehrer, redo/undo verantwortlicher ?

ich geh mal davon aus dass es nur ein einfaches bsp gehalten ist...

Aber stell dir vor, du würdest jetzt in die BufferedImage-Doku schauen, und dort eine Methode sehen wie
int getLastSetRGB(...)
die die zuletzt mit setRGB gesetzte Farbe zurückliefert: Dann wäre dein Undo schon "kaputt" bzw. unzureichend, und im schlimmsten Fall könnte so eine Aktion dann gar nicht rückgängig gemacht werden.
was ist daran schwerer als bei dem geposteten Bsp... man muesste sich halt nur die letzte Farbe immer merken. Mehr nicht. Redo/undo rufen dann entsprechend die setRGB oder was ich immer auf und speichern sich wieder die alte Farbe.

du musst auch dein Model nicht daraufauslegen und "gepaarte" Methoden anbieten. Wie gesagt, es gibt zb in swing modelle fuer das gruppieren solcher Commands (genauso gemischer begriff)
 
Zuletzt bearbeitet von einem Moderator:
S

Spacerat

Gast
Mal 'ne andere Frage: Woher weis das Model eigentlich, dass eine Node selektiert wurde? Speichert er selektierte Nodes in einer separaten Liste, dann hättest du ein Problem. Setzt du stattdessen in der Node ein Selected-Signal (bzw. Flag), lassen sich auch selektierte Nodes problemlos entfernen und auch wieder hinzufügen. Das Command muss ja den Zustand der einzelnen Nodes gar nicht ändern.

Mein Beispiel sollte aber überall funktionieren, auch bei weniger trivialen Dingen. Sofern der Mechanismus im Model also selektierte Nodes in einer separaten Liste speichert, muss man dieses bei der Ausführung des Commands halt beachten und es genauso machen. Und das ist genau der Punkt, wenn man einem Objekt Rollback-Funktionalität beibringen will. Man muss wissen wie die Methoden arbeiten bzw. wie man an die Information Zustand-Alt kommt und diese so speichert, dass man sie leicht widerherstellen kann.

@bygones: Jep, das MakroImage würde im Prinzip eine komplette Kapselung eines BI's ergeben, wenn man's weiter ausrollt. Evtl. könnte man es sogar erweitern und jeder einzelnen Methode diese Funktionalität beibiegen.
 
Zuletzt bearbeitet von einem Moderator:

Marco13

Top Contributor
@bygones: was ist daran schwerer als bei dem geposteten Bsp... man muesste sich halt nur die letzte Farbe immer merken. Mehr nicht. Redo/undo rufen dann entsprechend die setRGB oder was ich immer auf und speichern sich wieder die alte Farbe.

Ja, wenn man das rückgängigmachen durch einen Aufruf von setRGB(oldColor) erledigen kann, stimmt das - daher war das als Beispiel unzureichend. Jetzt zu sagen, dass das, was ich eigentlich meinte, auftreten würde, wenn es eine Methode gäbe wie
List<Integer> getAllArgumentsThatHaveBeenPassedToSetRGBUntilNow()
würde vielleicht zu konstruiert wirken ... mal schauen ob mir noch was praxisnäheres einfällt :oops:


@Spacerat: Mal 'ne andere Frage: Woher weis das Model eigentlich, dass eine Node selektiert wurde?

Es gibt einmal das reine "Datenmodell", das über die Selektion nichts weiß. Wenn man die Selektion aber rückgängig machen können will, muss es eine Modellhafte Repräsentation des Selektionszustandes geben (grob wie ein ListSelectionModel in Swing). Dieses Modell enthält z.B. auch die Positionen von Knoten auf dem Bildschirm, was ja auch nicht unbedingt mit einer reinen Datenstruktur zu tun hat, sodern nur mit ihrere Präsentation (und z.B. zum Rückgängigmachen von Verschiebungen notwendig ist).

Man muss wissen wie die Methoden arbeiten bzw. wie man an die Information Zustand-Alt kommt und diese so speichert, dass man sie leicht widerherstellen kann.

Ja, das meinte ich mit der Aussage, dass man u.U. viele Innereien seines Modells exponieren muss. Die Zustandsübergänge müssen eindeutig und umkehrbar sein, und u.U. sind die ja recht kompliziert, und teilweise eigentlich NUR Sache des Modells. Das Wissen darüber, wie ein Modell-Methodenaufruf rückgängig gemacht werden kann herauszukristallisieren, und das Modell so zu gestalten, dass man dieses Wissen tatsächlich zum Rückgängigmachen nutzen kann, ist (soweit ich das bisher überblicke) nicht durch ein reines "Einwickeln von Methodenaufrufen in Commands" getan, sondern wirklich eine weitere Dimension bei der Planung und Spezifikation der Modellschnittstelle. Nicht unmöglich, und IMHO sogar recht spannend, aber kann schon aufwändig sein....
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
M Best Practices Exception Handling für eigene library Allgemeine Java-Themen 8
S Best Practices CopyConstrutor mit ArrayList Allgemeine Java-Themen 1
F Error Logging - best practices? Allgemeine Java-Themen 3
G Best Practices Software-Engineering‏ Allgemeine Java-Themen 3
G Best Practices Allgemeine Java-Themen 10
Ameise03 Best&Worst Case bei Insertionsort Allgemeine Java-Themen 10
T Best Practice überprüfen von Übergabeparametern Allgemeine Java-Themen 17
S best practice: Einordnung Enitity und Datenklasse Allgemeine Java-Themen 11
temi best practice: Parameter überprüfen, wo? Allgemeine Java-Themen 9
Airwolf89 JUnit: Vorschläge/ Best Practice Allgemeine Java-Themen 7
M Best Practice: Daten aufnehmen-speichern-bereitstellen Allgemeine Java-Themen 8
H Best Practice zu vielen konstanten Objekten? Allgemeine Java-Themen 10
F best practice Allgemeine Java-Themen 5
J Input/Output Dateien bearbeiten - "Best Practice" Allgemeine Java-Themen 3
R Statische Klasse: Best practice mit flags (2) Allgemeine Java-Themen 3
musiKk Best Practice für kleine Variationen in gegebenen Modellklassen Allgemeine Java-Themen 11
S best practise Allgemeine Java-Themen 6
J Best Practice für implementierung von equals(...) Allgemeine Java-Themen 7
Daniel_L Best Practice zum Löschen von Log-Files? Allgemeine Java-Themen 8
S Array: Anzahl Elemente mit best. Wert zählen Allgemeine Java-Themen 4
M Best Match / Best Fit auf Strings Allgemeine Java-Themen 9
G Exception handling - b.practices/tipps. etc. Allgemeine Java-Themen 3
Karl_Der_Nette_Anfänger Hat wer ne Lösung für verknüpfte Postleitzahlen? (Baum/Wurzel Struktur) Allgemeine Java-Themen 11
R 11 GB File lesen ohne zu extrahieren Filedaten Bereich für Bereich adressieren dann mit Multi-Thread id die DB importieren Allgemeine Java-Themen 3
G KeyListener für JTextField Allgemeine Java-Themen 5
webracer999 Library für Textsuche (z. B. include/exclude, and/or)? Allgemeine Java-Themen 5
I Module-Info für Jar erzeugen Allgemeine Java-Themen 7
krgewb Java-Bibliothek für ONVIF Allgemeine Java-Themen 1
B Simpler Eventlistener für Tastaturtaste bauen? Allgemeine Java-Themen 13
_user_q Eingegebenen Text Zeile für Zeile ausgeben lassen Allgemeine Java-Themen 11
E Key für TOTP Algorythmus(Google Authentificator) Allgemeine Java-Themen 0
S Formel für Sonnenwinkel in ein Programm überführen Allgemeine Java-Themen 11
M pfx-Zertifikat in Tomcat für SSL-Verschlüsselung nutzen Allgemeine Java-Themen 14
R Best Practice Erfahrungswerte für eine Migration von JSF nach Angular (oder anderes JS-Framework) Allgemeine Java-Themen 1
B HeapSort für Array of Strings funktioniert nur teilweise Allgemeine Java-Themen 3
jhCDtGVjcZGcfzug Klassen Was genau passiert hier? Kann mir das jemand bitte Zeile für Zeile erklären? Allgemeine Java-Themen 1
rosima26 Bester Sortieralgorithmus für kurze Arrays Allgemeine Java-Themen 40
S Mit Methoden kann man definieren für was <T> steht. Geht das auch irgendwie für Variablen? Allgemeine Java-Themen 12
MangoTango Operatoren while-Schleife für Potenz Allgemeine Java-Themen 3
B Lottospiel, genug Reihen tippen für 3 Richtige (Spaß mit Arrays)? Allgemeine Java-Themen 46
B Mit welchen Datentypen und Strukturierung am Besten dutzende Baccaratspiele Shcritt für Schritt durchsimulieren? Allgemeine Java-Themen 26
D Klassendesign für einen Pascal Interpreter Allgemeine Java-Themen 6
I OCR Library für Belegerkennung Allgemeine Java-Themen 7
farah GetterMathod für Farbkanäle Allgemeine Java-Themen 6
B Welcher Datentyp für sehr große Zahlenbereiche? Allgemeine Java-Themen 1
S Webservices für binäre Daten? Allgemeine Java-Themen 5
G Licence-Header für InHouse entwickelten Source Allgemeine Java-Themen 8
M Schleife für einen TicTacToe Computer Allgemeine Java-Themen 5
O git ignore für Intellji braucht es die .idea Dateien? Allgemeine Java-Themen 8
F Java Script für das Vorhaben das richtige? Allgemeine Java-Themen 9
M wiviel Java muss ich für die Berufswelt können ? Allgemeine Java-Themen 5
Robertop Datumsformat für GB ab Java 16 Allgemeine Java-Themen 1
Thallius Verschiedene entities für gleichen Code…. Allgemeine Java-Themen 8
OnDemand Zentrale "Drehscheibe" für verschiedene APIs Allgemeine Java-Themen 14
S Übergabe eines Sortierkriteriums für ein Artikel Array mittels BiPredicate<Artikel, Artikel> Allgemeine Java-Themen 13
F Streams als Alternative für dieses Problem ? Allgemeine Java-Themen 15
D SHA-3 für Java-version 1.8 Allgemeine Java-Themen 1
N Validator für einen SQL-Befehl Allgemeine Java-Themen 22
Muatasem Hammud Erstellung von Testdaten für Arrays Allgemeine Java-Themen 6
B Logikfehlersuche, das perfekte Lottosystem für 3 Richtige mit Arraylists? Allgemeine Java-Themen 61
G Methoden für die Zukunft sinnvoll? Allgemeine Java-Themen 4
M API für PLZ Umkreissuche Allgemeine Java-Themen 3
1Spinne JDK 8 für Eclipse installieren Allgemeine Java-Themen 5
Tobero Meine Funktion für das beinhalten eines Punktes in einem Kreis funktioniert nicht Allgemeine Java-Themen 5
L Methoden Parser für gängige Datumsformate? Allgemeine Java-Themen 1
H Interface PluginSystem ClassNotFound exception für library Klassen Allgemeine Java-Themen 10
N relativier Pfad für sqlite-Datenbank in Gradle/IntelliJ Allgemeine Java-Themen 2
buchfrau Anagram für beliebiges Wort Allgemeine Java-Themen 2
TonioTec Api für Datenaustausch zwischen Client und Server Allgemeine Java-Themen 0
W Suche Ursache für NPE - woher kommt sie? (Hilfe beim Debugging) Allgemeine Java-Themen 19
Kirby.exe Distanz Map für die Distanztransformation erstellen Allgemeine Java-Themen 1
F PI Regler für Heizung Allgemeine Java-Themen 7
8u3631984 Generelle Log4j.xml für alle Module Allgemeine Java-Themen 5
M Wie übergebe ich den Zähler für die Anzahl Rekursionsschritte korrekt? Allgemeine Java-Themen 2
B Login für User, der im Hintergrund Schedules ausführt Allgemeine Java-Themen 16
L RegEx für Teile einer Berechnung Allgemeine Java-Themen 14
S Java-Task-Management-Tool für Windows und Mac selber programmieren Allgemeine Java-Themen 4
M Java 2D Array für ein Grid erstellen ? Allgemeine Java-Themen 2
Z Welches GUI Framework für Java ist aktuell? Allgemeine Java-Themen 16
N Convert.FromBase64 von C# für Java Allgemeine Java-Themen 11
N fixed-keyword von C# für Java Allgemeine Java-Themen 6
O Suche Scripter für alt:V Project! Allgemeine Java-Themen 0
S Interface Design von HookUp oder Callback Methoden für eigenes Framework Allgemeine Java-Themen 9
O Suche Unterstützung für ein OpenSource-Projekt (grafischer Editor) Allgemeine Java-Themen 13
Kirby.exe Software für Graphische Visualisierung Allgemeine Java-Themen 20
B OOP Auslöser für NullPointerException Allgemeine Java-Themen 3
L Generator für einen Parser implementieren Allgemeine Java-Themen 13
DonMalte Ambitioniertes Projekt für Einsteiger & Motivierte Allgemeine Java-Themen 0
Kirby.exe Movement System für Spiel Allgemeine Java-Themen 13
Kirby.exe Framework für Game Design Allgemeine Java-Themen 8
W Alternative für Threads Allgemeine Java-Themen 6
S Rückgabe einer HttpURLConnection für eine Seite einlesen bei der man eingeloggt ist..? Allgemeine Java-Themen 5
Elyt Compiler-Fehler Datei kann nicht erstellt werden. Die Syntax für den Dateinamen etc. ist falsch. Allgemeine Java-Themen 2
Thallius Rätsel für Windows Profis Allgemeine Java-Themen 8
D OOP Gemeinsamen ID-Raum für zwei Klassen implementieren Allgemeine Java-Themen 7
D Input/Output Implementierung eines CommandHandlers/Parsers für viele Eingaben Allgemeine Java-Themen 26
Thallius Alternative für SwingWorker Allgemeine Java-Themen 5
I Lohnt sich heutzutage der Aufwand einer Portierung für MacOS Allgemeine Java-Themen 8
L Klassen Algorithmus für das folgende Problem entwickeln? Allgemeine Java-Themen 30
J Datenstruktur für eine Map erstellen Allgemeine Java-Themen 2

Ähnliche Java Themen

Neue Themen


Oben