2006年03月29日

State ― 状態をクラスとして表現する

  
ここに掲載したコードは、『増補改訂版Java言語で学ぶデザインパターン入門 / 結城 浩(著)』に掲載されているサンプルコードをC#に移植したものです。移植後のコードの公開に関しては、結城氏の了解を得ています。
※当ソースは、Visual C# 2005 Express Editionで動作を確認しています。



IContextインターフェース
using System;

namespace Gushwell.DesignPatterns {
public interface IContext {
void SetClock(int hour); // 時刻の設定
void ChangeState(State state); // 状態変化
void CallSecurityCenter(string msg); // 警備センター警備員呼び出し
void RecordLog(string msg); // 警備センター記録
}
}


Stateインターフェース
using System;

namespace Gushwell.DesignPatterns {
public interface State {
void DoClock(IContext context, int hour); // 時刻設定
void DoUse(IContext context); // 金庫使用
void DoAlarm(IContext context); // 非常ベル
void DoPhone(IContext context); // 通常通話
}
}


DayStateクラス
using System;

namespace Gushwell.DesignPatterns {
public sealed class DayState : State {
// 唯一のインスタンスを得る
public static State Instance {
get { return singleton; }
}
private static readonly DayState singleton = new DayState();

// コンストラクタはprivate
private DayState() {
}

// 時刻設定
public void DoClock(IContext context, int hour) {
if (hour < 9 || 17 <= hour) {
context.ChangeState(NightState.Instance);
}
}

// 金庫使用
public void DoUse(IContext context) {
context.RecordLog("金庫使用(昼間)");
}

// 非常ベル
public void DoAlarm(IContext context) {
context.CallSecurityCenter("非常ベル(昼間)");
}

// 通常通話
public void DoPhone(IContext context) {
context.CallSecurityCenter("通常の通話(昼間)");
}

// 文字列表現
public override string ToString() {
return "[昼間]";
}
}
}


NightStateクラス
using System;

namespace Gushwell.DesignPatterns {
public sealed class NightState : State {
// 唯一のインスタンスを得る
public static State Instance {
get { return singleton; }
}
private static readonly NightState singleton = new NightState();

// コンストラクタはprivate
private NightState() {
}

// 時刻設定
public void DoClock(IContext context, int hour) {
if (9 <= hour && hour < 17) {
context.ChangeState(DayState.Instance);
}
}

// 金庫使用
public void DoUse(IContext context) {
context.CallSecurityCenter("非常:夜間の金庫使用!");
}

// 非常ベル
public void DoAlarm(IContext context) {
context.CallSecurityCenter("非常ベル(夜間)");
}

// 通常通話
public void DoPhone(IContext context) {
context.RecordLog("夜間の通話録音");
}

// 文字列表現
public override string ToString() {
return "[夜間]";
}
}
}


SafeFormクラス
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Gushwell.DesignPatterns {
public partial class SafeForm : Form, IContext {
private State state = DayState.Instance;
public SafeForm() {
InitializeComponent();
}

private void ActionPerformed(object sender, EventArgs e) {
Console.WriteLine(e.ToString());
if (sender == buttonUse) {
// 金庫使用ボタン
state.DoUse(this);
} else if (sender == buttonAlarm) {
// 非常ベルボタン
state.DoAlarm(this);
} else if (sender == buttonPhone) {
// 通常通話ボタン
state.DoPhone(this);
} else if (sender == buttonExit) {
// 終了ボタン
System.Environment.Exit(0);
} else {
Console.WriteLine("?");
}
}

// 時刻の設定
virtual public void SetClock(int hour) {
string clockstring = "現在時刻は";
if (hour < 10) {
clockstring += ("0" + hour + ":00");
} else {
clockstring += (hour + ":00");
}
Console.WriteLine(clockstring);
textClock.Text = clockstring;
state.DoClock(this, hour);
}

public virtual void ChangeState(State state) {
Console.WriteLine(this.state + "から" + state
+ "へ状態が変化しました。");
this.state = state;
}

// 警備センター警備員呼び出し
public virtual void CallSecurityCenter(string msg) {
textScreen.AppendText("call! " + msg + "\n");
}

// 警備センター記録
public virtual void RecordLog(string msg) {
textScreen.AppendText("record ... " + msg + "\n");
}

private void Form1_Load(object sender, EventArgs e) {
timerClock.Interval = 1000;
timerClock.Enabled = true;
}

private int hour = 0;
private void timer1_Tick(object sender, EventArgs e) {
SetClock(hour++);
if (hour >= 24)
hour = 0;
}

}
}


Programクラス
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 SafeForm());
}
}
}


