Commandパターン

Command パターン - Wikipedia

どの種類の操作も"操作"とひとくくりにする -> Commandインターフェイス
操作毎に実装クラスを作成する。このクラスに実際の処理を行うクラスを内包する。

下記ソースは
Commandインターフェイスとして「ICommand」
実装コマンドクラスとして「DrawCommand」
そこに内包されている実処理クラスとして「Canvas」
それらを生成・実行・管理するフォームで構成されている。

また、フォームではコマンドを実行順にListへ保存している。
その為、コマンドのUndo処理を行うことができるようになっている。

    /// <summary>
    /// コマンドインターフェイス
    /// </summary>
    public interface ICommand
    {
        /// <summary>
        /// コマンドの実行
        /// </summary>
        void execute();
    }

    /// <summary>
    /// 描画コマンド
    /// </summary>
    public class DrawCommand : ICommand
    {
        private IDrawtable drawer = null; //描画オブジェクト

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="drawer"></param>
        public DrawCommand(IDrawtable drawer)
        {
            this.drawer = drawer;
        }

        /// <summary>
        /// コマンドの実行
        /// </summary>
        public void execute()
        {
            drawer.draw();
        }
    }
    
    /// <summary>
    /// 描画インターフェイス
    /// </summary>
    public interface IDrawtable
    {
        /// <summary>
        /// 描画
        /// </summary>
        void draw();
    }


    /// <summary>
    /// 描画クラス
    /// </summary>
    public class Canvas : IDrawtable
    {
        private Graphics graphics;  //描画先
        private Point pt; //描画座標
        private SolidBrush brush = new SolidBrush(Color.Black);
        private Font font = new Font("MS ゴシック", 9f);
        private String mark = "●";

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="g"></param>
        /// <param name="pt"></param>
        public Canvas(Graphics g, Point pt)
        {
            this.graphics = g;
            this.pt = pt;
        }

        /// <summary>
        /// 描画
        /// </summary>
        public void draw()
        {
            graphics.DrawString(mark, font, brush, (PointF)pt);
        }
    }
    
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private Graphics graphics;  //描画オブジェクト
        private List<ICommand> cmd_history = new List<ICommand>(); //コマンド履歴 末尾要素が最新実行コマンド
        private bool is_mouse_down = false; //マウス押下フラグ
        private int cur_cmd_idx = -1; //現在のコマンドインデックス

        private void Form1_Load(object sender, EventArgs e)
        {
            graphics = panel1.CreateGraphics();
        }

        //「処理履歴 戻る」クリック
        private void button1_Click(object sender, EventArgs e)
        {
            //パネルをクリアし、現在コマンド一つ前までのコマンドを再実行する。
            graphics.Clear(Color.White);

            cur_cmd_idx = Math.Max(0, cur_cmd_idx - 1);
            for (int i = 0; i < cur_cmd_idx; i++)
            {
                cmd_history[i].execute();
            }
        }

        //「処理履歴 進む」クリック
        private void button2_Click(object sender, EventArgs e)
        {
            //現在コマンドを1つ進めて、そのコマンドを再実行する

            cur_cmd_idx = Math.Min(cmd_history.Count - 1, cur_cmd_idx + 1);
            cmd_history[cur_cmd_idx].execute();
        }

        private void panel1_MouseDown(object sender, MouseEventArgs e)
        {
            //パネル上でマウスON -> 描画フラグOn
            is_mouse_down = true;
        }

        private void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            //パネル上でマウス移動 -> 描画フラグOnなら、現在の座標を取得。描画コマンド作成し、実行
            if (is_mouse_down == true)
            {
                Canvas canvas = new Canvas(graphics, e.Location);
                DrawCommand cmd = new DrawCommand(canvas);
                cmd_history.Add(cmd);
                cur_cmd_idx += 1;
                canvas.draw();
            }
        }

        private void panel1_MouseUp(object sender, MouseEventArgs e)
        {
            //パネル上でマウスUp -> 描画フラグOff
            is_mouse_down = false;
        }

        //「クリア」クリック
        private void button3_Click(object sender, EventArgs e)
        {
            cur_cmd_idx = -1;
            cmd_history.Clear();
            graphics.Clear(Color.White);
        }
    }