【Winform】中級:コマンドパターンを使用したサンプル

C#のコマンドパターンを使用して、WinFormアプリケーションで「前進」「後退」「左移動」「右移動」の操作を管理する方法を解説します。

コマンドパターンの概要

コマンドパターンは、操作をオブジェクトとしてカプセル化し、その操作を実行するタイミングや手段を柔軟に変更できるようにします。これにより、操作の管理やログの記録、取り消し機能の実装が容易になります。

実装手順

1. コマンドインターフェースの定義

すべてのコマンドが実装するインターフェースを定義します。

public interface ICommand
{
    void Execute();
}

2. コマンドクラスの作成

具体的なコマンドクラスを作成します。例えば、前進や後退のコマンドです。

public class MoveForwardCommand : ICommand
{
    private readonly Player player;

    public MoveForwardCommand(Player player)
    {
        this.player = player;
    }

    public void Execute()
    {
        player.MoveForward();
    }
}
public class MoveBackwardCommand : ICommand
{
    private readonly Player player;

    public MoveBackwardCommand(Player player)
    {
        this.player = player;
    }

    public void Execute()
    {
        player.MoveBackward();
    }
}
public class MoveLeftCommand : ICommand
{
    private readonly Player player;

    public MoveLeftCommand(Player player)
    {
        this.player = player;
    }

    public void Execute()
    {
        player.MoveLeft();
    }
}
public class MoveRightCommand : ICommand
{
    private readonly Player player;

    public MoveRightCommand(Player player)
    {
        this.player = player;
    }

    public void Execute()
    {
        player.MoveRight();
    }
}

3. プレイヤークラスの作成

プレイヤーが実際に動作を行うクラスです。

public class Player
{
    public void MoveForward()
    {
        MessageBox.Show("前進しました");
    }

    public void MoveBackward()
    {
        MessageBox.Show("後退しました");
    }

    public void MoveLeft()
    {
        MessageBox.Show("左に移動しました");
    }

    public void MoveRight()
    {
        MessageBox.Show("右に移動しました");
    }
}

4. コントローラークラスの作成

コマンドを実行するクラスを作成します。ユーザーの操作に応じて、適切なコマンドを実行します。

public class GameController
{
    private ICommand moveForwardCommand;
    private ICommand moveBackwardCommand;
    private ICommand moveLeftCommand;
    private ICommand moveRightCommand;

    public GameController(Player player)
    {
        moveForwardCommand = new MoveForwardCommand(player);
        moveBackwardCommand = new MoveBackwardCommand(player);
        moveLeftCommand = new MoveLeftCommand(player);
        moveRightCommand = new MoveRightCommand(player);
    }

    public void MoveForward()
    {
        moveForwardCommand.Execute();
    }

    public void MoveBackward()
    {
        moveBackwardCommand.Execute();
    }

    public void MoveLeft()
    {
        moveLeftCommand.Execute();
    }

    public void MoveRight()
    {
        moveRightCommand.Execute();
    }
}

5. WinFormでの実装

WinFormのボタンをクリックした際に、対応するコマンドが実行されるように設定します。

public partial class MainForm : Form
{
    private GameController gameController;

    public MainForm()
    {
        InitializeComponent();
        Player player = new Player();
        gameController = new GameController(player);
    }

    private void buttonMoveForward_Click(object sender, EventArgs e)
    {
        gameController.MoveForward();
    }

    private void buttonMoveBackward_Click(object sender, EventArgs e)
    {
        gameController.MoveBackward();
    }

    private void buttonMoveLeft_Click(object sender, EventArgs e)
    {
        gameController.MoveLeft();
    }

    private void buttonMoveRight_Click(object sender, EventArgs e)
    {
        gameController.MoveRight();
    }
}

このサンプルでは、コマンドパターンを使ってゲーム内のキャラクターの移動操作を管理し、WinFormアプリケーションのボタンに連動させる方法を示しました。

UML図

クラス図

クラス図は、クラス間の関係を視覚化するための図です。ここでは、ICommandインターフェースとその具体的なコマンドクラス、およびPlayerクラスを示します。

シーケンス図

シーケンス図は、オブジェクト間の相互作用を時間の流れに沿って示します。ここでは、Buttonがコマンドを実行する過程を示します。

コンポーネント図

コンポーネント図は、システム内のコンポーネントとその相互関係を示します。ここでは、コマンドパターンの各コンポーネントとその依存関係を示します。

