2006年03月29日

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

   このエントリーをはてなブックマークに追加 Clip to Evernote
ここに掲載したコードは、『増補改訂版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;
}
}

  

Posted by gushwell at 22:55Comments(0)TrackBack(0)

2006年03月23日

Memento ― 状態を保存する

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



Mementoクラス
using System;
using System.Collections.Generic;

namespace Gushwell.DesignPatterns.Game {

public class Memento {
private int money; // 所持金
private List<string> fruits; // フルーツ

// コンストラクタ(wide interface)
public Memento(int money) {
this.money = money;
this.fruits = new List<string>();
}

// 所持金を得る(narrow interface)
public virtual int Money {
get { return money; }

}

// フルーツを得る(wide interface)
public virtual List<string> Fruits {
get {
List<string> clone = new List<string>();
foreach (string s in fruits) {
clone.Add(s);
}
return clone;
}
}

// フルーツを追加する(wide interface)
public virtual void AddFruit(string fruit) {
fruits.Add(fruit);
}
}
}


Gamerクラス
using System;
using System.Collections.Generic;

namespace Gushwell.DesignPatterns.Game {

public class Gamer {
private int money; // 所持金
private List<string> fruits = new List<string>(); // フルーツ
private Random random = new Random(); // 乱数発生器
private static string[] fruitsname =
new string[] { "リンゴ", "ぶどう", "バナナ", "みかん" };

// コンストラクタ
public Gamer(int money) {
this.money = money;
}

// 現在の所持金を得る
public virtual int Money {
get { return money; }
}

// フルーツを1個得る
private string GetFruit() {
string prefix = "";
if (random.Next(0, 2) == 0) {
prefix = "おいしい";
}
return prefix + fruitsname[random.Next(fruitsname.Length)];
}

public virtual void Bet() {
// 賭ける…ゲームの進行
int dice = random.Next(6) + 1; // サイコロを振る
if (dice == 1) {
// 1の目…所持金が増える
money += 100;
Console.WriteLine("所持金が増えました。");
} else if (dice == 2) {
// 2の目…所持金が半分になる
money /= 2;
Console.WriteLine("所持金が半分になりました。");
} else if (dice == 6) {
// 6の目…フルーツをもらう
string f = GetFruit();
Console.WriteLine("フルーツ(" + f + ")をもらいました。");
fruits.Add(f);
} else {
// それ以外…何も起きない
Console.WriteLine("何も起こりませんでした。");
}
}

// スナップショットをとる
public virtual Memento CreateMemento() {
Memento m = new Memento(money);
foreach (string f in fruits) {
if (f.StartsWith("おいしい")) {
// フルーツはおいしいものだけ保存
m.AddFruit(f);
}
}
return m;
}

// アンドゥを行う
public virtual void RestoreMemento(Memento memento) {
this.money = memento.Money;
this.fruits = memento.Fruits;
}

// 文字列表現
public override string ToString() {
string s = string.Join(", ", fruits.ToArray());

return string.Format("[money = {0}, fruits = [{1}]]", money, s);
}
}
}


Programクラス
using System;
using System.Threading;
using Gushwell.DesignPatterns.Game;
using System.Collections.Generic;

namespace Gushwell.DesignPatterns {

public class Program {

public static void Main(string[] args) {
Gamer gamer = new Gamer(100); // 最初の所持金は100
Memento memento = gamer.CreateMemento(); // 最初の状態を保存しておく

for (int i = 0; i < 100; i++) {
Console.WriteLine("==== " + i); // 回数表示
Console.WriteLine("現状:" + gamer); // 現在の主人公の状態表示

gamer.Bet(); // ゲームを進める

Console.WriteLine("所持金は" + gamer.Money + "円になりました。");

// Mementoの取り扱いの決定
if (gamer.Money > memento.Money) {
Console.WriteLine(" (だいぶ増えたので、現在の状態を保存しておこう)");
memento = gamer.CreateMemento();
} else if (gamer.Money < memento.Money / 2) {
Console.WriteLine(" (だいぶ減ったので、以前の状態に復帰しよう)");
gamer.RestoreMemento(memento);
}

// 時間待ち
Thread.Sleep(1000);
Console.WriteLine("");
}
}
}
}

  
Posted by gushwell at 23:10Comments(0)TrackBack(0)

