C#デザインパターン  - State

ここに掲載したコードは、『増補改訂版Java言語で学ぶデザインパターン入門 / 結城 浩(著)』に掲載されているサンプルコードをC#に移植したものです。
解説らしい解説は載せていませんので、『増補改訂版Java言語で学ぶデザインパターン入門 / 結城 浩(著)』も合わせてお読みください。

※当ソースは、Visual C# 2008 Express Editionで動作を確認しています。
  Visual Studio 2005をお使いの方は、ブログの記事を残しておきますので、そちらをご覧ください。



■IState.cs
using System;

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


■DayState.cs
using System;

namespace Gushwell.DesignPatterns {
    public sealed class DayState : IState {
        // 唯一のインスタンスを得る
        public static IState 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 .cs
using System;

namespace Gushwell.DesignPatterns {
    public sealed class NightState : IState {
        // 唯一のインスタンスを得る
        public static IState 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 "[夜間]";
        }
    }
}




IContext.cs
using System;

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


■SafeForm.cs
using System;
using System.Windows.Forms;

namespace Gushwell.DesignPatterns {
    //フォームはIContextを実装
    public partial class SafeForm : Form, IContext {
        private IState state = DayState.Instance;
        public SafeForm() {
            InitializeComponent();
        }

        // 金庫使用ボタン
        private void buttonUse_Click(object sender, EventArgs e) {
            state.DoUse(this);
        }

        // 非常ベルボタン
        private void buttonAlarm_Click(object sender, EventArgs e) {
            state.DoAlarm(this);
        }

        // 通常通話ボタン
        private void buttonPhone_Click(object sender, EventArgs e) {
            state.DoPhone(this);
        }

        // 終了ボタン
        private void buttonExit_Click(object sender, EventArgs e) {
            System.Environment.Exit(0);
        }
        
        // 時刻の設定
        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(IState 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.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 SafeForm());
        }
    }
}