伝説のアーキテクトが教える:Windows Formsで「Undo/Redo」を極めるCommandパターンの真髄
こんにちは。VB.NETの世界へようこそ。
マクロの記録で「動いた!」と喜んでいたあの頃から、一歩先へ進みたいあなたへ。今日は、プロフェッショナルなアプリケーションの証とも言える「Undo(元に戻す)/ Redo(やり直し)」機能の実装術を伝授します。
多くの初心者は、Undoのために「すべての状態を巨大な配列に保存する」といった愚策に陥ります。しかし、メモリを食いつぶし、バグの温床になるだけです。真の解決策は「Commandパターン」にあります。
—
1. なぜ「Commandパターン」なのか?
Commandパターンとは、「操作そのものをオブジェクト(部品)として扱う」設計思想です。
例えば、「テキストボックスの文字を変えた」という操作を、単なるデータではなく、「実行(Execute)」と「逆実行(UnExecute)」というメソッドを持つ「命令書」としてパッケージ化するのです。
これにより、履歴管理は「命令書をスタック(積み重ね)という箱に入れるだけ」というシンプルな仕組みに変わります。
—
2. 「命令書」の設計図を作る(Interface)
まずは、すべての操作が守るべき「ルール」をインターフェースとして定義します。VB.NETで最も重要な設計の第一歩です。
‘ すべての操作(Undo/Redo対象)が実装すべき契約
Public Interface ICommand
Sub Execute() ‘ 操作を実行する
Sub UnExecute() ‘ 操作を逆回転させる
End Interface
—
3. 具体的な「命令」を実装する
例えば、「テキストボックスの値を変更する」という操作をクラス化してみましょう。
Public Class ChangeTextCommand
Implements ICommand
Private _target As TextBox
Private _oldValue As String
Private _newValue As String
Public Sub New(target As TextBox, newValue As String)
_target = target
_oldValue = target.Text
_newValue = newValue
End Sub
Public Sub Execute() Implements ICommand.Execute
_target.Text = _newValue
End Sub
Public Sub UnExecute() Implements ICommand.UnExecute
_target.Text = _oldValue
End Sub
End Class
—
4. 履歴を管理する「司令塔(CommandManager)」
履歴を保存する箱(Stack)を用意します。ここが脳の役割を果たします。
Public Class CommandManager
‘ 操作履歴をスタックで管理(後入れ先出し)
Private _undoStack As New Stack(Of ICommand)
Private _redoStack As New Stack(Of ICommand)
‘ 操作を実行して履歴に残す
Public Sub ExecuteCommand(cmd As ICommand)
cmd.Execute()
_undoStack.Push(cmd)
_redoStack.Clear() ‘ 新しい操作をしたらやり直し履歴は消すのがルール
End Sub
‘ Undo機能
Public Sub Undo()
If _undoStack.Count > 0 Then
Dim cmd = _undoStack.Pop()
cmd.UnExecute()
_redoStack.Push(cmd)
End If
End Sub
End Class
—
5. 実装で陥りやすい「罠」と解決策
初心者がこの実装でよくつまづくポイントを、現場の視点から教えます。
- イベントの無限ループに注意!
`TextBox.TextChanged` イベントで `ExecuteCommand` を呼ぶと、Undo操作でテキストを書き換えた際にもイベントが発火し、無限ループに陥ります。
解決策: 操作中はフラグを立ててイベントを一時的に無効化する `Private isUndoing As Boolean = False` のようなガードを必ず入れてください。
- メモリの肥大化
巨大なデータをUndo対象にするとメモリが枯渇します。オブジェクト全体を保持せず、「変更差分」だけを保持するように設計を絞りましょう。
—
6. まとめ:ここを越えれば、あなたはもう初心者ではない
このCommandパターンを習得すると、単なる入力フォームが、まるでプロ仕様のグラフィックソフトのような「洗練された挙動」を持つようになります。
今日のステップ:
1. `ICommand` インターフェースを書く。
2. 小さな操作(テキスト変更など)をクラスにする。
3. `Stack`を使って履歴を管理してみる。
最初は難しく感じるかもしれません。しかし、これこそがオブジェクト指向の醍醐味です。「状態」を管理するのではなく、「操作」を管理する。この発想の転換ができたとき、あなたのVB.NETスキルは一段上の領域へと進化します。
何か分からないことがあれば、いつでも聞いてください。焦らず、一歩ずつ。あなたのコードが、より美しくなることを応援しています。