2006年03月22日

Observer −状態の変化を通知する

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



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

namespace Gushwell.DesignPatterns {
public interface IObserver {
void Update(NumberGenerator generator);
}
}


NumberGeneratorクラス
using System;
using System.Collections;

namespace Gushwell.DesignPatterns {

public abstract class NumberGenerator {
public abstract int Number { get;}
// Observerたちを保持
private ArrayList observers = new ArrayList();

// Observerを追加
public virtual void AddObserver(IObserver observer) {
observers.Add( observer );
}

// Observerを削除
public virtual void DeleteObserver(IObserver observer) {
observers.Remove( observer );
}

// Observerへ通知
public virtual void NotifyObservers() {
foreach ( IObserver o in observers ) {
o.Update( this );
}
}

// 数を生成する
public abstract void Execute();
}
}


RandomNumberGeneratorクラス
using System;

namespace Gushwell.DesignPatterns {
public class RandomNumberGenerator : NumberGenerator {
private Random random = new Random(); // 乱数生成機
private int number; // 現在の数

// 数を取得する
public override int Number {
get { return number; }
}

public override void Execute() {
for ( int i = 0; i < 20; i++ ) {
number = random.Next( 50 );
NotifyObservers();
}
}
}
}


DigitObserverクラス
using System;
using System.Threading;

namespace Gushwell.DesignPatterns {

public class DigitObserver : IObserver {
public virtual void Update(NumberGenerator generator) {
Console.WriteLine( "DigitObserver:" + generator.Number );
Thread.Sleep( 100 );
}
}
}


GraphObserverクラス
using System;
using System.Threading;

namespace Gushwell.DesignPatterns {

public class GraphObserver : IObserver {
public virtual void Update(NumberGenerator generator) {
Console.Write( "GraphObserver:" );
int count = generator.Number;
for ( int i = 0; i < count; i++ ) {
Console.Write( "*" );
}
Console.WriteLine( "" );
Thread.Sleep( 100 );
}
}
}


Programクラス
using System;

namespace Gushwell.DesignPatterns {

public class Program {
public static void Main(string[] args) {
NumberGenerator generator = new RandomNumberGenerator();
IObserver observer1 = new DigitObserver();
IObserver observer2 = new GraphObserver();
generator.AddObserver( observer1 );
generator.AddObserver( observer2 );
generator.Execute();
}
}
}

  
Posted by gushwell at 07:05Comments(0)TrackBack(0)

2006年03月20日

Mediator −相手は相談役1人だけ

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



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

namespace Gushwell.DesignPatterns {

public interface IColleague {
void SetMediator(IMediator mediator);
void SetColleagueEnabled(bool enabled);
}
}


ColleagueButtonクラス
using System;

namespace Gushwell.DesignPatterns {

[Serializable]
public class ColleagueButton : System.Windows.Forms.Button, IColleague {
private IMediator mediator;
public ColleagueButton()
: base() {
}
// Mediatorを保持
virtual public void SetMediator(IMediator value) {
this.mediator = value;
}

// Mediatorから有効/無効が指示される
virtual public void SetColleagueEnabled(bool value) {
Enabled = value;
}
}
}


ColleagueRadioButtonクラス
using System;

namespace Gushwell.DesignPatterns {

[Serializable]
public class ColleagueRadioButton : System.Windows.Forms.RadioButton, IColleague {
private IMediator mediator = null;
public ColleagueRadioButton()
: base() {
}

// Mediatorを保持
virtual public void SetMediator(IMediator value) {
this.mediator = value;
}

// Mediatorから有効/無効が指示される
virtual public void SetColleagueEnabled(bool value) {
Enabled = value;
}

protected override void OnCheckedChanged(EventArgs e) {
base.OnCheckedChanged(e);
if (mediator != null)
mediator.ColleagueChanged();
}
}
}


