我正在实现一个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设计模式。
我已经为它(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());
我期望发生的事情如下:
而不是预测的行为,在最后一步是这里发生的事情:
我开始调试整个事情,并注意到,当我使用该翻转方法更改组对象时,GroupState对象的字段state
也会发生变化。我不知道为什么。首先,state
字段是最终的。其次,我知道在引用类型中,引用已经通过但是不变性,为什么第6步也改变了GtoupState的字段呢?如何使GroupState从传递的数组中复制数据?谢谢你的帮助。