2006年01月24日

Builderパターン -複雑なインスタンスを組み立てる

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



Builder
using System;

namespace Gushwell.DesignPatterns {
public abstract class Builder {
public abstract void MakeTitle(string title);
public abstract void MakeString(string str);
public abstract void MakeItems(string[] items);
public abstract void Close();
}
}



TextBuilder
using System;
using System.Text;

namespace Gushwell.DesignPatterns {
public class TextBuilder : Builder {
// このフィールドに文書を構築していく
private StringBuilder buffer = new StringBuilder();

// 完成した文書
virtual public string Result {
get { return buffer.ToString(); }
}

// プレーンテキストでのタイトル
public override void MakeTitle(string title) {
buffer.Append("==============================\n"); // 飾り線
buffer.Append("『" + title + "』\n"); // 『』つきのタイトル
buffer.Append("\n"); // 空行
}

// プレーンテキストでの文字列
public override void MakeString(string str) {
buffer.Append('■' + str + "\n"); // ■つきの文字列
buffer.Append("\n"); // 空行
}

// プレーンテキストでの箇条書き
public override void MakeItems(string[] items) {
for (int i = 0; i < items.Length; i++) {
buffer.Append(" ・" + items[i] + "\n"); // ・つきの項目
}
buffer.Append("\n"); // 空行
}

// 文書の完成
public override void Close() {
buffer.Append("==============================\n"); // 飾り線
}
}
}



HTMLBuilder
using System;
using System.IO;

namespace Gushwell.DesignPatterns {
public class HTMLBuilder : Builder {
private string filename; // 作成するファイル名
private StreamWriter writer; // ファイルに書き込む

// 完成した文書
public virtual string Result {
get { return filename; } // ファイル名を返す
}

// HTMLファイルでのタイトル
public override void MakeTitle(string title) {
filename = title + ".html"; // タイトルを元にファイル名決定
try {
writer = new StreamWriter(filename, false);
} catch (System.IO.IOException e) {
Console.WriteLine(e.StackTrace);
}
// タイトルを出力
writer.WriteLine("<html><head><title>" + title + "</title></head><body>");
writer.WriteLine("<meta http-equiv=\"Content-Type\" " +
"content=\"text/html; charset=UTF-8\" />");
writer.WriteLine("<h1>" + title + "</h1>");
}

// HTMLファイルでの文字列
public override void MakeString(string str) {
writer.WriteLine("<p>" + str + "</p>"); // <p>タグで出力
}

// HTMLファイルでの箇条書き
public override void MakeItems(string[] items) {
writer.WriteLine("<ul>"); // <ul>と<li>で出力
for (int i = 0; i < items.Length; i++) {
writer.WriteLine("<li>" + items[i] + "</li>");
}
writer.WriteLine("</ul>");
}

// 文書の完成
public override void Close() {
writer.WriteLine("</body></html>"); // タグを閉じる
writer.Close(); // ファイルをクローズ
}
}
}



Director
using System;

namespace Gushwell.DesignPatterns {
public class Director {
private Builder builder;

public Director(Builder builder) {
// Builderのサブクラスのインスタンスが与えられるので、
// builderフィールドに保持しておく。
this.builder = builder;
}

public virtual void Construct() {
// 文書構築
builder.MakeTitle("Greeting"); // タイトル
builder.MakeString("朝から昼にかけて"); // 文字列
builder.MakeItems(new string[]
{ "おはようございます。", "こんにちは。" });
builder.MakeString("夜に"); // 別の文字列
builder.MakeItems(new string[]
{ "こんばんは。", "おやすみなさい。", "さようなら。" });
builder.Close(); // 文書を完成させる
}
}
}



Program
using System;

namespace Gushwell.DesignPatterns {
public class Program {
public static void Main(string[] args) {
if (args.Length != 1) {
Usage();
return;
}
if (args[0].Equals("plain")) {
TextBuilder textbuilder = new TextBuilder();
Director director = new Director(textbuilder);
director.Construct();
string result = textbuilder.Result;
Console.WriteLine(result);
} else if (args[0].Equals("html")) {
HTMLBuilder htmlbuilder = new HTMLBuilder();
Director director = new Director(htmlbuilder);
director.Construct();
string filename = htmlbuilder.Result;
Console.WriteLine(filename + "が作成されました。");
} else {
Usage();
return;
}
}

public static void Usage() {
Console.WriteLine("Usage: BuilderSample plain プレーンテキストで文書作成");
Console.WriteLine("Usage: BuilderSample html HTMLファイルで文書作成");
}
}
}
  

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