ColleagueTextFieldクラス
using System;

namespace Gushwell.DesignPatterns {

[Serializable]
public class ColleagueTextField : System.Windows.Forms.TextBox, IColleague {
private IMediator mediator = null;
public ColleagueTextField()
: base() {
}

// Mediatorを保持
virtual public void SetMediator(IMediator value) {
this.mediator = value;
}

// Mediatorから有効/無効が指示される
virtual public void SetColleagueEnabled(bool value) {
Enabled = value;
}

// 文字列が変化したらMediatorに通知
protected override void OnTextChanged(EventArgs e) {
base.OnTextChanged(e);
if (mediator != null)
mediator.ColleagueChanged();
}
}
}


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

namespace Gushwell.DesignPatterns {

public interface IMediator {
void CreateColleagues();
void ColleagueChanged();
}
}


LoginFormクラス
using System;
using System.Windows.Forms;

namespace Gushwell.DesignPatterns {
public partial class LoginForm : Form, IMediator {
public LoginForm() {
InitializeComponent();
CreateColleagues();
ColleagueChanged();
}

// 名前が実態と一致しなくなったが、オリジナルの名前のままとする。
public virtual void CreateColleagues() {
checkGuest.SetMediator(this);
checkLogin.SetMediator(this);
textUser.SetMediator(this);
textPass.SetMediator(this);
buttonOk.SetMediator(this);
buttonCancel.SetMediator(this);
}

// Colleageからの通知で各Colleageの有効/無効を判定する。
public virtual void ColleagueChanged() {
if (checkGuest.Checked) {
// Guest mode
textUser.SetColleagueEnabled(false);
textPass.SetColleagueEnabled(false);
buttonOk.SetColleagueEnabled(true);
} else {
// Login mode
textUser.SetColleagueEnabled(true);
UserpassChanged();
}
}
// textUserまたはtextPassの変更があった。
// 各Colleageの有効/無効を判定する。
private void UserpassChanged() {
if (textUser.Text.Length > 0) {
textPass.SetColleagueEnabled(true);
if (textPass.Text.Length > 0) {
buttonOk.SetColleagueEnabled(true);
} else {
buttonOk.SetColleagueEnabled(false);
}
} else {
textPass.SetColleagueEnabled(false);
buttonOk.SetColleagueEnabled(false);
}
}

private void buttonOk_Click(object sender, EventArgs e) {
Console.WriteLine(sender + " : " + e.ToString());
Close();
}
}
}


