C#デザインパターン - Command
ここに掲載したコードは、『増補改訂版Java言語で学ぶデザインパターン入門 /
結城 浩(著)』に掲載されているサンプルコードをC#に移植したものです。
解説らしい解説は載せていませんので、『増補改訂版Java言語で学ぶデザインパターン入門
/ 結城 浩(著)』も合わせてお読みください。
※当ソースは、Visual C# 2008 Express Editionで動作を確認しています。
Visual Studio 2005をお使いの方は、ブログの記事を残しておきますので、そちらをご覧ください。
■ICommand.cs
using System;
namespace Gushwell.DesignPatterns.Command {
public interface ICommand {
void Execute();
}
}
■MacroCommand.cs
using System;
using System.Collections.Generic;
using Gushwell.Dejavu;
namespace Gushwell.DesignPatterns.Command {
// 具体的なCommandには依存しない。
public class MacroCommand : ICommand {
// 命令の集合
private Stack<ICommand> commands = new Stack<ICommand>();
// 実行
public virtual void Execute() {
commands.ForEach(cmd => cmd.Execute());
}
// 追加
public virtual void Append(ICommand cmd) {
if (cmd != this) {
commands.Push(cmd);
}
}
// 最後の命令を削除
public virtual void Undo() {
if (!(commands.Count == 0)) {
commands.Pop();
}
}
// 全部削除
public virtual void Clear() {
commands.Clear();
}
}
}
■IDrawable.cs
using System;
namespace Gushwell.DesignPatterns.Drawer {
public interface IDrawable {
void Draw(int x, int y);
}
}
■DrawCommand.cs
using System;
using System.Drawing;
using Gushwell.DesignPatterns.Command;
namespace Gushwell.DesignPatterns.Drawer {
// Commandの具象クラス
public class DrawCommand : ICommand {
// 描画対象
protected internal IDrawable drawable;
// 描画位置
private System.Drawing.Point position;
// コンストラクタ
public DrawCommand(IDrawable drawable, Point position) {
this.drawable = drawable;
this.position = position;
}
// 実行
public virtual void Execute() {
drawable.Draw(position.X, position.Y);
}
}
}
■DrawCanvas.cs
using System.Drawing;
using System.Windows.Forms;
using Gushwell.DesignPatterns.Command;
namespace Gushwell.DesignPatterns.Drawer {
// UserControlを継承すると共にう、IDrawableインターフェースを実装する。
public partial class DrawCanvas : UserControl, IDrawable {
public DrawCanvas() {
InitializeComponent();
}
// 描画色
private Color color = Color.Red;
// 描画する点の半径
private int radius = 6;
// 履歴
private MacroCommand history = null;
public void Draw(int x, int y) {
using ( Graphics g = CreateGraphics() )
using ( Brush brush = new SolidBrush(color) ) {
g.FillEllipse(brush, x - radius, y - radius, radius * 2, radius * 2);
}
}
// 本当はコンストラクタで行ないたい。
// 初期化用メソッド
public void SetHistory(MacroCommand history) {
this.history = history;
}
// これが無いと、最小化から戻したときなどに、再描画されない。
private void DrawCanvas_Paint(object sender, PaintEventArgs e) {
if (history != null)
history.Execute();
}
}
}
■MainForm.cs
using System;
using System.Windows.Forms;
using Gushwell.DesignPatterns.Command;
using Gushwell.DesignPatterns.Drawer;
namespace Gushwell.DesignPatterns {
public partial class MainForm : Form {
public MainForm() {
InitializeComponent();
drawCanvas1.SetHistory(history);
}
private MacroCommand history = new MacroCommand();
private bool drag = false;
private void drawCanvas1_MouseDown(object sender, MouseEventArgs e) {
drag = true;
}
private void drawCanvas1_MouseMove(object sender, MouseEventArgs e) {
if (drag) {
ICommand cmd = new DrawCommand(drawCanvas1, e.Location);
history.Append(cmd);
cmd.Execute();
}
}
private void drawCanvas1_MouseUp(object sender, MouseEventArgs e) {
drag = false;
}
private void clearButton_Click(object sender, EventArgs e) {
history.Clear();
drawCanvas1.Invalidate();
}
}
}
Program .cs
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace Gushwell.DesignPatterns {
static class Program {
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
EnumerableExtentions .cs
using System;
using System.Collections.Generic;
namespace Gushwell.Dejavu {
public static class EnumerableExtentions {
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
foreach (var x in source) {
action(x);
}
}
public static void ForEach<T>(this IEnumerable<T> source, Action<T, int> func) {
int i = 0;
foreach (var x in source) {
func(x, i);
i++;
}
}
}
}