2006年01月23日

リファクタリングの由来

   このエントリーをはてなブックマークに追加 Clip to Evernote
リファクタリングという言葉は、Larry Constantine が、構造化プログラミングで使った「ファクタリング」という用語に由来するそうです。
「ファクタリング」とは、「プログラム成分をできるだけ細かく分解すること」だそうです。
なるほどね。  
Posted by gushwell at 23:06Comments(0)TrackBack(0)

2006年01月22日

Bridgeパターン -機能の階層と実装の階層を分ける

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



Displayクラス
using System;

namespace Gushwell.DesignPatterns {

public class Display {
private DisplayImpl impl;

public Display(DisplayImpl impl) {
this.impl = impl;
}

public virtual void Open() {
impl.RawOpen();
}

public virtual void Print() {
impl.RawPrint();
}

public virtual void Close() {
impl.RawClose();
}

// オリジナルのメソッド名は 'display'
// クラスメイトバッティングするため、Showに変更
public void Show() {
Open();
Print();
Close();
}
}
}



CountDisplayクラス
using System;

namespace Gushwell.DesignPatterns {

public class CountDisplay : Display {
public CountDisplay(DisplayImpl impl) : base(impl) {
}

public virtual void MultiDisplay(int times) {
// times回繰り返して表示する
Open();
for (int i = 0; i < times; i++) {
Print();
}
Close();
}
}
}



DisplayImplクラス
using System;

namespace Gushwell.DesignPatterns {

public abstract class DisplayImpl {
public abstract void RawOpen();
public abstract void RawPrint();
public abstract void RawClose();
}
}



StringDisplayImplクラス
using System;
using System.Text;

namespace Gushwell.DesignPatterns {

public class StringDisplayImpl : DisplayImpl {
private string str; // 表示するべき文字列
private int width; // バイト単位で計算した文字列の「幅」

public StringDisplayImpl(string str) {
//コンストラクタで渡された文字列stringを、
this.str = str; //フィールドに記憶しておく。
this.width = Encoding.GetEncoding("shift-jis").GetByteCount(str);
}

public override void RawOpen() {
printLine();
}

public override void RawPrint() {
Console.WriteLine("|" + str + "|"); // 前後に"|"をつけて表示
}

public override void RawClose() {
printLine();
}

private void printLine() {
Console.Write("+"); // 枠の角を表現する"+"マークを表示する。
for (int i = 0; i < width; i++) {
Console.Write("-"); // width個の"-"を表示して、枠線として用いる。
}
Console.WriteLine("+"); // 枠の角を表現する"+"マークを表示する。
}
}
}



Programクラス
using System;

namespace Gushwell.DesignPatterns {

public class Program {
public static void Main(string[] args) {
Display d1 = new Display(new StringDisplayImpl("Hello, Japan."));
Display d2 = new CountDisplay(new StringDisplayImpl("Hello, World."));
CountDisplay d3 = new CountDisplay(new StringDisplayImpl("Hello, Universe."));
d1.Show();
d2.Show();
d3.Show();
d3.MultiDisplay(5);
}
}
}
  
Posted by gushwell at 23:16Comments(0)TrackBack(0)

2006年01月19日

C#: 昨日、今日、明日: アンダース ヘルスバーグへのインタビュー Part 2

   このエントリーをはてなブックマークに追加 Clip to Evernote
ブログ「猪股健太郎の雑記」で『C#: 昨日、今日、明日: アンダース ヘルスバーグへのインタビュー Part 2』の翻訳が公開されました。
アンダース氏の新しいものへ取り組む姿勢は参考になりますね。猪俣氏に感謝です。
  
Posted by gushwell at 21:50Comments(0)TrackBack(0)

2006年01月17日

Prototype ― コピーしてインスタンスを作る

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




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

namespace Gushwell.DesignPatterns.Prototype.Framework {

public interface IProduct : System.ICloneable {
void Use(string s);
}
}



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

namespace Gushwell.DesignPatterns.Prototype.Framework {

public class Manager {
private Hashtable showcase = new Hashtable();
public virtual void Register(string name, IProduct proto) {
showcase[name] = proto;
}
public virtual IProduct Create(string protoname) {
IProduct p = (IProduct)showcase[protoname];
return (IProduct)p.Clone();
}
}
}



UnderlinePenクラス
using System;
using System.Text;
using Gushwell.DesignPatterns.Prototype.Framework;