LoginFormクラス (IDEが作成したソース : LoginForm.Designer.cs)
namespace Gushwell.DesignPatterns {
partial class LoginForm {
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.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.textPass = new ColleagueTextField();
this.textUser = new ColleagueTextField();
this.buttonCancel = new ColleagueButton();
this.buttonOk = new ColleagueButton();
this.checkLogin = new ColleagueRadioButton();
this.checkGuest = new ColleagueRadioButton();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(11, 48);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(58, 12);
this.label1.TabIndex = 2;
this.label1.Text = "Username:";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(13, 82);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(56, 12);
this.label2.TabIndex = 3;
this.label2.Text = "Password:";
//
// textPass
//
this.textPass.Location = new System.Drawing.Point(76, 74);
this.textPass.MaxLength = 10;
this.textPass.Name = "textPass";
this.textPass.PasswordChar = '*';
this.textPass.Size = new System.Drawing.Size(118, 19);
this.textPass.TabIndex = 7;
//
// textUser
//
this.textUser.Location = new System.Drawing.Point(75, 41);
this.textUser.MaxLength = 10;
this.textUser.Name = "textUser";
this.textUser.Size = new System.Drawing.Size(119, 19);
this.textUser.TabIndex = 6;
//
// buttonCancel
//
this.buttonCancel.Location = new System.Drawing.Point(110, 117);
this.buttonCancel.Name = "buttonCancel";
this.buttonCancel.Size = new System.Drawing.Size(93, 23);
this.buttonCancel.TabIndex = 5;
this.buttonCancel.Text = "Cancel";
this.buttonCancel.UseVisualStyleBackColor = true;
this.buttonCancel.Click += new System.EventHandler(this.buttonOk_Click);
//
// buttonOk
//
this.buttonOk.Location = new System.Drawing.Point(3, 117);
this.buttonOk.Name = "buttonOk";
this.buttonOk.Size = new System.Drawing.Size(101, 23);
this.buttonOk.TabIndex = 4;
this.buttonOk.Text = "OK";
this.buttonOk.UseVisualStyleBackColor = true;
this.buttonOk.Click += new System.EventHandler(this.buttonOk_Click);
//
// checkLogin
//
this.checkLogin.AutoSize = true;
this.checkLogin.Location = new System.Drawing.Point(87, 12);
this.checkLogin.Name = "checkLogin";
this.checkLogin.Size = new System.Drawing.Size(50, 16);
this.checkLogin.TabIndex = 1;
this.checkLogin.TabStop = true;
this.checkLogin.Text = "Login";
this.checkLogin.UseVisualStyleBackColor = true;
//
// checkGuest
//
this.checkGuest.AutoSize = true;
this.checkGuest.Location = new System.Drawing.Point(16, 12);
this.checkGuest.Name = "checkGuest";
this.checkGuest.Size = new System.Drawing.Size(53, 16);
this.checkGuest.TabIndex = 0;
this.checkGuest.TabStop = true;
this.checkGuest.Text = "Guest";
this.checkGuest.UseVisualStyleBackColor = true;
//
// LoginForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(206, 146);
this.Controls.Add(this.textPass);
this.Controls.Add(this.textUser);
this.Controls.Add(this.buttonCancel);
this.Controls.Add(this.buttonOk);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.checkLogin);
this.Controls.Add(this.checkGuest);
this.Name = "LoginForm";
this.Text = "Mediator Sample";
this.ResumeLayout(false);
this.PerformLayout();

}

#endregion

private ColleagueRadioButton checkGuest;
private ColleagueRadioButton checkLogin;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private ColleagueButton buttonOk;
private ColleagueButton buttonCancel;
private ColleagueTextField textUser;
private ColleagueTextField textPass;

}
}


Programクラス
using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace Gushwell.DesignPatterns {
static class Program {
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new LoginForm());
}
}
}


注意点:
ColleagueButton、ColleagueRadioButton、ColleagueTextField の3つのクラスをプロジェクトに追加するとツールボックスにこれら3つのコントロールが追加されますので、このコントロールを使って、以下の画面を参考に、フォームをデザインしてください。
  
Posted by gushwell at 07:00Comments(0)TrackBack(0)

2006年03月17日

増補改訂版Java言語で学ぶデザインパターン入門マルチスレッド編

   このエントリーをはてなブックマークに追加 Clip to Evernote
『増補改訂版Java言語で学ぶデザインパターン入門マルチスレッド編』無料プレゼントを 結城さんのページでやってます。

マルチスレッド編を読まなくては、と思っているうちに、増補改定版が出てしまいました。プレゼント当たらないかなー。
  
Posted by gushwell at 21:46Comments(0)TrackBack(0)

2006年03月14日

Facade −シンプルな窓口

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



HtmlWriterクラス
using System;
using System.IO;