オブジェクト図

この図では、Playerオブジェクトとそれに関連する具体的なコマンドオブジェクト(MoveForwardCommandなど)を示しています。

このオブジェクト図では、各コマンドオブジェクトが Player オブジェクトを参照している様子を示しています。各コマンドオブジェクトが Player のメソッドを呼び出すことで、キャラクターの操作が実行されることを視覚化しています。

状態図

状態図は、コマンドの実行状態の遷移を示します。

アクティビティ図

アクティビティ図は、コマンドの実行プロセスを視覚化します。

コマンドパターンを使用した操作の取り消し機能の実装

この資料では、C#でコマンドパターンを使用して、操作の取り消し機能(Undo)を実装する方法を解説します。コマンドパターンを用いることで、操作の管理、ログの記録、そして取り消し操作を簡単に行うことができます。

コマンドパターンの基礎

コマンドパターンは、操作(コマンド)をオブジェクトとしてカプセル化し、その操作を実行するタイミングや方法を柔軟に変更できるようにするデザインパターンです。各操作は独立したクラスとして定義され、操作対象(例えば、ゲーム内のプレイヤー)に対して特定のアクションを実行します。

取り消し機能の実装手順

1. コマンドインターフェースの定義

まず、すべてのコマンドが実装するインターフェースを定義します。このインターフェースには、操作を実行する Execute メソッドと、操作を取り消す Unexecute メソッドを含めます。

public interface ICommand
{
    void Execute();
    void Unexecute();  // 取り消し操作
}

2. コマンドクラスの作成

次に、具体的なコマンドクラスを作成します。ここでは、プレイヤーが前進する操作と、その操作を取り消すための後退操作を実装します。

public class MoveForwardCommand : ICommand
{
    private readonly Player player;

    public MoveForwardCommand(Player player)
    {
        this.player = player;
    }

    public void Execute()
    {
        player.MoveForward();
    }

    public void Unexecute()
    {
        player.MoveBackward();  // 前進を取り消して後退させる
    }
}

// 後退、左移動、右移動のコマンドも同様に作成できます。

3. プレイヤークラスの作成

プレイヤーが実際に動作を行うクラスを作成します。このクラスは、前進や後退といった操作を実行します。

public class Player
{
    public void MoveForward()
    {
        MessageBox.Show("前進しました");
    }

    public void MoveBackward()
    {
        MessageBox.Show("後退しました");
    }

    public void MoveLeft()
    {
        MessageBox.Show("左に移動しました");
    }

    public void MoveRight()
    {
        MessageBox.Show("右に移動しました");
    }
}

4. コントローラークラスの作成

コントローラークラスでは、コマンドの実行と取り消しを管理します。実行されたコマンドはスタックに保存され、取り消し要求があった際にスタックからコマンドを取り出し、Unexecute メソッドを呼び出します。

public class GameController
{
    private Stack<ICommand> commandHistory = new Stack<ICommand>();

    public void ExecuteCommand(ICommand command)
    {
        command.Execute();
        commandHistory.Push(command);
    }

    public void Undo()
    {
        if (commandHistory.Count > 0)
        {
            ICommand command = commandHistory.Pop();
            command.Unexecute();
        }
    }
}

5. WinFormでの実装

WinFormのボタンをクリックした際に、対応するコマンドが実行され、取り消しボタンがクリックされると最後に実行された操作が取り消されます。

public partial class MainForm : Form
{
    private GameController gameController;
    private Player player;

    public MainForm()
    {
        InitializeComponent();
        player = new Player();
        gameController = new GameController();
    }

    private void buttonMoveForward_Click(object sender, EventArgs e)
    {
        MoveForwardCommand command = new MoveForwardCommand(player);
        gameController.ExecuteCommand(command);
    }

    private void buttonUndo_Click(object sender, EventArgs e)
    {
        gameController.Undo();
    }

    // 他のボタンに対しても同様にコマンドを設定します
}

まとめ

コマンドパターンを使用することで、操作をオブジェクトとして管理し、ログの記録や取り消し機能を実装することが容易になります。この資料では、プレイヤーの移動操作に対する取り消し機能の実装方法を示しました。スタックを用いたコマンド履歴の管理により、操作を遡って取り消すことができ、より柔軟で拡張性の高いシステム設計が可能になります。