namespace Gushwell.DesignPatterns.Prototype {
public class UnderlinePen : IProduct {
private char ulchar;
public UnderlinePen(char ulchar) {
this.ulchar = ulchar;
}

public virtual void Use(string s) {
int length = Encoding.GetEncoding("shift-jis").GetByteCount(s);

Console.WriteLine("\"" + s + "\"");
Console.Write(" ");
for (int i = 0; i < length; i++) {
Console.Write(ulchar);
}
Console.WriteLine("");
}

public virtual object Clone() {
return (IProduct)MemberwiseClone();
}

}
}



MessageBoxクラス
using System;
using System.Text;
using Gushwell.DesignPatterns.Prototype.Framework;

namespace Gushwell.DesignPatterns.Prototype {

public class MessageBox : IProduct {
private char decochar;
public MessageBox(char decochar) {
this.decochar = decochar;
}

public virtual void Use(string s) {
int length = Encoding.GetEncoding("shift-jis").GetByteCount(s);
for (int i = 0; i < length + 4; i++) {
Console.Write(decochar);
}
Console.WriteLine("");

Console.WriteLine(decochar + " " + s + " " + decochar);

for (int i = 0; i < length + 4; i++) {
Console.Write(decochar);
}
Console.WriteLine("");
}

public virtual object Clone() {
return (IProduct)MemberwiseClone();
}
}
}



Programクラス
using System;
using Gushwell.DesignPatterns.Prototype.Framework;

namespace Gushwell.DesignPatterns.Prototype {
public class Program {
[STAThread]
public static void Main(string[] args) {
// 準備
Manager manager = new Manager();
UnderlinePen upen = new UnderlinePen('~');
MessageBox mbox = new MessageBox('*');
MessageBox sbox = new MessageBox('/');
manager.Register("strong message", upen);
manager.Register("warning box", mbox);
manager.Register("slash box", sbox);

// 生成
IProduct p1 = manager.Create("strong message");
p1.Use("Hello, world.");
IProduct p2 = manager.Create("warning box");
p2.Use("Hello, world.");
IProduct p3 = manager.Create("slash box");
p3.Use("Hello, world.");

}
}
}
  
Posted by gushwell at 22:52Comments(0)TrackBack(0)

2006年01月14日

Singletonパターン -たった1つのインスタンス

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



Singletonクラス
using System;

namespace Gushwell.DesignPatterns {
public sealed class Singleton {
public static Singleton Instance {
get { return singleton; }

}
private static readonly Singleton singleton = new Singleton();
private Singleton() {
Console.WriteLine("インスタンスを生成しました。");
}
}
}



Programクラス
using System;

namespace Gushwell.DesignPatterns {
public class Program {
[STAThread]
public static void Main(System.String[] args) {
Console.WriteLine("Start.");
Singleton obj1 = Singleton.Instance;
Singleton obj2 = Singleton.Instance;
if (obj1 == obj2) {
Console.WriteLine("obj1とobj2は同じインスタンスです。");
} else {
Console.WriteLine("obj1とobj2は同じインスタンスではありません。");
}
Console.WriteLine("End.");
Console.ReadLine();
}
}
}


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

2006年01月12日

FactoryMethod ― インスタンス作成をサブクラスにまかせる

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


Productクラス
using System;

namespace Gushwell.DesignPatterns.Framework {

public abstract class Product {
public abstract void Use();
}
}


Factoryクラス
using System;

namespace Gushwell.DesignPatterns.Framework {

public abstract class Factory {
public Product Create(string owner) {
Product p = CreateProduct(owner);
RegisterProduct(p);
return p;
}

protected abstract Product CreateProduct(string owner);
protected abstract void RegisterProduct(Product product);
}
}


IDCardクラス
using System;
using Gushwell.DesignPatterns.Framework;

namespace Gushwell.DesignPatterns.IDCard {

public class IDCard : Product {
private string owner;

public IDCard(string owner) {
Console.WriteLine(owner + "のカードを作ります。");
this.owner = owner;
}

public override void Use() {
Console.WriteLine(owner + "のカードを使います。");
}

public virtual string Owner {
get { return owner; }
}

}
}


IDCardFactoryクラス
using System;
using System.Collections.Generic;
using Gushwell.DesignPatterns.Framework;

namespace Gushwell.DesignPatterns.IDCard {

public class IDCardFactory : Factory {
private List<string> owners = new List<string>();

protected override Product CreateProduct(string owner) {
return new IDCard(owner);
}

protected override void RegisterProduct(Product product) {
owners.Add(((IDCard)product).Owner);
}

public virtual List<string> Owners {
get { return owners; }
}
}
}


Programクラス
using System;
using Gushwell.DesignPatterns.Framework;
using Gushwell.DesignPatterns.IDCard;