namespace Gushwell.DesignPatterns.Pagemaker {

public class HtmlWriter {
private StreamWriter writer;

// コンストラクタ
public HtmlWriter(StreamWriter writer) {
this.writer = writer;
}

// タイトルの出力
public virtual void Title(string title) {
writer.Write("<html>");
writer.Write("<head>");
writer.Write("<title>" + title + "</title>");
writer.Write("</head>");
writer.Write("<body>\n");
writer.Write("<h1>" + title + "</h1>\n");
}

// 段落の出力
public virtual void Paragraph(string msg) {
writer.Write("<p>" + msg + "</p>\n");
}

// リンクの出力
public virtual void Link(string href, string caption) {
Paragraph("<a href=\"" + href + "\">" + caption + "</a>");
}

// メールアドレスの出力
public virtual void Mailto(string mailaddr, string username) {
Link("mailto:" + mailaddr, username);
}

// 閉じる
public virtual void Close() {
writer.Write("</body>");
writer.Write("</html>\n");
writer.Close();
}
}
}



Databaseクラス
using System;
using System.IO;
using System.Collections.Specialized;

namespace Gushwell.DesignPatterns.Pagemaker {

public class Database {
private Database() {
// newでインスタンス生成させないためにprivate宣言
}

// データベース名からPropertiesを得る
public static NameValueCollection GetProperties(string dbname) {
string filename = dbname + ".txt";
NameValueCollection prop = new NameValueCollection();
try {
StreamReader sr = new StreamReader(filename);
while (!sr.EndOfStream) {
string line = sr.ReadLine();
string[] strs = line.Split('=');
prop.Add(strs[0], strs[1]);
}
} catch (System.IO.FileNotFoundException) {
Console.WriteLine("Warning: " + filename + " is not found.");
}
return prop;
}
}
}



PageMakerクラス
using System;
using System.Text;
using System.IO;
using System.Collections.Specialized;

namespace Gushwell.DesignPatterns.Pagemaker {

public class PageMaker {
private PageMaker() {
// インスタンスは作らないのでprivate宣言する
}

public static void MakeWelcomePage(string mailaddr, string filename) {
try {
NameValueCollection mailprop = Database.GetProperties("maildata");
string username = mailprop.Get(mailaddr);
HtmlWriter writer =
new HtmlWriter(new StreamWriter(filename, false, Encoding.Default));
writer.Title("Welcome to " + username + "'s page!");
writer.Paragraph(username + "のページへようこそ。");
writer.Paragraph("メールまっていますね。");
writer.Mailto(mailaddr, username);
writer.Close();
Console.WriteLine(filename + " is created for " + mailaddr +
" (" + username + ")");
} catch (System.IO.IOException e) {
Console.Error.WriteLine(e.StackTrace);
}
}
}
}



Programクラス
using System;
using Gushwell.DesignPatterns.Pagemaker;

namespace Gushwell.DesignPatterns {

public class Program {
public static void Main(string[] args) {
PageMaker.MakeWelcomePage("hyuki@hyuki.com", "welcome.html");
}
}
}

  
Posted by gushwell at 21:40Comments(0)TrackBack(0)

2006年03月13日

Math.Roundの新しいoverload

   このエントリーをはてなブックマークに追加 Clip to Evernote
.NET Framework2.0 の Math.Roundメソッドには、四捨五入できるオプションが追加されていました。

double a = double.Parse(s);
double n = Math.Round(a, 2, MidpointRounding.AwayFromZero);

のように、MidpointRounding 列挙体で、丸め方法を指定できるようになったようです。
もちろん、デフォルトは、結果を偶数にする丸めです。
  
Posted by gushwell at 08:00Comments(0)TrackBack(0)

2006年03月07日

Chain of Responsibility ‐責任のたらい回し

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



FileTreatmentExceptionクラス
using System;

namespace Gushwell.DesignPatterns {

[Serializable]
public class FileTreatmentException : System.SystemException {
public FileTreatmentException() {
}
public FileTreatmentException(string msg)
: base(msg) {
}
}
}


Visitorクラス
using System;

namespace Gushwell.DesignPatterns {

public abstract class Visitor {
public abstract void Visit(File file);
public abstract void Visit(Directory directory);
}
}


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

