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

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

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



■IBuilder.cs
using System;

namespace Gushwell.DesignPatterns {
public interface IBuilder {
void MakeTitle(string title);
void MakeString(string str);
void MakeItems(string[] items);
void Close();
string Result { get; }
}
}


■TextBuilder.cs
using System;
using System.Text;
using Gushwell.Dejavu;

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

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

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

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

// プレーンテキストでの箇条書き
public void MakeItems(string[] items) {
items.ForEach(str =>
buffer.AppendLine(" ・" + str));
buffer.AppendLine(); // 空行
}

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


■HtmlBuilder.cs
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using Gushwell.Dejavu;

namespace Gushwell.DesignPatterns {

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

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

// HTMLファイルでのタイトル
public 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 void MakeString(string str) {
writer.WriteLine("<p>" + str + "</p>"); // <p>タグで出力
}

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

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

// なぜ、HTMLBuilderは、ファイルに出力するのに、TextBuilderはファイルに出力しない設計
// なのか不明。僕ならば、両方stringとして結果を得られるようにし、ファイルに出力するか
// しないかは、利用する側で決められるようにする。

}



■Director.cs
using System;

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

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

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



■Program.cs
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();
string result = DoWork(textbuilder);
Console.WriteLine(result);
} else if (args[0].Equals("html")) {
HTMLBuilder htmlbuilder = new HTMLBuilder();
string filename = DoWork(htmlbuilder);
Console.WriteLine(filename + "が作成されました。");
} else {
Usage();
return;
}
}

private static string DoWork(IBuilder builder) {
Director director = new Director(builder);
director.Construct();
return builder.Result;
}

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



■EnumerableExtentions.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

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++;
}
}
}
}