namespace Gushwell.DesignPatterns {

public class Program {
[STAThread]
public static void Main(string[] args) {
Factory factory = new IDCardFactory();
Product card1 = factory.Create("結城浩");
Product card2 = factory.Create("とむら");
Product card3 = factory.Create("佐藤花子");
card1.Use();
card2.Use();
card3.Use();
}
}
}

  
Posted by gushwell at 20:34Comments(0)TrackBack(1)

2006年01月08日

Template Method ― 具体的な処理をサブクラスにまかせる

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


AbstractDisplayクラス
using System;

namespace Gushwell.DesignPatterns {
// 抽象クラスAbstractDisplay
public abstract class AbstractDisplay {
public abstract void Open(); // サブクラスに実装をまかせる抽象メソッド(1) Open
public abstract void Print(); // サブクラスに実装をまかせる抽象メソッド(2) Print
public abstract void Close(); // サブクラスに実装をまかせる抽象メソッド(3) Close

// この抽象クラスで実装しているメソッドDisplay
public void Display() {
Open(); // まずopenして…
// 5回printを繰り返して…
for (int i = 0; i < 5; i++) {
Print();
}
Close(); // …最後にCloseする。これがDisplayメソッドで実装されている内容。
}
}
}


CharDisplayクラス
using System;

namespace Gushwell.DesignPatterns {
public class CharDisplay: AbstractDisplay {
// CharDisplayは、AbstractDisplayのサブクラス。
private char ch; // 表示すべき文字。

public CharDisplay(char ch) { // コンストラクタで渡された文字chを、
this.ch = ch; // フィールドに記憶しておく。
}

// スーパークラスでは抽象メソッドだった。ここでオーバーライドして実装。
public override void Open() {
Console.Write("<<"); // 開始文字列として"<<"を表示する。
}

// printメソッドもここで実装する。これがdisplayから繰り返して呼び出される。
public override void Print() {
Console.Write(ch); // フィールドに記憶しておいた文字を1個表示する。
}

// closeメソッドもここで実装。
public override void Close() {
Console.WriteLine(">>"); // 終了文字列">>"を表示。
}
}
}


StringDisplayクラス
using System;
using System.Text;

namespace Gushwell.DesignPatterns {
public class StringDisplay: AbstractDisplay {
// StringDisplayも、AbstractDisplayのサブクラス。
private string str; // 表示するべき文字列。
private int width; // バイト単位で計算した文字列の「幅」。
public StringDisplay(string str) {
// コンストラクタで渡された文字列stringを、
this.str = str; // フィールドに記憶。
this.width = GetWidth(str); // それからバイト単位の幅もフィールドに記憶しておいて、後で使う。
}

// オーバーライドして定義するopenメソッド。
public override void Open() {
PrintLine(); // このクラスのメソッドPrintLineで線を引いている。
}

// Printメソッドは、
// フィールドに記憶しておいた文字列の前後に"|"をつけて表示。
public override void Print() {
Console.WriteLine("|" + str + "|");
}
// Closeメソッドは、
// Openと同じくPrintLineメソッドで線を引いている。
public override void Close() {
PrintLine();
}

// OpenとCloseから呼ばれるPrintLineメソッドだ。privateなので、このクラスの中だけで使われる。
private void PrintLine() {
Console.Write("+"); // 枠の角を表現する"+"マークを表示。
// width個の"-"を表示して、枠線として用いる。
for (int i = 0; i < width; i++) {
Console.Write("-");
}
Console.WriteLine("+"); // 枠の角を表現する"+"マークを表示。
}

// 文字幅を求める
private int GetWidth(string str) {
return Encoding.GetEncoding("shift-jis").GetByteCount(str);
}
}
}


Programクラス
using System;

namespace Gushwell.DesignPatterns {
public class Program {
public static void Main(System.String[] args) {
// 'H'を持ったCharDisplayのインスタンスを1個作る。
AbstractDisplay d1 = new CharDisplay('H');
// "Hello, world."を持ったStringDisplayのインスタンスを1個作る。
AbstractDisplay d2 = new StringDisplay("Hello, world.");
// "こんにちは。"を持ったStringDisplayのインスタンスを1個作る。
AbstractDisplay d3 = new StringDisplay("こんにちは。");

d1.Display(); // d1,d2,d3とも、すべて同じAbstractDisplayのサブクラスのインスタンス
d2.Display(); // だから、継承したdisplayメソッドを呼び出すことができる。
d3.Display(); // 実際の動作は個々のクラスCharDisplayやStringDisplayで定まる。
}
}
}

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