namespace Gushwell.DesignPatterns {

public interface IElement {
void Accept(Visitor v);
}
}


Entryクラス
using System;
using System.Collections;

namespace Gushwell.DesignPatterns {

public abstract class Entry : IElement, IEnumerable {
public abstract string Name { get; }
public abstract int Size { get; }

// エントリを追加する
public virtual Entry Add(Entry entry) {
throw new FileTreatmentException();
}

// IEnumeratorの生成
public virtual IEnumerator GetEnumerator() {
throw new FileTreatmentException();
}

// 文字列表現
public override string ToString() {
return Name + " (" + Size + ")";
}

public abstract void Accept(Visitor param1);
}
}


Fileクラス
using System;

namespace Gushwell.DesignPatterns {

public class File : Entry {
private string name;
private int size;

public File(string name, int size) {
this.name = name;
this.size = size;
}

public override string Name {
get { return name; }
}

public override int Size {
get { return size; }
}

public override void Accept(Visitor v) {
v.Visit(this);
}
}
}


Directoryクラス
using System.Collections.Generic;

namespace Gushwell.DesignPatterns {

public class Directory : Entry, IEnumerable {
private string name; // ディレクトリの名前
private List<Entry> dir = new List<Entry>(); // ディレクトリエントリの集合

// コンストラクタ
public Directory(string name) {
this.name = name;
}

// 名前を得る
public override string Name {
get { return name; }
}

// サイズを得る
public override int Size {
get {
int size = 0;
foreach (Entry entry in dir)
size += entry.Size;
return size;
}
}

// エントリの追加
public override Entry Add(Entry entry) {
dir.Add(entry);
return this;
}

// 訪問者の受け入れ
public override void Accept(Visitor v) {
v.Visit(this);
}

// IEnumeratorの生成
public override IEnumerator GetEnumerator() {
return dir.GetEnumerator();
}
}
}


ListVisitorクラス
using System;

namespace Gushwell.DesignPatterns {

public class ListVisitor : Visitor {
private string currentdir = ""; // 現在注目しているディレクトリ名

// ファイルを訪問したときに呼ばれる
public override void Visit(File file) {
Console.WriteLine(currentdir + "/" + file);
}

// ディレクトリを訪問したときに呼ばれる
public override void Visit(Directory directory) {
Console.WriteLine(currentdir + "/" + directory);
string savedir = currentdir;
currentdir = currentdir + "/" + directory.Name;

foreach (Entry entry in directory)
entry.Accept(this);

currentdir = savedir;
}
}
}


Programクラス
using System;

namespace Gushwell.DesignPatterns {

public class Program {
public static void Main(string[] args) {
try {
Console.WriteLine("Making root entries...");
Directory rootdir = new Directory("root");
Directory bindir = new Directory("bin");
Directory tmpdir = new Directory("tmp");
Directory usrdir = new Directory("usr");
rootdir.Add(bindir);
rootdir.Add(tmpdir);
rootdir.Add(usrdir);
bindir.Add(new File("vi", 10000));
bindir.Add(new File("latex", 20000));
rootdir.Accept(new ListVisitor());

Console.WriteLine("");
Console.WriteLine("Making user entries...");
Directory yuki = new Directory("yuki");
Directory hanako = new Directory("hanako");
Directory tomura = new Directory("tomura");
usrdir.Add(yuki);
usrdir.Add(hanako);
usrdir.Add(tomura);
yuki.Add(new File("diary.html", 100));
yuki.Add(new File("Composite.java", 200));
hanako.Add(new File("memo.tex", 300));
tomura.Add(new File("game.doc", 400));
tomura.Add(new File("junk.mail", 500));
rootdir.Accept(new ListVisitor());
} catch (FileTreatmentException e) {
Console.Error.WriteLine(e.StackTrace);
}
}
}
}

  
Posted by gushwell at 22:46Comments(2)TrackBack(0)