Шаблон дизайна Memento на Java
Я реализую Java-приложение, которое генерирует SVG-код из простых команд, таких как "add_circle 12 20 5". Есть четыре формы, такие как Rectangle, Circle, ... и каждый их класс реализует интерфейс с именем Component. Общие функции: translate(dx,dy)
, flip_vertical(axis)
, flip_horizontal(axis)
а также write(output)
,
Существует класс под названием Group, который также реализует интерфейс компонента. Его единственное поле является ArrayList<Component> groupOfComponents
который используется для хранения компонентов в нем. Если вы вызываете функцию преобразования этого класса, она вызывает функцию преобразования каждого компонента в массиве.
Есть и другие части приложения, которые генерируют svg, но пока это не имеет значения. Короче говоря, я хочу сделать механизм отмены. Чтобы сделать это, не разрушая инкапсуляцию, мне нужно использовать шаблон проектирования Memento.
сувенир
Я написал новый класс для этого (класс памяти) под названием GroupState. Это класс для хранения предыдущих состояний, чтобы его можно было восстановить позже. Поскольку единственная информация, которую мне нужно сохранить из объекта Group, это его массив, он хранит ArrayList.
public class GroupState {
private final ArrayList<Component> state;
public GroupState(ArrayList<Component> state) {
this.state = state;
}
public ArrayList<Component> getState() {
return state;
}
}
автор
Оригинатором является класс Group, мне пришлось добавить 2 новых метода: save
а также restore
, Эти методы предназначены для сохранения состояния Goup и его восстановления.
public class Group implements Component{
public GroupState save(){
return new GroupState(groupOfComponents);
}
public void restore(GroupState state) {
groupOfComponents = state.getState();
}
private ArrayList<Component> groupOfComponents = new ArrayList<>();
/** .
.
other parts of the class
.
*/
}
смотритель
Смотритель управляет всем процессом отмены. Это часть моего класса, которая не имеет значения, поэтому я собираюсь написать некоторый код, чтобы показать, как я хочу использовать весь механизм отмены.
Group group = new Group();
Circle circle = new Circle(1,2,3);
group.addComponent(circle);
Stack<GroupState> savedStates = new Stack<>();
savedStates.push(group.save());
group.flipHorizontal(100);
group.restore(savedStates.pop());
Я ожидаю, что произойдет следующее:
- Создать пустую группу
- Создать круг с некоторыми параметрами
- Добавьте круг в группу (добавьте круг в массив groupOfComponents класса группы)
- Создать стек для хранения состояний
- Сохранить состояние группового объекта в стек
- Внести изменения в объект группы (например, перевернуть)
- Отменить последнее изменение (восстановить из стека состояний)
проблема
Вместо предсказанного поведения на последнем шаге происходит следующее:
- Ничего такого
Я начал отлаживать все это и заметил, что когда я изменяю объект группы с помощью этого метода переворота, поле объекта GroupState state
также меняется. Я не знаю почему. Прежде всего, state
поле является окончательным. Во-вторых, я знаю, что в ссылочных типах ссылка передается, но как насчет неизменности, почему шаг 6 также меняет поле GtoupState? Как заставить GroupState скопировать данные из переданного массива? Спасибо за вашу помощь.