Я работаю над небольшим проектом UML-редактора на Java, который я начал пару месяцев назад. Через несколько недель я получил рабочую копию для редактора диаграмм классов UML.
Но теперь я полностью переработал его для поддержки других типов диаграмм, таких как последовательность, состояние, класс и т. Д. Это делается путем реализации структуры построения графиков (меня очень вдохновляет работа Кей Хорстманн над тема с помощью Violet UML editor).
Редизайн шел гладко, пока один из моих друзей не сказал мне, что я забыл добавить функциональность Do / Undo в проект, что, на мой взгляд, жизненно важно.
Вспоминая курсы объектно-ориентированного дизайна, я сразу подумал о шаблоне Memento и Command.
Вот сделка. У меня есть абстрактный класс AbstractDiagram, который содержит два ArrayLists: один для хранения узлов (называемых элементами в моем проекте), а другой для хранения Edges (называемых ссылками в моих проектах). Диаграмма, вероятно, будет содержать стек команд, которые можно отменить / повторить. Довольно стандартный.
Как я могу эффективно выполнить эти команды? Скажем, например, что я хочу переместить узел (узел будет иметь тип интерфейса с именем INode, и из него будут получены конкретные узлы (ClassNode, InterfaceNode, NoteNode и т. Д.)).
Информация о положении хранится как атрибут в узле, поэтому, изменяя этот атрибут в самом узле, состояние изменяется. Когда дисплей будет обновлен, узел переместится. Это часть Мементо паттерна (я думаю), с той разницей, что объектом является само состояние.
Более того, если я сохраню клон исходного узла (до его перемещения), я смогу вернуться к его старой версии. Тот же метод применяется к информации, содержащейся в узле (имя класса или интерфейса, текст для узла заметки, имя атрибута и т. Д.).
Дело в том, как заменить на схеме узел с его клоном при операции отмены / возврата? Если я клонирую исходный объект, на который ссылается диаграмма (находящийся в списке узлов), клон не является ссылкой на диаграмме, и единственное, на что он указывает, это сама команда! Должны ли я включить в диаграмму механизмы для нахождения узла по идентификатору (например), чтобы я мог заменить на диаграмме узел его клоном (и наоборот)? Это до шаблонов Memento и Command, чтобы сделать это? А как насчет ссылок? Они также должны быть подвижными, но я не хочу создавать команду только для ссылок (и одну только для узлов), и я должен иметь возможность изменять правильный список (узлы или ссылки) в соответствии с типом объекта команды имеет в виду.
Как бы вы поступили? Короче говоря, у меня возникают проблемы с представлением состояния объекта в шаблоне команда / памятка, чтобы его можно было эффективно восстановить и восстановить исходный объект в списке диаграмм, в зависимости от типа объекта (узла или ссылки).
Большое спасибо!
Гийом.
П.С .: Если мне неясно, скажите мне, и я уточню свое сообщение (как всегда!).
Редактировать
Вот мое реальное решение, которое я начал реализовывать до публикации этого вопроса.
Во-первых, у меня есть класс AbstractCommand, определенный следующим образом:
public abstract class AbstractCommand {
public boolean blnComplete;
public void setComplete(boolean complete) {
this.blnComplete = complete;
}
public boolean isComplete() {
return this.blnComplete;
}
public abstract void execute();
public abstract void unexecute();
}
Затем каждый тип команды реализуется с использованием конкретного вывода AbstractCommand.
Итак, у меня есть команда для перемещения объекта:
public class MoveCommand extends AbstractCommand {
Moveable movingObject;
Point2D startPos;
Point2D endPos;
public MoveCommand(Point2D start) {
this.startPos = start;
}
public void execute() {
if(this.movingObject != null && this.endPos != null)
this.movingObject.moveTo(this.endPos);
}
public void unexecute() {
if(this.movingObject != null && this.startPos != null)
this.movingObject.moveTo(this.startPos);
}
public void setStart(Point2D start) {
this.startPos = start;
}
public void setEnd(Point2D end) {
this.endPos = end;
}
}
У меня также есть MoveRemoveCommand (для ... перемещения или удаления объекта / узла). Если я использую идентификатор метода instanceof, мне не нужно передавать диаграмму фактическому узлу или ссылке, чтобы она могла удалить себя из диаграммы (я думаю, что это плохая идея).
Абстрактная диаграмма диаграммы;
Добавляемый объект;
Тип AddRemoveType;
@SuppressWarnings("unused")
private AddRemoveCommand() {}
public AddRemoveCommand(AbstractDiagram diagram, Addable obj, AddRemoveType type) {
this.diagram = diagram;
this.obj = obj;
this.type = type;
}
public void execute() {
if(obj != null && diagram != null) {
switch(type) {
case ADD:
this.obj.addToDiagram(diagram);
break;
case REMOVE:
this.obj.removeFromDiagram(diagram);
break;
}
}
}
public void unexecute() {
if(obj != null && diagram != null) {
switch(type) {
case ADD:
this.obj.removeFromDiagram(diagram);
break;
case REMOVE:
this.obj.addToDiagram(diagram);
break;
}
}
}
Наконец, у меня есть ModificationCommand, который используется для изменения информации об узле или ссылке (имя класса и т. Д.). Это может быть объединено в будущем с MoveCommand. Этот класс пока пуст. Я, вероятно, сделаю идентификацию с механизмом, чтобы определить, является ли измененный объект узлом или ребром (через instanceof или специальное определение в идентификаторе).
Это хорошее решение?