では「オブジェクト配列でのUndo/Redo」の例を紹介します。ここでは オブジェクト配列を深いコピーして履歴管理し、Undo/Redoを実現する 仕組みを作ります。
シナリオ
Studentクラスを用意(名前と点数を持つ)。Student[]配列を「状態」として扱う。- 状態を変更するたびに 深いコピー を履歴に保存。
- Undoで1つ前の状態に戻り、Redoでやり直しができる。
コード例:オブジェクト配列のUndo/Redo
import java.util.*;
class Student {
String name;
int score;
Student(String name, int score) {
this.name = name;
this.score = score;
}
// 深いコピー用のコンストラクタ
Student(Student other) {
this.name = other.name;
this.score = other.score;
}
@Override
public String toString() {
return name + "(" + score + ")";
}
}
public class UndoRedoObjects {
public static void main(String[] args) {
Student[] state = {
new Student("Alice", 90),
new Student("Bob", 80)
};
List<Student[]> undoStack = new ArrayList<>();
List<Student[]> redoStack = new ArrayList<>();
// 初期状態を保存
undoStack.add(deepCopy(state));
// ---- 状態変更 ----
state[0].score = 95; // Aliceの点数変更
undoStack.add(deepCopy(state));
state[1].score = 70; // Bobの点数変更
undoStack.add(deepCopy(state));
System.out.println("現在の状態: " + Arrays.toString(state));
// [Alice(95), Bob(70)]
// ---- Undo ----
state = undo(state, undoStack, redoStack);
System.out.println("Undo後: " + Arrays.toString(state));
// [Alice(95), Bob(80)]
state = undo(state, undoStack, redoStack);
System.out.println("さらにUndo後: " + Arrays.toString(state));
// [Alice(90), Bob(80)]
// ---- Redo ----
state = redo(state, undoStack, redoStack);
System.out.println("Redo後: " + Arrays.toString(state));
// [Alice(95), Bob(80)]
state = redo(state, undoStack, redoStack);
System.out.println("さらにRedo後: " + Arrays.toString(state));
// [Alice(95), Bob(70)]
}
// 深いコピー(Student配列)
private static Student[] deepCopy(Student[] src) {
Student[] copy = new Student[src.length];
for (int i = 0; i < src.length; i++) {
copy[i] = new Student(src[i]); // 新しいStudentを作成
}
return copy;
}
// Undo処理
private static Student[] undo(Student[] state, List<Student[]> undoStack, List<Student[]> redoStack) {
if (undoStack.size() > 1) {
redoStack.add(deepCopy(state));
undoStack.remove(undoStack.size() - 1);
return deepCopy(undoStack.get(undoStack.size() - 1));
}
return state;
}
// Redo処理
private static Student[] redo(Student[] state, List<Student[]> undoStack, List<Student[]> redoStack) {
if (!redoStack.isEmpty()) {
Student[] redoState = redoStack.remove(redoStack.size() - 1);
undoStack.add(deepCopy(redoState));
return redoState;
}
return state;
}
}
Java解説
- 深いコピー:
Student(Student other)コンストラクタで新しいオブジェクトを作成。 - Undo: 最新状態を
redoStackに保存 →undoStackの1つ前を復元。 - Redo:
redoStackから取り出して復元 →undoStackに戻す。 - 結果: オブジェクト配列でも「完全に独立した履歴」が作れる。
応用ポイント
- 複雑なオブジェクト:
Studentがさらに配列や他のオブジェクトを持つ場合も、同様に深いコピーを実装すればUndo/Redo可能。 - ゲームやシミュレーション: キャラクターや盤面の状態を履歴管理して「戻す」「やり直す」ができる。
- テキストエディタ風: 文字列やドキュメントの状態をコピーしてUndo/Redoを実現できる。
✅ これで「オブジェクト配列のUndo/Redo」の完全版が完成です。
