Java | コピーを使った Undo 機能

Java Java
スポンサーリンク

では「オブジェクト配列での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」の完全版が完成です。

Java
スポンサーリンク
シェアする
@lifehackerをフォローする
スポンサーリンク
タイトルとURLをコピーしました