SafeFormクラス (IDEが作成したソース : SafeForm.Designer.cs)
namespace Gushwell.DesignPatterns {
partial class SafeForm {
private System.ComponentModel.IContainer components = null;

protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}

#region Windows フォーム デザイナで生成されたコード

private void InitializeComponent() {
this.components = new System.ComponentModel.Container();
this.textScreen = new System.Windows.Forms.TextBox();
this.textClock = new System.Windows.Forms.TextBox();
this.buttonUse = new System.Windows.Forms.Button();
this.buttonAlarm = new System.Windows.Forms.Button();
this.buttonPhone = new System.Windows.Forms.Button();
this.buttonExit = new System.Windows.Forms.Button();
this.timerClock = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
//
// textScreen
//
this.textScreen.Anchor = ((System.Windows.Forms.AnchorStyles)
((((System.Windows.Forms.AnchorStyles.Top
| System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.textScreen.Location = new System.Drawing.Point(0, 28);
this.textScreen.Multiline = true;
this.textScreen.Name = "textScreen";
this.textScreen.ReadOnly = true;
this.textScreen.Size = new System.Drawing.Size(348, 175);
this.textScreen.TabIndex = 0;
//
// textClock
//
this.textClock.Anchor = ((System.Windows.Forms.AnchorStyles)
(((System.Windows.Forms.AnchorStyles.Top
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.textClock.Location = new System.Drawing.Point(0, 3);
this.textClock.Name = "textClock";
this.textClock.ReadOnly = true;
this.textClock.Size = new System.Drawing.Size(348, 19);
this.textClock.TabIndex = 1;
//
// buttonUse
//
this.buttonUse.Anchor = ((System.Windows.Forms.AnchorStyles)
((System.Windows.Forms.AnchorStyles.Bottom
| System.Windows.Forms.AnchorStyles.Left)));
this.buttonUse.Location = new System.Drawing.Point(6, 215);
this.buttonUse.Name = "buttonUse";
this.buttonUse.Size = new System.Drawing.Size(75, 23);
this.buttonUse.TabIndex = 2;
this.buttonUse.Text = "金庫使用";
this.buttonUse.UseVisualStyleBackColor = true;
this.buttonUse.Click += new System.EventHandler(this.ActionPerformed);
//
// buttonAlarm
//
this.buttonAlarm.Anchor = ((System.Windows.Forms.AnchorStyles)
((System.Windows.Forms.AnchorStyles.Bottom
| System.Windows.Forms.AnchorStyles.Left)));
this.buttonAlarm.Location = new System.Drawing.Point(91, 215);
this.buttonAlarm.Name = "buttonAlarm";
this.buttonAlarm.Size = new System.Drawing.Size(75, 23);
this.buttonAlarm.TabIndex = 3;
this.buttonAlarm.Text = "非常ベル";
this.buttonAlarm.UseVisualStyleBackColor = true;
this.buttonAlarm.Click += new System.EventHandler(this.ActionPerformed);
//
// buttonPhone
//
this.buttonPhone.Anchor = ((System.Windows.Forms.AnchorStyles)
((System.Windows.Forms.AnchorStyles.Bottom
| System.Windows.Forms.AnchorStyles.Left)));
this.buttonPhone.Location = new System.Drawing.Point(176, 215);
this.buttonPhone.Name = "buttonPhone";
this.buttonPhone.Size = new System.Drawing.Size(75, 23);
this.buttonPhone.TabIndex = 4;
this.buttonPhone.Text = "通常通話";
this.buttonPhone.UseVisualStyleBackColor = true;
this.buttonPhone.Click += new System.EventHandler(this.ActionPerformed);
//
// buttonExit
//
this.buttonExit.Anchor = ((System.Windows.Forms.AnchorStyles)
((System.Windows.Forms.AnchorStyles.Bottom
| System.Windows.Forms.AnchorStyles.Left)));
this.buttonExit.Location = new System.Drawing.Point(261, 215);
this.buttonExit.Name = "buttonExit";
this.buttonExit.Size = new System.Drawing.Size(75, 23);
this.buttonExit.TabIndex = 5;
this.buttonExit.Text = "終了";
this.buttonExit.UseVisualStyleBackColor = true;
this.buttonExit.Click += new System.EventHandler(this.ActionPerformed);
//
// timerClock
//
this.timerClock.Tick += new System.EventHandler(this.timer1_Tick);
//
// SafeForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(348, 248);
this.Controls.Add(this.buttonExit);
this.Controls.Add(this.buttonPhone);
this.Controls.Add(this.buttonAlarm);
this.Controls.Add(this.buttonUse);
this.Controls.Add(this.textClock);
this.Controls.Add(this.textScreen);
this.Name = "SafeForm";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);
this.PerformLayout();

}

#endregion

private System.Windows.Forms.TextBox textScreen;
private System.Windows.Forms.TextBox textClock;
private System.Windows.Forms.Button buttonUse;
private System.Windows.Forms.Button buttonAlarm;
private System.Windows.Forms.Button buttonPhone;
private System.Windows.Forms.Button buttonExit;
private System.Windows.Forms.Timer timerClock;
}
}



 

この記事へのトラックバックURL