Builderパターン
同じ作成過程で異なる表現形式の結果を得る
Builder パターンとは、「処理手順」を決定する Director と呼ばれるものと「処理内容」を決定する Builder と呼ばれるものを組み合わせることで、オブジェクトの生成をより柔軟にし、そのオブジェクトの「処理手順」をもコントロールすることができるようにするためのパターンです。

例えば、社員旅行することを考えてみます。どのような旅行になるかは「旅行の手順」と「旅行の内容」の大きく2つの要素で決定されます。「旅行の手順」とは、「旅行はどこに、どのような順番で、何をどのようにしていくか」というようなことであり、「旅行の内容」とは、「移動には何を使って、ホテルはどこに泊まって・・・」ということであると考えてください。

このとき、「旅行の手順」には、“観光旅行のための手順” や “食べ歩きのための手順”、または “史跡見学のための手順” など様々なものが考えられます。同様に、「旅行の内容」にも、“移動は新幹線で、宿泊は豪華ホテルで” などのような費用の掛かる富豪コースもあれば、“移動はバスで、ホテルは激安で”といった貧民コースも考えられます。
これらをそれぞれ用意しておくことで、 “観光旅行のための手順” で “富豪コース” とか“食べ歩きのための手順” で “貧民コース”といったように、あらかじめ用意された「旅行の手順」と「旅行の内容」を組み合わせることによって、いろいろな要望に柔軟に応えることができるようになります。
オブジェクト指向プログラミングでは、「誰が何を知っているか」はとても大切です。すなわち、どのクラスがどのメソッドを使ってよいかに注意してプログラミングする必要があります。
Builder パターンでは、利用者のクラス(main)は、Builder クラスのメソッドを知りません。つまり、呼び出しません。Director クラスのあるメソッド(construct)のみ呼び出します。すると、Director クラスの中で処理が進み、作業が完了します。
一方、 Director クラスが知っているのは、Builder クラスです。Director クラスは Builder クラスのメソッドを使って作業を進めます。しかし、Director クラスは、自分が実際に利用しているクラスが「本当は」何なのかを知りません。 つまり、Builder クラスを継承したサブクラスであるということしか知らないのです。しかし、知らなくてもかまわないのです、Director クラスは、Builder クラスのメソッドだけを使っており、 Builder クラスのサブクラスはそのメソッドを実装しているからです。
例を挙げてもう一度説明しましょう。「旅行の手順」という Director クラスは、「旅行の内容」という Builder クラスのメソッドだけを知っています。例えば、(書いてないけど)交通機関を得るメソッド、ホテルを得るメソッドなどです。しかし、実際はどのコースなのかということは知らなくてもかまわないのです。「富豪コース」であろうが、「貧民コース」であろうが、同じメソッドを実装しているからです。
Director クラスは、Builder のサブクラスが何であるということは知りません。逆に言うと、知らないからこそ、入れ替えできるのです。サブクラスが何であるということ知っていて、その固有のメソッドを使用していては、もはや入れ替えはできません。
知らないからこそ、入れ替えができるのです。入れ替えられるからこそ、部品としての価値が高くなるのです。この「交換可能性」については、クラスを設計するときに常に意識しておくことが必要になります。
しかし、いくら厳密に設計したとしても、修正や追加は発生します。クラスの役割を理解していないと、どのクラスを変更すべきかの判断を誤ります。例えば、 Builder クラスを修正するということは、 Director クラスが呼び出すメソッドを修正することであり、また、 Builder クラスのサブクラス全部に影響が及ぶということです。あるいは、うっかり、 Director クラスがBuilder クラスのあるサブクラスに固有のメソッドを呼び出しすると、部品としての独立性が失われ、他のサブクラスに切り替えたときにうまく動かないということになってしまいます。
例題
あらかじめ用意された文書を指定されたフォーマットに整形するクラスを作成しなさい。
ひとつはプレーンなテキストにする TextBuilder クラス、もうひとつは HTML にする HtmlBuilder クラスです。
| プレーンなテキスト *** いろいろな国の言葉 *** ■こんにちは ○Hello ○Bonjour : (end) | HTML <h3>いろいろな国の言葉</h3> <span>こんにちは</span> <ul> <li>Hello</li> <li>Bonjour</li> : </ul> |
|
Builderパターンを使用しない例 AbstractContent.java public abstract class AbstractContent {
protected StringBuffer buf = new StringBuffer();
protected final String title = "いろいろな国の言葉";
protected final String[] japanese = new String[] {
"こんにちは", "ありがとう" };
protected final String[][] flangs = new String[][] {
{ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" },
{ "Thank you", "Merci", "Danke", "Grazie", "Gracias" } };
protected abstract void makeTitle(String title);
protected abstract void makeJapanese(String japanese);
protected abstract void makeFlangs(String[] flangs);
protected abstract void close();
public String get() {
return buf.toString();
}
public void construct() {
makeTitle(title);
for (int i = 0; i < japanese.length; i++) {
makeJapanese(japanese[i]);
makeFlangs(flangs[i]);
}
close();
}
}
TextBuilder.java public class TextBuilder extends AbstractContent {
protected void makeTitle(String title) {
buf.append("*** " + title + " ***\n");
}
protected void makeJapanese(String japanese) {
buf.append("■" + japanese + "\n");
}
protected void makeFlangs(String[] flangs) {
for (int i = 0; i < flangs.length; i++)
buf.append(" ○" + flangs[i] + "\n");
}
protected void close() {
buf.append("(end)\n");
}
}
HtmlBuilder.java public class HtmlBuilder extends AbstractContent {
protected void makeTitle(String title) {
buf.append("<html>\n<head>\n<title>" + title + "</title>\n</head>\n<body>\n");
buf.append("<h3>" + title + "</h3>\n");
}
protected void makeJapanese(String japanese) {
buf.append("<span>" + japanese + "</span>\n");
}
protected void makeFlangs(String[] flangs) {
buf.append("<ul>\n");
for (int i = 0; i < flangs.length; i++)
buf.append("<li>" + flangs[i] + "</li>\n");
buf.append("</ul>\n");
}
protected void close() {
buf.append("</body>\n</html>\n");
}
}
Main.java public class Main {
public static void main(String[] args) {
TextBuilder txt = new TextBuilder();
txt.construct();
System.out.print(txt.get());
HtmlBuilder htm = new HtmlBuilder();
htm.construct();
System.out.print(htm.get());
}
}
|
Builderパターンを使用した例 AbstractDirector.java public abstract class AbstractDirector {
protected AbstractBuilder builder;
public AbstractDirector() {}
public AbstractDirector(AbstractBuilder builder) {
this.builder = builder;
}
public abstract void construct();
}
Director.java public class Director extends AbstractDirector {
private final String title = "いろいろな国の言葉";
private final String[] japanese = new String[] {
"こんにちは", "ありがとう" };
private final String[][] flangs = new String[][] {
{ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" },
{ "Thank you", "Merci", "Danke", "Grazie", "Gracias" } };
public Director(AbstractBuilder builder) {
super(builder);
}
public void construct() {
builder.makeTitle(title);
for (int i = 0; i < japanese.length; i++) {
builder.makeJapanese(japanese[i]);
builder.makeFlangs(flangs[i]);
}
builder.close();
}
}
AbstractBuilder.java public abstract class AbstractBuilder {
protected StringBuffer buf = new StringBuffer();
protected abstract void makeTitle(String title);
protected abstract void makeJapanese(String japanese);
protected abstract void makeFlangs(String[] flangs);
protected abstract void close();
public String get() {
return buf.toString();
}
}
TextBuilder.java public class TextBuilder extends AbstractBuilder {
protected void makeTitle(String title) {
buf.append("*** " + title + " ***\n");
}
protected void makeJapanese(String japanese) {
buf.append("■" + japanese + "\n");
}
protected void makeFlangs(String[] flangs) {
for (int i = 0; i < flangs.length; i++)
buf.append(" ○" + flangs[i] + "\n");
}
protected void close() {
buf.append("(end)\n");
}
}
HtmlBuilder.java public class HtmlBuilder extends AbstractBuilder {
protected void makeTitle(String title) {
buf.append("<html>\n<head>\n<title>" + title + "</title>\n</head>\n<body>\n");
buf.append("<h3>" + title + "</h3>\n");
}
protected void makeJapanese(String japanese) {
buf.append("<span>" + japanese + "</span>\n");
}
protected void makeFlangs(String[] flangs) {
buf.append("<ul>\n");
for (int i = 0; i < flangs.length; i++)
buf.append("<li>" + flangs[i] + "</li>\n");
buf.append("</ul>\n");
}
protected void close() {
buf.append("</body>\n</html>\n");
}
}
Main.java public class Main {
public static void main(String[] args) {
AbstractDirector director = null;
TextBuilder txt = new TextBuilder();
director = new Director(txt);
director.construct();
System.out.print(txt.get());
HtmlBuilder htm = new HtmlBuilder();
director = new Director(htm);
director.construct();
System.out.print(htm.get());
}
}
|
|
この例は Template Method パターンで書かれています。 処理の枠組みを記述したスーパークラスが AbstractContent で、それを継承して処理の具体的内容を記述したのが TextBuilder と HtmlBuilder です。インスタンスの生成はTextBuilder と HtmlBuilder について行われ、それらのクラスにある、AbstractContent から継承した construct() メソッドを呼び出しています。 しかし、 TextBuilder と HtmlBuilder は、処理手順の書かれた AbstractContent のサブクラスとして作成されていますので、処理手順と表現方法を自由に組み合わせたり変更したりができません。 例えば、HTML文章を今は「処理手順1」で出していたけど、次は「処理手順5」で出そうというようなことができないわけです。 処理手順である AbstractContent を継承して、TextBuilder はプレーンテキストで出す、HtmlBuilder はHTMLで出す、としているので、処理手順は変更できないのです。 |
「作成過程」を決定する Director と呼ばれるものと「表現形式」を決定する Builder と呼ばれるものを組み合わせて実現しています。 Template Method パターンと同様、 Director には処理の枠組みが記述されており、 Builder には処理の具体的内容が記述されています。 ただし、 Template Method パターンと異なるところは、インスタンスの生成が両方について行われることです。まず、Builder を継承した TextBuilder や HtmlBuilder のインスタンスが生成され、Director のインスタンス生成時にそれらが引き渡されます。そして、 Director クラスの construct() メソッドを呼び出します。 そして、引き渡されたTextBuilder や HtmlBuilder のインスタンスに従った文書が作成されるわけです。例えば、 HtmlBuilder のインスタンスがDirector に渡された場合は、 Director から呼ばれている makeTitle、makeJapanese、makeFlangs、close はすべてHtmlBuilder のものが使われ、HTML文書が出来上がることになります。 Builderパターンでは、Template Method パターンと違って、処理手順を変更できます。Director クラスの代わりに別の処理手順が書かれたクラスのインスタンスを生成すればよいからです。 それでは Director クラスを別のものに替えて見ましょう。 Director.java public class Director extends AbstractDirector {
private final String title = "中国語";
private final String japanese = "ありがとう";
private final String[] flangs = new String[] { "謝謝", "多謝", "唔該" };
public Director(AbstractBuilder builder) {
super(builder);
}
public void construct() {
builder.makeTitle(title + "の" + japanese);
builder.makeFlangs(flangs);
builder.close();
}
}
|
|
Builderパターンを使用しない例 AbstractContent.h #include <string>
class AbstractContent
{
protected:
static const std::string title;
static const std::string japanese[];
static const std::string flang[][5];
std::string buf;
virtual void makeTitle(const std::string) = 0;
virtual void makeJapanese(const std::string) = 0;
virtual void makeFlang(const std::string[], const int) = 0;
virtual void close(void) = 0;
public:
AbstractContent(void);
virtual ~AbstractContent(void);
void construct(void);
std::string get(void);
}; AbstractContent.cpp #include "AbstractContent.h"
using namespace std;
const string AbstractContent::title = "いろいろな国の言葉";
const string AbstractContent::japanese[] = {"こんにちは", "ありがとう"};
const string AbstractContent::flang[][5] = {
{"Hello","Bonjour","Guten Tag","Ciao","Hola"},
{"Thank you","Merci","Danke", "Grazie","Gracias"}
};
AbstractContent::AbstractContent(void) : buf("") {}
AbstractContent::~AbstractContent(void) {}
string AbstractContent::get(void) {
return buf;
}
void AbstractContent::construct(void) {
makeTitle(title);
for (int i = 0 ; i < sizeof(japanese) / sizeof(japanese[0]) ; i++) {
makeJapanese(japanese[i]);
makeFlang(flang[i], 5);
}
close();
} TextBuilder.h #include "AbstractContent.h"
class TextBuilder : public AbstractContent
{
protected:
void makeTitle(const std::string);
void makeJapanese(const std::string);
void makeFlang(const std::string[], const int);
void close(void);
public:
TextBuilder(void);
virtual ~TextBuilder(void);
}; TextBuilder.cpp #include "TextBuilder.h"
using namespace std;
TextBuilder::TextBuilder(void) {}
TextBuilder::~TextBuilder(void) {}
void TextBuilder::makeTitle(const string title) {
buf += "*** " + title + " ***\n\n";
}
void TextBuilder::makeJapanese(const string japanese) {
buf += " ■" + japanese + "\n";
}
void TextBuilder::makeFlang(const string flang[], const int size) {
for (int i = 0 ; i < size ; i++)
buf += " ○" + flang[i] + "\n";
}
void TextBuilder::close(void) {
buf += "(end)\n";
} HtmlBuilder.h #include "AbstractContent.h"
class HtmlBuilder : public AbstractContent
{
protected:
void makeTitle(const std::string);
void makeJapanese(const std::string);
void makeFlang(const std::string[], const int);
void close(void);
public:
HtmlBuilder(void);
virtual ~HtmlBuilder(void);
}; HtmlBuilder.cpp #include "HtmlBuilder.h"
using namespace std;
HtmlBuilder::HtmlBuilder(void) {}
HtmlBuilder::~HtmlBuilder(void) {}
void HtmlBuilder::makeTitle(const string title) {
buf += "<html>\n<head>\n<title>" + title + "</title>\n</head>\n<body>\n";
buf += "<h3>" + title + "</h3>\n";
}
void HtmlBuilder::makeJapanese(const string japanese) {
buf += "<span>" + japanese + "</span>\n";
}
void HtmlBuilder::makeFlang(const string flang[], const int size) {
buf += "<ul>\n";
for (int i = 0 ; i < size ; i++)
buf += "<li>" + flang[i] + "</li>\n";
buf += "</ul>\n";
}
void HtmlBuilder::close(void) {
buf += "</body>\n</html>\n";
}
Main.cpp #include <iostream>
using namespace std;
#include "TextBuilder.h"
#include "HtmlBuilder.h"
int main() {
TextBuilder txt;
txt.construct();
cout << txt.get();
HtmlBuilder htm;
htm.construct();
cout << htm.get();
return 0;
}
|
Builderパターンを使用した例 AbstractDirector.h #include <string>
#include "AbstractBuilder.h"
class AbstractDirector
{
protected:
AbstractBuilder* builder;
public:
AbstractDirector(void);
AbstractDirector(AbstractBuilder*);
virtual ~AbstractDirector(void);
virtual void construct(void) = 0;
}; AbstractDirector.cpp #include "AbstractDirector.h"
using namespace std;
AbstractDirector::AbstractDirector(void) {}
AbstractDirector::AbstractDirector(AbstractBuilder* builder) : builder(builder) {}
AbstractDirector::~AbstractDirector(void) {}
Director.h #include <string>
#include "AbstractDirector.h"
#include "AbstractBuilder.h"
class Director : public AbstractDirector
{
protected:
static const std::string title;
static const std::string japanese[];
static const std::string flang[][5];
public:
Director(void);
Director(AbstractBuilder*);
virtual ~Director(void);
void construct(void);
}; Director.cpp #include "Director.h"
using namespace std;
const string Director::title = "いろいろな国の言葉";
const string Director::japanese[] = {"こんにちは", "ありがとう"};
const string Director::flang[][5] = {
{"Hello","Bonjour","Guten Tag","Ciao","Hola"},
{"Thank you","Merci","Danke", "Grazie","Gracias"}
};
Director::Director(void) {}
Director::Director(AbstractBuilder* builder) : AbstractDirector(builder) {}
Director::~Director(void) {}
void Director::construct(void) {
builder->makeTitle(title);
for (int i = 0 ; i < 2 ; i++) {
builder->makeJapanese(japanese[i]);
builder->makeFlang(flang[i], 5);
}
builder->close();
} TextBuilder.h #include "AbstractBuilder.h"
class TextBuilder : public AbstractBuilder
{
public:
TextBuilder(void);
virtual ~TextBuilder(void);
void makeTitle(const std::string);
void makeJapanese(const std::string);
void makeFlang(const std::string[], const int);
void close(void);
}; TextBuilder.cpp #include "TextBuilder.h"
using namespace std;
TextBuilder::TextBuilder(void) {}
TextBuilder::~TextBuilder(void) {}
void TextBuilder::makeTitle(const string title) {
buf += "*** " + title + " ***\n\n";
}
void TextBuilder::makeJapanese(const string japanese) {
buf += "<span>" + japanese + "</span>\n";
}
void TextBuilder::makeFlang(const string flang[], const int size) {
for (int i = 0 ; i < size ; i++)
buf += " ○" + flang[i] + "\n";
}
void TextBuilder::close(void) {
buf += "(end)\n";
} HtmlBuilder.h #include "builder.h"
class HtmlBuilder : public AbstractBuilder
{
public:
HtmlBuilder(void);
virtual ~HtmlBuilder(void);
void makeTitle(const std::string);
void makeJapanese(const std::string);
void makeFlang(const std::string[], const int);
void close(void);
}; HtmlBuilder.cpp #include "HtmlBuilder.h"
using namespace std;
HtmlBuilder::HtmlBuilder(void) {}
HtmlBuilder::~HtmlBuilder(void) {}
void HtmlBuilder::makeTitle(const string title) {
buf += "<html>\n<head>\n<title>" + title + "</title>\n</head>\n<body>\n";
buf += "<h3>" + title + "</h3>\n";
}
void HtmlBuilder::makeJapanese(const string japanese) {
buf += "<span>" + japanese + "</span>\n";
}
void HtmlBuilder::makeFlang(const string flang[], const int size) {
buf += "<ul>\n";
for (int i = 0 ; i < size ; i++)
buf += "<li>" + flang[i] + "</li>\n";
buf += "</ul>\n";
}
void HtmlBuilder::close(void) {
buf += "</body>\n</html>\n";
} Main.cpp #include <iostream>
using namespace std;
#include "Director.h"
#include "TextBuilder.h"
#include "HtmlBuilder.h"
int main() {
TextBuilder txt;
Director dt(&txt);
dt.construct();
cout << txt.get();
HtmlBuilder htm;
Director dh(&htm);
dh.construct();
cout << htm.get();
return 0;
}
|
|
この例は Template Method パターンで書かれています。 処理の枠組みを記述したスーパークラスが AbstractContent で、それを継承して処理の具体的内容を記述したのが TextBuilder と HtmlBuilder です。インスタンスの生成はTextBuilder と HtmlBuilder について行われ、それらのクラスにある、AbstractContent から継承した construct() メソッドを呼び出しています。 しかし、 TextBuilder と HtmlBuilder は、処理手順の書かれたAbstractContentのサブクラスとして作成されていますので、処理手順と表現方法を自由に組み合わせたり変更したりができません。 例えば、HTML文章を今は「処理手順1」で出していたけど、次は「処理手順5」で出そうというようなことができないわけです。 処理手順であるAbstractContent を継承して、TextBuilder はプレーンテキストで出す、HtmlBuilder はHTMLで出す、としているので、処理手順は変更できないのです。 |
「作成過程」を決定する Director と呼ばれるものと「表現形式」を決定する builder と呼ばれるものを組み合わせて実現しています。 Template Method パターンと同様、 Director には処理の枠組み(construct)が記述されており、 builder には処理の具体的内容(makeJapanese、makeFlang)が記述されています。 ただし、 Template Method パターンと異なるところは、インスタンスの生成が両方について行われることです。まず、builder を継承した TextBuilder や HtmlBuilder のインスタンスが生成され、Director のインスタンス生成時にそれらが引き渡されます。そして、 Director クラスの construct() メソッドを呼び出します。 そして、引き渡されたTextBuilder や HtmlBuilder のインスタンスに従った文書が作成されるわけです。例えば、HtmlBuilder のインスタンスがDirector に渡された場合は、 Director から呼ばれている makeTitle、makeJapanese、makeForeign、close はすべてHtmlBuilder のものが使われ、HTML文書が出来上がることになります。 builderパターンでは、template Method パターンと違って、処理手順を変更できます。Director クラスの代わりに別の処理手順が書かれたクラスのインスタンスを生成すればよいからです。 それでは Director クラスを別のものに替えて見ましょう。 Director.h #include <string>
#include "AbstractDirector.h"
#include "AbstractBuilder.h"
class Director : public AbstractDirector {
private:
static const std::string title;
static const std::string japanese;
static const std::string flang[2];
public:
Director();
Director(AbstractBuilder*);
virtual ~Director();
void construct(void);
}; Director.cpp #include "Director.h"
using namespace std;
const string title = "中国語";
const string japanese = "ありがとう";
const string flangs[] = { "謝謝", "多謝", "唔該" };
Director::Director(void) {}
Director::Director(AbstractBuilder* builder) : AbstractDirector(builder) {}
Director::~Director() {}
void Director::construct() {
builder->makeTitle(title + "の" + japanese);
builder->makeFlang(flangs, 3);
builder->close();
}
|
|
Builderパターンを使用しない例 AbstractContent.cs abstract class AbstractContent
{
protected string buf;
protected string title = "いろいろな国の言葉";
protected string[] japanese = { "こんにちは", "ありがとう" };
protected string[][] flang =
{
new string[] {"Hello","Bonjour","Guten Tag", "Ciao","Hola"},
new string[] {"Thank you", "Merci", "Danke", "Grazie", "Gracias"}
};
protected abstract void MakeTitle(string title);
protected abstract void MakeJapanese(string japanese);
protected abstract void MakeFlang(string[] flang);
protected abstract void Close();
public string GetContent()
{
return buf;
}
public void Construct()
{
MakeTitle(title);
for (int i = 0; i < japanese.Length; i++)
{
MakeJapanese(japanese[i]);
MakeFlang(buf[i]);
}
Close();
}
} TextBuilder.cs class TextBuilder : AbstractContent
{
protected override void MakeTitle(string title)
{
buf += "*** " + title + " ***\n";
}
protected override void MakeJapanese(string japanese)
{
buf += "■" + japanese + "\n";
}
protected override void MakeFlang(string[] flang)
{
for (int i = 0; i < flang.Length; i++)
{
buf += " ○" + flang[i] + "\n";
}
}
protected override void Close()
{
buf += "(end)\n";
}
} HtmlBuilder.cs class HtmlBuilder : AbstractContent
{
protected override void MakeTitle(string title)
{
buf += "<html>\n<head>\n";
buf += "<title>" + title + "</title>\n"
+ "</head>\n<body>\n"
+ "<h3>" + title + "</h3>\n";
}
protected override void MakeJapanese(string japanese)
{
buf += " ■" + japanese + "\n";
}
protected override void MakeFlang(string[] flang)
{
buf += "<ul>\n";
for (int i = 0; i < flang.Length; i++)
{
buf += "<li>" + flang[i] + "</li>\n";
}
buf += "</ul>\n";
}
protected override void Close()
{
buf += "</body>\n</html>\n";
}
} Program.cs class Program
{
static void Main(string[] args)
{
TextBuilder txt = new TextBuilder();
txt.Construct();
Console.WriteLine(txt.GetContent());
HtmlBuilder htm = new HtmlBuilder();
htm.Construct();
Console.WriteLine(htm.GetContent());
}
}
|
Builderパターンを使用した例 AbstractDirector.cs abstract class AbstractDirector
{
protected AbstractBuilder builder;
public AbstractDirector() { }
public AbstractDirector(AbstractBuilder builder)
{
this.builder = builder;
}
public abstract void Construct();
} Director.cs class Director : AbstractDirector
{
private string title = "いろいろな国の言葉";
private string[] japanese = { "こんにちは", "ありがとう" };
private string[][] flang = new string[][]
{
new string[] {"Hello", "Bonjour", "Guten Tag", "Ciao", "Hola"},
new string[] {"Thank you", "Merci", "Danke", "Grazie", "Gracias"}
};
public Director(AbstractBuilder builder) : base(builder) { }
public override void Construct()
{
builder.MakeTitle(title);
for (int i = 0; i < japanese.Length; i++)
{
builder.MakeJapanese(japanese[i]);
builder.MakeFlang(flang[i]);
}
builder.Close();
}
} AbstractBuilder.cs abstract class AbstractBuilder
{
protected string buf;
public abstract void MakeTitle(string title);
public abstract void MakeJapanese(string japanese);
public abstract void MakeFlang(string[] flang);
public abstract void Close();
public string GetContent()
{
return buf;
}
} TextBuilder.cs class TextBuilder : AbstractBuilder
{
public override void MakeTitle(string title)
{
buf += "*** " + title + " ***\n";
}
public override void MakeJapanese(string japanese)
{
buf += "<span>" + japanese + "</span>\n";
}
public override void MakeFlang(string[] flang)
{
for (int i = 0; i < flang.Length; i++)
{
buf += " ○" + flang[i] + "\n";
}
}
public override void Close()
{
buf += "(end)\n";
}
} HtmlBuilder.cs class HtmlBuilder : AbstractBuilder
{
public override void MakeTitle(string title)
{
buf += "<html>\n<head>\n";
buf += "<title>" + title + "</title>\n"
+ "</head>\n<body>\n"
+ "<h3>" + title + "</h3>\n";
}
public override void MakeJapanese(string japanese)
{
buf += "■" + japanese + "\n";
}
public override void MakeFlang(string[] flang)
{
buf += "<ul>\n";
for (int i = 0; i < flang.Length; i++)
{
buf += "<li>" + flang[i] + "</li>\n";
}
buf += "</ul>\n";
}
public override void Close()
{
buf += "</body>\n</html>\n";
}
} Program.cs class Program
{
static void Main(string[] args)
{
Director director;
TextBuilder text = new TextBuilder();
director = new Director(text);
director.Construct();
Console.WriteLine(text.GetContent());
HtmlBuilder htm = new HtmlBuilder();
director = new Director(htm);
director.Construct();
Console.WriteLine(htm.GetContent());
}
}
|
|
この例は Template Method パターンで書かれています。 処理の枠組みを記述したスーパークラスが AbstractContent で、それを継承して処理の具体的内容を記述したのが TextBuilder と HtmlBuilder です。インスタンスの生成はTextBuilder と HtmlBuilder について行われ、それらのクラスにある、AbstractContent から継承した construct() メソッドを呼び出しています。 しかし、 TextBuilder と HtmlBuilder は、処理手順の書かれた AbstractContent のサブクラスとして作成されていますので、処理手順と表現方法を自由に組み合わせたり変更したりができません。 例えば、HTML文章を今は「処理手順1」で出していたけど、次は「処理手順5」で出そうというようなことができないわけです。 処理手順である AbstractContent を継承して、TextBuilder はプレーンテキストで出す、HtmlBuilder はHTMLで出す、としているので、処理手順は変更できないのです。 |
「作成過程」を決定する Director と呼ばれるものと「表現形式」を決定する Builder と呼ばれるものを組み合わせて実現しています。 Template Method パターンと同様、 Director には処理の枠組みが記述されており、 Builder には処理の具体的内容が記述されています。 ただし、 Template Method パターンと異なるところは、インスタンスの生成が両方について行われることです。まず、Builder を継承した TextBuilder や HtmlBuilder のインスタンスが生成され、Director のインスタンス生成時にそれらが引き渡されます。そして、 Director クラスの construct() メソッドを呼び出します。 そして、引き渡されたTextBuilder や HtmlBuilder のインスタンスに従った文書が作成されるわけです。例えば、 HtmlBuilder のインスタンスがDirector に渡された場合は、 Director から呼ばれている makeTitle、makeJapanese、makeFlangs、close はすべてHtmlBuilder のものが使われ、HTML文書が出来上がることになります。 Builderパターンでは、Template Method パターンと違って、処理手順を変更できます。Director クラスの代わりに別の処理手順が書かれたクラスのインスタンスを生成すればよいからです。 それでは Director クラスを別のものに替えて見ましょう。 Director.cs public class Director : AbstractDirector {
private string title = "中国語";
private string japanese = "ありがとう";
private string[] flangs = new string[] { "謝謝", "多謝", "唔該" };
public Director(AbstractBuilder builder) {
super(builder);
}
public override void Construct() {
builder.MakeTitle(title + "の" + japanese);
builder.MakeFlangs(flangs);
builder.Close();
}
}
|
|
Builderパターンを使用しない例 AbstractContent.vb Public MustInherit Class AbstractContent
Protected buf As String
Protected title As String = "いろいろな国の言葉"
Protected japanese As String() = {"こんにちは", "ありがとう"}
Protected flang As String()() = New String()() {
New String() {"Hello", "Bonjour", "Guten Tag", "Ciao", "Hola"},
New String() {"Thank you", "Merci", "Danke", "Grazie", "Gracias"}
}
protected MustOverride Sub MakeTitle(ByVal title As String)
protected MustOverride Sub MakeJapanese(ByVal japanese As String)
protected MustOverride Sub MakeFlang(ByVal flang As String())
protected MustOverride Sub Close()
Public Function GetContent() As String
Return buf
End Function
Public Sub Construct()
MakeTitle(title)
For i As Integer = 0 To japanese.Length - 1
MakeJapanese(japanese(i))
MakeFlang(flang(i))
Next
Close()
End Sub
End Class
TextBuilder.vb Public Class TextBuilder
Inherits AbstractContent
protected Overrides Sub MakeTitle(ByVal title As String)
buf &= "*** " & title & " ***" & ControlChars.CrLf
End Sub
protected Overrides Sub MakeJapanese(ByVal japanese As String)
buf &= " ■" & japanese & ControlChars.CrLf
End Sub
protected Overrides Sub MakeFlang(ByVal flang() As String)
For i As Integer = 0 To flang.Length - 1
buf &= " ○" & flang(i) & ControlChars.CrLf
Next
End Sub
protected Overrides Sub Close()
buf &= "(end)" & ControlChars.CrLf
End Sub
End Class
HtmlBuilder.vb Public Class HtmlBuilder
Inherits AbstractContent
protected Overrides Sub MakeTitle(ByVal title As String)
buf &= "<html>" & ControlChars.CrLf _
& "<head>" & ControlChars.CrLf _
& "<title>" & title & "</title>" & ControlChars.CrLf _
& "</head>" & ControlChars.CrLf _
& "<body>" & ControlChars.CrLf _
& "<h3>" & title & "</h3>" & ControlChars.CrLf
End Sub
protected Overrides Sub MakeJapanese(ByVal japanese As String)
buf &= " ■" & japanese & ControlChars.CrLf
End Sub
protected Overrides Sub MakeFlang(ByVal flang() As String)
buf &= "<ul>" & ControlChars.CrLf
For i As Integer = 0 To flang.Length - 1
buf &= "<li>" & flang(i) & "</li>" & ControlChars.CrLf
Next
buf &= "</ul>" & ControlChars.CrLf
End Sub
protected Overrides Sub Close()
buf &= "</body>" & ControlChars.CrLf &
"</html>" & ControlChars.CrLf
End Sub
End Class
Program.vb Module Main
Sub Main()
Dim txt As TextBuilder = New TextBuilder()
txt.Construct()
Console.WriteLine(txt.GetContent())
Dim htm As HtmlBuilder = New HtmlBuilder()
htm.Construct()
Console.WriteLine(htm.GetContent())
End Sub
End Module
|
Builderパターンを使用した例 AbstractDirector.vb Public MustInherit Class AbstractDirector
Protected builder As AbstractBuilder
Public Sub New()
End Sub
Public Sub New(builder As AbstractBuilder)
MeBase.New(builder)
End Sub
Public MustOverride Sub Construct()
End Class
Director.vb Public Class Director
Inherits AbstractBuilder
Protected title As String = "いろいろな国の言葉"
Protected japanese As String() = {"こんにちは", "ありがとう"}
Protected flang As String()() = New String()() {
New String() {"Hello", "Bonjour", "Guten Tag", "Ciao", "Hola"},
New String() {"Thank you", "Merci", "Danke", "Grazie", "Gracias"}
}
Public Sub New(ByVal builder As AbstractBuilder)
Me.builder = builder
End Sub
Public Overrides Sub Construct()
builder.MakeTitle(title)
For i As Integer = 0 To japanese.Length - 1
builder.MakeJapanese(japanese(i))
builder.MakeFlang(flang(i))
Next
builder.close()
End Sub
End Class
AbstractBuilder.vb Public MustInherit Class AbstractBuilder
Protected buf As String
Public MustOverride Sub MakeTitle(ByVal title As String)
Public MustOverride Sub MakeJapanese(ByVal japanese As String)
Public MustOverride Sub MakeFlang(ByVal flang As String())
Public MustOverride Sub Close()
Public Function GetContent() As String
Return buf
End Function
End Class
TextBuilder.vb Public Class TextBuilder
Inherits AbstractBuilder
Public Overrides Sub MakeTitle(ByVal title As String)
buf &= "*** " & title & " ***" & ControlChars.CrLf
End Sub
Public Overrides Sub MakeJapanese(ByVal japanese As String)
buf &= " ■" & japanese & ControlChars.CrLf
End Sub
Public Overrides Sub MakeFlang(ByVal flang() As String)
For i As Integer = 0 To flang.Length - 1
buf &= " ○" & flang(i) & ControlChars.CrLf
Next
End Sub
Public Overrides Sub Close()
buf &= "(end)" & ControlChars.CrLf
End Sub
End Class
HtmlBuilder.vb Public Class HtmlBuilder
Inherits AbstractBuilder
Public Overrides Sub MakeTitle(ByVal title As String)
buf &= "<html>" & ControlChars.CrLf _
& "<head>" & ControlChars.CrLf _
& "<title>" & title & "</title>" & ControlChars.CrLf _
& "</head>" & ControlChars.CrLf _
& "<body>" & ControlChars.CrLf _
& "<h3>" & title & "</h3>" & ControlChars.CrLf
End Sub
Public Overrides Sub MakeJapanese(ByVal japanese As String)
buf &= " ■" & japanese & ControlChars.CrLf
End Sub
Public Overrides Sub MakeFlang(ByVal flang() As String)
buf &= "<ul>" & ControlChars.CrLf
For i As Integer = 0 To flang.Length - 1
buf &= "<li>" & flang(i) & "</li>" & ControlChars.CrLf
Next
buf &= "</ul>" & ControlChars.CrLf
End Sub
Public Overrides Sub Close()
buf &= "</body>" & ControlChars.CrLf & "</html>" & ControlChars.CrLf
End Sub
End Class
Program.vb Module Main
Sub Main()
Dim director As AbstractDirector
Dim text As TextBuilder = New TextBuilder()
director = New Director(text)
director.Construct()
Console.WriteLine(text.GetContent())
Dim html As HtmlBuilder = New HtmlBuilder()
director = New Director(html)
director.Construct()
Console.WriteLine(html.GetContent())
End Sub
End Module
|
|
この例は Template Method パターンで書かれています。 処理の枠組みを記述したスーパークラスが AbstractContent で、それを継承して処理の具体的内容を記述したのが TextBuilder と HtmlBuilder です。インスタンスの生成はTextBuilder と HtmlBuilder について行われ、それらのクラスにある、AbstractContent から継承した construct() メソッドを呼び出しています。 しかし、 TextBuilder と HtmlBuilder は、処理手順の書かれたAbstractContentのサブクラスとして作成されていますので、処理手順と表現方法を自由に組み合わせたり変更したりができません。 例えば、HTML文章を今は「処理手順1」で出していたけど、次は「処理手順5」で出そうというようなことができないわけです。 処理手順であるAbstractContent を継承して、TextBuilder はプレーンテキストで出す、HtmlBuilder はHTMLで出す、としているので、処理手順は変更できないのです。 |
「作成過程」を決定する Director と呼ばれるものと「表現形式」を決定する builder と呼ばれるものを組み合わせて実現しています。 Template Method パターンと同様、 Director には処理の枠組み(construct)が記述されており、 builder には処理の具体的内容(makeJapanese、makeFlang)が記述されています。 ただし、 Template Method パターンと異なるところは、インスタンスの生成が両方について行われることです。まず、builder を継承した TextBuilder や HtmlBuilder のインスタンスが生成され、Director のインスタンス生成時にそれらが引き渡されます。そして、 Director クラスの construct() メソッドを呼び出します。 そして、引き渡されたTextBuilder や HtmlBuilder のインスタンスに従った文書が作成されるわけです。例えば、HtmlBuilder のインスタンスがDirector に渡された場合は、 Director から呼ばれている makeTitle、makeJapanese、makeForeign、close はすべてHtmlBuilder のものが使われ、HTML文書が出来上がることになります。 builderパターンでは、template Method パターンと違って、処理手順を変更できます。Director クラスの代わりに別の処理手順が書かれたクラスのインスタンスを生成すればよいからです。 それでは Director クラスを別のものに替えて見ましょう。 Director.vb Public Class Director
Inherits AbstractDirector
Private title As String = "中国語"
Private japanese As String = "ありがとう"
Private flangs As String() = New String() {"謝謝", "多謝", "唔該"}
Public Sub New(builder As AbstractBuilder)
MyBase.New(builder)
End Sub
Public Overrides Sub Construct()
builder.MakeTitle(title + "の" + japanese)
builder.MakeFlang(flangs)
builder.Close()
End Sub
End Class
|
|
Builderパターンを使用しない例 AbstractContent.js module.exports = class AbstractContent {
constructor() {
this.title = "いろいろな国の言葉";
this.japanese = [ "こんにちは", "ありがとう" ];
this.flangs = [
[ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ],
[ "Thank you", "Merci", "Danke", "Grazie", "Gracias" ]
];
}
construct() {
this.makeTitle(title);
for (let i = 0; i < this.japanese.length; i++) {
this.makeJapanese(this.japanese[i]);
this.makeFlangs(this.flangs[i]);
}
this.close();
}
makeTitle() {
console.log("makeTitle メソッドを定義してください。");
}
makeJapanese() {
console.log("makeJapanese メソッドを定義してください。");
}
makeFlangs() {
console.log("makeFlangs メソッドを定義してください。");
}
close() {
console.log("close メソッドを定義してください。");
}
get() {
return this.buf;
}
}
TextBuilder.js const AbstractContent = require("./AbstractContent.js");
module.exports = class TextBuilder extends AbstractContent {
makeTitle(title) {
this.buf = "*** " + title + " ***\n";
}
makeJapanese(japanese) {
this.buf += "■" + japanese + "\n";
}
makeFlangs(flangs) {
for (let i = 0; i < flangs.length; i++)
this.buf += " ○" + flangs[i] + "\n";
}
close() {
this.buf += "(end)\n";
}
}
HtmlBuilder.js const AbstractContent = require("./AbstractContent.js");
module.exports = class HtmlBuilder extends AbstractContent {
makeTitle(title) {
this.buf += "<html>\n<head>\n<title>" + title
+ "</title>\n</head>\n<body>\n";
this.buf += "<h3>" + title + "</h3>\n";
}
makeJapanese(String japanese) {
buf += "<span>" + japanese + "</span>\n";
}
makeFlangs(flangs) {
this.buf += "<ul>\n";
for (let i = 0; i < flangs.length; i++)
this.buf += "<li>" + flangs[i] + "</li>\n";
this.buf += "</ul>\n";
}
close() {
this.buf += "</body>\n</html>\n";
}
}
Main.js const TextBuilder = require("./TextBuilder.js");
const HtmlBuilder = require("./HtmlBuilder.js");
let txt = new TextBuilder();
txt.construct();
process.stdout.write(txt.get() + "\n");
let htm = new HtmlBuilder();
htm.construct();
process.stdout.write(htm.get() + "\n");
|
Builderパターンを使用した例 AbstractDirector.js module.exports = class AbstractDirector {
constructor(builder) {
this.builder = builder;
}
construct() { console.log("construct メソッドを定義してください。"); }
}
Director.js const AbstractDirector = require("./AbstractDirector.js");
module.exports = class Director extends AbstractDirector {
constructor(builder) {
super(builder);
this.title = "いろいろな国の言葉";
this.japanese = [ "こんにちは", "ありがとう" ];
this.flangs = [
[ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ],
[ "Thank you", "Merci", "Danke", "Grazie", "Gracias" ]
];
}
construct() {
this.builder.makeTitle(this.title);
for (let i = 0; i < this.japanese.length; i++) {
this.builder.makeJapanese(this.japanese[i]);
this.builder.makeFlangs(this.flangs[i]);
}
this.builder.close();
}
}
AbstractBuilder.js module.exports = class AbstractBuilder {
makeTitle() {
console.log("makeTitle メソッドを定義してください。");
}
makeJapanese() {
console.log("makeJapanese メソッドを定義してください。");
}
makeFlangs() {
console.log("makeFlangs メソッドを定義してください。");
}
close() {
console.log("close メソッドを定義してください。");
}
get() {
return this.buf;
}
}
TextBuilder.js const AbstractBuilder = require("./AbstractBuilder.js");
module.exports = class TextBuilder extends AbstractBuilder {
makeTitle(title) {
this.buf += "*** " + title + " ***\n";
}
makeJapanese(japanese) {
this.buf += "■" + japanese + "\n";
}
makeFlangs(flangs) {
for (let i = 0; i < flangs.length; i++)
this.buf += " ○" + flangs[i] + "\n";
}
close() {
this.buf += "(end)\n";
}
}
HtmlBuilder.js const AbstractBuilder = require("./AbstractBuilder.js");
module.exports = class HtmlBuilder extends AbstractBuilder {
makeTitle(title) {
this.buf += "<html>\n<head>\n<title>" + title
+ "</title>\n</head>\n<body>\n";
this.buf += "<h3>" + title + "</h3>\n";
}
makeJapanese(japanese) {
this.buf += "<span>" + japanese + "</span>\n";
}
makeFlangs(flangs) {
this.buf += "<ul>\n";
for (let i = 0; i < flangs.length; i++)
this.buf += "<li>" + flangs[i] + "</li>\n";
this.buf += "</ul>\n";
}
close() {
this.buf += "</body>\n</html>\n";
}
}
Main.js const TextBuilder = require("./TextBuilder.js");
const HtmlBuilder = require("./HtmlBuilder.js");
const Director = require("./Director.js");
let director = null;
let txt = new TextBuilder();
director = new Director(txt);
director.construct();
process.stdout.write(txt.get());
let htm = new HtmlBuilder();
director = new Director(htm);
director.construct();
process.stdout.write(htm.get());
|
|
この例は Template Method パターンで書かれています。 処理の枠組みを記述したスーパークラスが AbstractContent で、それを継承して処理の具体的内容を記述したのが TextBuilder と HtmlBuilder です。インスタンスの生成はTextBuilder と HtmlBuilder について行われ、それらのクラスにある、AbstractContent から継承した construct() メソッドを呼び出しています。 しかし、 TextBuilder と HtmlBuilder は、処理手順の書かれた AbstractContent のサブクラスとして作成されていますので、処理手順と表現方法を自由に組み合わせたり変更したりができません。 例えば、HTML文章を今は「処理手順1」で出していたけど、次は「処理手順5」で出そうというようなことができないわけです。 処理手順である AbstractContent を継承して、TextBuilder はプレーンテキストで出す、HtmlBuilder はHTMLで出す、としているので、処理手順は変更できないのです。 |
「作成過程」を決定する Director と呼ばれるものと「表現形式」を決定する Builder と呼ばれるものを組み合わせて実現しています。 Template Method パターンと同様、 Director には処理の枠組みが記述されており、 Builder には処理の具体的内容が記述されています。 ただし、 Template Method パターンと異なるところは、インスタンスの生成が両方について行われることです。まず、Builder を継承した TextBuilder や HtmlBuilder のインスタンスが生成され、Director のインスタンス生成時にそれらが引き渡されます。そして、 Director クラスの construct() メソッドを呼び出します。 そして、引き渡されたTextBuilder や HtmlBuilder のインスタンスに従った文書が作成されるわけです。例えば、 HtmlBuilder のインスタンスがDirector に渡された場合は、 Director から呼ばれている makeTitle、makeJapanese、makeFlangs、close はすべてHtmlBuilder のものが使われ、HTML文書が出来上がることになります。 Builderパターンでは、Template Method パターンと違って、処理手順を変更できます。Director クラスの代わりに別の処理手順が書かれたクラスのインスタンスを生成すればよいからです。 それでは Director クラスを別のものに替えて見ましょう。 Director.js const AbstractDirector = require("./AbstractDirector.js");
module.exports = class Director extends AbstractDirector {
constructor(builder) {
super(builder);
this.title = "中国語";
this.japanese = "ありがとう";
this.flangs = [ "謝謝", "多謝", "唔該" ];
}
construct() {
this.builder.makeTitle(this.title + "の" + this.japanese);
this.builder.makeFlangs(this.flangs);
this.builder.close();
}
}
|
|
Builderパターンを使用しない例 AbstractContent.pm package AbstractContent {
sub new {
my ($class) = @_;
my ($this) = { title => "いろいろな国の言葉",
japanese => [ "こんにちは", "ありがとう" ];
flangs => [
[ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ],
[ "Thank you", "Merci", "Danke", "Grazie", "Gracias" ]
];
};
}
sub construct {
my ($this) = @_;
$this->makeTitle($this->{title});
my $n = @{$this->{japanese}};
for my $i ( 0 .. $n - 1 ) {
$this->makeJapanese(@{$this->{japanese}}[$i]);
$this->makeFlangs($this->{flangs}[$i]);
}
$this->close();
}
sub makeTitle { print "makeTitle メソッドを定義してください。"; }
sub makeJapanese { print "makeJapanese メソッドを定義してください。"; }
sub makeFlangs { print "makeFlangs メソッドを定義してください。"; }
sub close { print "close メソッドを定義してください。"; }
sub get {
my ($this) = @_;
return $this->{buf};
}
}
1;
TextBuilder.pm class TextBuilder {
use base qw(AbstractContent);
sub new {
my ($class) = @_;
my $this = $class->SUPER::new();
}
sub makeTitle {
my ($this, $title) = @_;
$this->{buf} = "*** ${title} ***\n";
}
sub makeJapanese {
my ($this, $japanese) = @_;
$this->{buf} .= "■${japanese}\n";
}
sub makeFlangs {
my ($this, $flangs) = @_;
my $n = @{$flangs};
for my $i ( 0 .. $n - 1 ) {
$this->{buf} .= " ○ @{$flangs}[$i]\n";
}
}
sub close {
my ($this) = @_;
$this->{buf} .= "(end)\n";
}
}
1;
HtmlBuilder.pm package HtmlBuilder {
use base qw(AbstractContent);
sub new {
my ($class) = @_;
my $this = $class->SUPER::new();
}
sub makeTitle {
my ($this, $title) = @_;
$this->{buf} = "<html>\n<head>\n<title>${title}</title>\n"
. "</head>\n<body>\n";
$this->{buf} .= "<h3>${title}</h3>\n";
}
sub makeJapanese {
my ($this, $japanese) = @_;
$this->{buf} .= "<span>$this->{$japanese}</span>\n";
}
sub makeFlangs {
my ($this, $flangs) = @_;
$this->{buf} .= "<ul>\n";
my $n = @{$flangs};
for my $i ( 0 .. $n - 1 ) {
$this->{buf} .= "<li>$this->{flangs}[$i]</li>\n";
$this->{buf} .= "</ul>\n";
}
sub close {
my ($this, $flangs) = @_;
$this->{buf} .= "</body>\n</html>\n";
}
}
1;
Main.pl use lib qw(./);
use TextBuilder;
use HtmlBuilder;
my $txt = new TextBuilder();
$txt->construct();
print $txt->get() . "\n";
my $htm = new HtmlBuilder();
$htm->construct();
print $htm->get() + "\n";
|
Builderパターンを使用した例 AbstractDirector.pm package AbstractDirector {
sub new {
my ($class, $builder) = @_;
my $this = { builder => $builder };
return bless $this, $class;
}
sub construct { print "construct メソッドを定義してください。"; }
}
1;
Director.pm package Director {
use base qw(AbstractDirector);
sub new {
my ($class, $builder) = @_;
my $this = $class->SUPER::new($builder);
$this->{title} = "いろいろな国の言葉";
$this->{japanese} = [ "こんにちは", "ありがとう" ];
$this->{flangs} = [
[ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ],
[ "Thank you", "Merci", "Danke", "Grazie", "Gracias" ]
];
return bless $this, $class;
}
sub construct {
my ($this) = @_;
$this->{builder}->makeTitle($this->{title});
my $n = @{$this->{japanese}};
for my $i (0 .. $n - 1) {
$this->{builder}->makeJapanese(@{$this->{japanese}}[$i]);
$this->{builder}->makeFlangs(@{$this->{flangs}}[$i]);
}
$this->{builder}->close();
}
}
1;
AbstractBuilder.pm package AbstractBuilder {
sub makeTitle { print "makeTitle メソッドを定義してください。"; }
sub makeJapanese { print "makeJapanese メソッドを定義してください。"; }
sub makeFlangs { print "makeFlangs メソッドを定義してください。"; }
sub close { print "close メソッドを定義してください。"; }
sub get {
my ($this) = @_;
return $this->{buf};
}
}
1;
TextBuilder.pm package TextBuilder {
use base qw(AbstractBuilder);
sub new {
my ($class) = @_;
return bless {}, $class;
}
sub makeTitle {
my ($class, title) = @_;
$this->{buf} = "*** ${title} ***\n";
}
sub makeJapanese {
my ($class, japanese) = @_;
$this->{buf} .= "■ ${japanese}\n";
}
sub makeFlangs {
my ($class, flangs) = @_;
my $n = @{$flangs};
for my $i ( 0 .. $n - 1 ) {
$this->{buf} .= " ○ @{$flangs}[$i]\n";
}
}
sub close {
my ($this) = @_;
$this->{buf} .= "(end)\n";
}
}
HtmlBuilder.pm package HtmlBuilder {
use base qw(AbstractBuilder);
sub new {
my ($class) = @_;
return bless {}, $class;
}
sub makeTitle {
my ($this, $title) = @_;
$this->{buf} = "<html>\n<head>\n<title>${title}</title>\n"
. "</head>\n<body>\n";
$this->{buf} .= "<h3>${title}</h3>\n";
}
sub makeJapanese {
my ($this, $japanese) = @_;
$this->{buf} .= "<span>${japanese}</span>\n";
}
sub makeFlangs {
my ($this, $flangs) = @_;
$this->{buf} .= "<ul>\n";
my $n = @{$flangs};
for my $i ( 0 .. $i - 1 ) {
$this->{buf} .= "<li>@{$flangs}[$i]</li>\n";
}
$this->{buf} .= "</ul>\n";
}
sub close {
my ($this) = @_;
$this->{buf} .= "</body>\n</html>\n";
}
}
1;
Main.pl use lib qw(./);
use Director;
use TextBuilder;
use HtmlBuilder;
my $director;
my $txt = new TextBuilder();
$director = new Director($txt);
$director->construct();
print txt->get() . "\n";
my $htm = new HtmlBuilder();
$director = new Director($htm);
$director->construct();
print $htm->get(); . "\n"
|
|
この例は Template Method パターンで書かれています。 処理の枠組みを記述したスーパークラスが AbstractContent で、それを継承して処理の具体的内容を記述したのが TextBuilder と HtmlBuilder です。インスタンスの生成はTextBuilder と HtmlBuilder について行われ、それらのクラスにある、AbstractContent から継承した construct() メソッドを呼び出しています。 しかし、 TextBuilder と HtmlBuilder は、処理手順の書かれた AbstractContent のサブクラスとして作成されていますので、処理手順と表現方法を自由に組み合わせたり変更したりができません。 例えば、HTML文章を今は「処理手順1」で出していたけど、次は「処理手順5」で出そうというようなことができないわけです。 処理手順である AbstractContent を継承して、TextBuilder はプレーンテキストで出す、HtmlBuilder はHTMLで出す、としているので、処理手順は変更できないのです。 |
「作成過程」を決定する Director と呼ばれるものと「表現形式」を決定する Builder と呼ばれるものを組み合わせて実現しています。 Template Method パターンと同様、 Director には処理の枠組みが記述されており、 Builder には処理の具体的内容が記述されています。 ただし、 Template Method パターンと異なるところは、インスタンスの生成が両方について行われることです。まず、Builder を継承した TextBuilder や HtmlBuilder のインスタンスが生成され、Director のインスタンス生成時にそれらが引き渡されます。そして、 Director クラスの construct() メソッドを呼び出します。 そして、引き渡されたTextBuilder や HtmlBuilder のインスタンスに従った文書が作成されるわけです。例えば、 HtmlBuilder のインスタンスがDirector に渡された場合は、 Director から呼ばれている makeTitle、makeJapanese、makeFlangs、close はすべてHtmlBuilder のものが使われ、HTML文書が出来上がることになります。 Builderパターンでは、Template Method パターンと違って、処理手順を変更できます。Director クラスの代わりに別の処理手順が書かれたクラスのインスタンスを生成すればよいからです。 それでは Director クラスを別のものに替えて見ましょう。 Director.pm package Director {
use base qw(AbstractDirector);
sub new {
my ($class, $builder) = @_;
my $this = $class->SUPER::new($builder);
$this->{title} = "中国語";
$this->{japanese} = "ありがとう";
$this->{flangs} = [ "謝謝", "多謝", "唔該" ];
return bless $this, $class;
}
sub construct {
my ($this) = @_;
$this->{builder}->makeTitle($this->{title} . "の" . $this->{japanese});
$this->{builder}->makeFlangs($this->{flangs});
$this->{builder}->close();
}
}
1;
|
|
Builderパターンを使用しない例 AbstractContent.rb class AbstractContent
def initialize()
@title = "いろいろな国の言葉";
@japanese = [ "こんにちは", "ありがとう" ];
@flangs = [
[ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ],
[ "Thank you", "Merci", "Danke", "Grazie", "Gracias" ]
]
end
def construct()
makeTitle(@title)
for i in 0..@japanese.length-1
makeJapanese(@japanese[i])
makeFlangs(@flangs[i])
end
close()
end
def makeTitle()
puts "makeTitle メソッドを定義してください。"
end
def makeJapanese()
puts "makeJapanese メソッドを定義してください。"
end
def makeFlangs()
puts "makeFlangs メソッドを定義してください。"
end
def close()
puts "close メソッドを定義してください。"
end
def get()
return @buf
end
end
TextBuilder.rb require './AbstractContent'
class TextBuilder < AbstractContent
def makeTitle(title)
@buf = "*** #{title} ***\n"
end
def makeJapanese(japanese)
@buf += "■#{japanese}\n"
end
def makeFlangs(flangs)
for i in 0..flangs.length-1
@buf += " ○#{flangs[i]}\n"
end
end
def close()
@buf += "(end)\n"
end
end
HtmlBuilder.rb require './AbstractContent'
class HtmlBuilder < AbstractContent {
def makeTitle(title) {
@buf += "<html>\n<head>\n<title>#{title}</title>\n</head>\n<body>\n" +
"<h3>#{title}</h3>\n"
end
def makeJapanese(japanese)
@buf += "<span>#{japanese}</span>\n"
end
def makeFlangs(flangs) {
@buf += "<ul>\n"
for i in 0..flangs.length - 1
@buf += "<li>#{flangs[i]}</li>\n"
end
@buf += "</ul>\n"
close()
@buf += "</body>\n</html>\n"
end
end
Main.rb require './TextBuilder'
require './HtmlBuilder'
txt = TextBuilder.new()
txt.construct()
puts txt.get()
let htm = HtmlBuilder.new()
htm.construct()
puts htm.get()
|
Builderパターンを使用した例 AbstractDirector.rb class AbstractDirector
def initialize(builder) {
@builder = builder;
end
def construct()
puts "construct メソッドを定義してください。"
end
end
Director.rb require './AbstractDirector'
class Director < AbstractDirector
def initialize(builder)
super(builder)
@title = "いろいろな国の言葉"
@japanese = [ "こんにちは", "ありがとう" ]
@flangs = [
[ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ],
[ "Thank you", "Merci", "Danke", "Grazie", "Gracias" ]
]
end
def construct()
@builder.makeTitle(@title)
for i in 0..@japanese.length-1
@builder.makeJapanese(@japanese[i])
@builder.makeFlangs(@flangs[i])
end
@builder.close()
end
end
AbstractBuilder.rb class AbstractBuilder
def makeTitle()
puts "makeTitle メソッドを定義してください。"
end
def makeJapanese()
puts "makeJapanese メソッドを定義してください。"
end
def makeFlangs()
puts "makeFlangs メソッドを定義してください。"
end
def close()
puts "close メソッドを定義してください。"
end
def get()
return @buf
end
end
TextBuilder.rb require './AbstractBuilder'
class TextBuilder < AbstractBuilder
def makeTitle(title)
@buf += "*** #{title} ***\n"
end
def makeJapanese(japanese)
@buf += "■#{japanese}\n"
end
def makeFlangs(flangs) {
for (let i = 0; i < flangs.length; i++)
@buf += " ○#{flangs[i]}\n"
end
def close() {
@buf += "(end)\n"
end
end
HtmlBuilder.js require './AbstractBuilder'
class HtmlBuilder < AbstractBuilder
def makeTitle(title)
@buf += "<html>\n<head>\n<title>#{title}</title>\n</head>\n<body>\n" +
"<h3>#{title}</h3>\n"
end
def makeJapanese(japanese)
@buf += "<span>#{japanese}</span>\n"
end
def makeFlangs(flangs) {
@buf += "<ul>\n"
for i in 0..flangs.length-1
@buf += "<li>#{flangs[i]}</li>\n"
end
@buf += "</ul>\n"
end
def close()
@buf += "</body>\n</html>\n"
end
end
Main.js require './Director'
require './TextBuilder'
require './HtmlBuilder'
txt = TextBuilder.new()
director = Director.new(txt)
director.construct()
puts txt.get()
htm = HtmlBuilder.new()
director = Director.new(htm)
director.construct()
puts htm.get()
|
|
この例は Template Method パターンで書かれています。 処理の枠組みを記述したスーパークラスが AbstractContent で、それを継承して処理の具体的内容を記述したのが TextBuilder と HtmlBuilder です。インスタンスの生成はTextBuilder と HtmlBuilder について行われ、それらのクラスにある、AbstractContent から継承した construct() メソッドを呼び出しています。 しかし、 TextBuilder と HtmlBuilder は、処理手順の書かれた AbstractContent のサブクラスとして作成されていますので、処理手順と表現方法を自由に組み合わせたり変更したりができません。 例えば、HTML文章を今は「処理手順1」で出していたけど、次は「処理手順5」で出そうというようなことができないわけです。 処理手順である AbstractContent を継承して、TextBuilder はプレーンテキストで出す、HtmlBuilder はHTMLで出す、としているので、処理手順は変更できないのです。 |
「作成過程」を決定する Director と呼ばれるものと「表現形式」を決定する Builder と呼ばれるものを組み合わせて実現しています。 Template Method パターンと同様、 Director には処理の枠組みが記述されており、 Builder には処理の具体的内容が記述されています。 ただし、 Template Method パターンと異なるところは、インスタンスの生成が両方について行われることです。まず、Builder を継承した TextBuilder や HtmlBuilder のインスタンスが生成され、Director のインスタンス生成時にそれらが引き渡されます。そして、 Director クラスの construct() メソッドを呼び出します。 そして、引き渡されたTextBuilder や HtmlBuilder のインスタンスに従った文書が作成されるわけです。例えば、 HtmlBuilder のインスタンスがDirector に渡された場合は、 Director から呼ばれている makeTitle、makeJapanese、makeFlangs、close はすべてHtmlBuilder のものが使われ、HTML文書が出来上がることになります。 Builderパターンでは、Template Method パターンと違って、処理手順を変更できます。Director クラスの代わりに別の処理手順が書かれたクラスのインスタンスを生成すればよいからです。 それでは Director クラスを別のものに替えて見ましょう。 Director.rb require './AbstractDirector'
class Director < AbstractDirector
def initialize(builder)
super(builder)
@title = "中国語"
@japanese = "ありがとう"
@flangs = [ "謝謝", "多謝", "唔該" ]
end
def construct()
@builder.makeTitle(@title + "の" + @japanese)
@builder.makeFlangs(@flangs)
@builder.close()
end
end
|
|
Builderパターンを使用しない例 AbstractContent.py from abc import ABCMeta, abstractmethod
class AbstractContent(metaclass=ABCMeta):
def __init__(self):
self.title = "いろいろな国の言葉"
self.japanese = [ "こんにちは", "ありがとう" ]
self.flangs = [
[ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ],
[ "Thank you", "Merci", "Danke", "Grazie", "Gracias" ]
]
def construct(self):
this.makeTitle(self.title)
for i in range(len(self.japanese)):
self.makeJapanese(self.japanese[i])
self.makeFlangs(self.flangs[i])
self.close()
@abstractmethod
def makeTitle(self):
pass
@abstractmethod
def makeJapanese(self):
pass
@abstractmethod
def makeFlangs(self):
pass
@abstractmethod
def close(self):
pass
def get(self):
return self.buf
TextBuilder.py from AbstractContent import AbstractContent
class TextBuilder(AbstractContent):
def makeTitle(self, title):
self.buf = "*** " + self.title + " ***\n"
def makeJapanese(self, japanese):
self.buf += "■" + japanese + "\n"
def makeFlangs(self, flangs):
for i in range(len(flangs)):
self.buf += " ○" + flangs[i] + "\n"
def close(self):
self.buf += "(end)\n"
HtmlBuilder.py from AbstractContent import AbstractContent
class HtmlBuilder(AbstractContent):
def makeTitle(self, title):
self.buf += "<html>\n<head>\n<title>" + self.title \
+ "</title>\n</head>\n<body>\n"
self.buf += "<h3>" + self.title + "</h3>\n"
def makeJapanese(self, japanese):
self.buf += "<span>" + japanese + "</span>\n"
def makeFlangs(self, flangs)
self.buf += "<ul>\n"
for i in range(len(flangs)):
self.buf += "<li>" + flangs[i] + "</li>\n"
self.buf += "</ul>\n"
def close(self):
self.buf += "</body>\n</html>\n"
Main.py from TextBuilder import TextBuilder
from HtmlBuilder import HtmlBuilder
txt = TextBuilder()
txt.construct()
print(txt.get())
htm = HtmlBuilder()
htm.construct()
print(htm.get())
|
Builderパターンを使用した例 AbstractDirector.py from abc import ABCMeta, abstractmethod
class AbstractDirector(metaclass=ABCMeta):
def __init__(self, builder):
self.builder = builder
@abstractmethod
def construct(self):
pass
Director.py from AbstractDirector import AbstractDirector
class Director(AbstractDirector):
def __init__(self, builder):
super().__init__(builder)
self.title = "いろいろな国の言葉"
self.japanese = [ "こんにちは", "ありがとう" ]
self.flangs = [
[ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ],
[ "Thank you", "Merci", "Danke", "Grazie", "Gracias" ]
]
def construct(self):
self.builder.makeTitle(self.title)
for i in range(len(self.japanese)):
self.builder.makeJapanese(self.japanese[i])
self.builder.makeFlangs(self.flangs[i])
self.builder.close()
AbstractBuilder.py from abc import ABCMeta, abstractmethod
class AbstractBuilder(metaclass=ABCMeta):
@abstractmethod
def makeTitle(self, title):
pass
@abstractmethod
def makeJapanese(self):
pass
@abstractmethod
def makeFlangs(self):
pass
@abstractmethod
def close(self):
pass
def get(self):
return self.buf
TextBuilder.py from AbstractBuilder import AbstractBuilder
class TextBuilder(AbstractBuilder):
def makeTitle(self, title):
self.buf += "*** " + title + " ***\n"
def makeJapanese(japanese):
self.buf += "■" + japanese + "\n"
def makeFlangs(flangs):
for i in range(len(flangs)):
self.buf += " ○" + flangs[i] + "\n"
def close(self):
self.buf += "(end)\n"
HtmlBuilder.py from AbstractBuilder import AbstractBuilder
class HtmlBuilder(AbstractBuilder):
def makeTitle(self, title):
self.buf += "<html>\n<head>\n<title>" + title \
+ "</title>\n</head>\n<body>\n"
self.buf += "<h3>" + title + "</h3>\n"
def makeJapanese(self, japanese):
self.buf += "<span>" + japanese + "</span>\n"
def makeFlangs(self, flangs):
self.buf += "<ul>\n"
for i in range(len(flangs)):
self.buf += "<li>" + flangs[i] + "</li>\n"
self.buf += "</ul>\n"
def close(self):
self.buf += "</body>\n</html>\n"
Main.py from TextBuilder import TextBuilder
from HtmlBuilder import HtmlBuilder
from Director import Director
txt = TextBuilder()
director = Director(txt)
director.construct()
print(txt.get())
htm = HtmlBuilder()
director = Director(htm)
director.construct()
print(htm.get())
|
|
この例は Template Method パターンで書かれています。 処理の枠組みを記述したスーパークラスが AbstractContent で、それを継承して処理の具体的内容を記述したのが TextBuilder と HtmlBuilder です。インスタンスの生成はTextBuilder と HtmlBuilder について行われ、それらのクラスにある、AbstractContent から継承した construct() メソッドを呼び出しています。 しかし、 TextBuilder と HtmlBuilder は、処理手順の書かれた AbstractContent のサブクラスとして作成されていますので、処理手順と表現方法を自由に組み合わせたり変更したりができません。 例えば、HTML文章を今は「処理手順1」で出していたけど、次は「処理手順5」で出そうというようなことができないわけです。 処理手順である AbstractContent を継承して、TextBuilder はプレーンテキストで出す、HtmlBuilder はHTMLで出す、としているので、処理手順は変更できないのです。 |
「作成過程」を決定する Director と呼ばれるものと「表現形式」を決定する Builder と呼ばれるものを組み合わせて実現しています。 Template Method パターンと同様、 Director には処理の枠組みが記述されており、 Builder には処理の具体的内容が記述されています。 ただし、 Template Method パターンと異なるところは、インスタンスの生成が両方について行われることです。まず、Builder を継承した TextBuilder や HtmlBuilder のインスタンスが生成され、Director のインスタンス生成時にそれらが引き渡されます。そして、 Director クラスの construct() メソッドを呼び出します。 そして、引き渡されたTextBuilder や HtmlBuilder のインスタンスに従った文書が作成されるわけです。例えば、 HtmlBuilder のインスタンスがDirector に渡された場合は、 Director から呼ばれている makeTitle、makeJapanese、makeFlangs、close はすべてHtmlBuilder のものが使われ、HTML文書が出来上がることになります。 Builderパターンでは、Template Method パターンと違って、処理手順を変更できます。Director クラスの代わりに別の処理手順が書かれたクラスのインスタンスを生成すればよいからです。 それでは Director クラスを別のものに替えて見ましょう。 Director.py from AbstractDirector import AbstractDirector
class Director(AbstractDirector):
def __init__(self, builder):
super.__init__(builder)
self.title = "中国語"
self.japanese = "ありがとう"
self.flangs = [ "謝謝", "多謝", "唔該" ]
def construct(self):
self.builder.makeTitle(self.title + "の" + self.japanese)
self.builder.makeFlangs(self.flangs)
self.builder.close()
|
|
Builderパターンを使用しない例 AbstractContent.php <?php
abstract class AbstractContent {
protected static $title = "いろいろな国の言葉";
protected static $japanese = ["こんにちは", "ありがとう"];
protected static $flangs = [
[ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ],
[ "Thank you", "Merci", "Danke", "Grazie", "Gracias" ]
];
protected abstract function makeTitle($title);
protected abstract function makeJapanese($japanese);
protected abstract function makeFlangs($flangs);
protected abstract function close();
public function get() {
return $this->buf;
}
public function construct() {
$this->makeTitle(self::$title);
for ($i = 0; $i < count(self::$japanese); $i++) {
$this->makeJapanese(self::$japanese[$i]);
$this->makeFlangs(self::$flangs[$i]);
}
$this->close();
}
}
?> TextBuilder.php <?php
require_once('AbstractContent.php');
class TextBuilder extends AbstractContent {
protected function makeTitle($title) {
$this->buf .= "*** " . $title . " ***\n";
}
protected function makeJapanese($japanese) {
$this->buf .= "■" . $japanese . "\n";
}
protected function makeFlangs($flangs) {
for ($i = 0; $i < count(flangs); $i++)
$this->buf .= " ○" . $flangs[$i] . "\n";
}
protected function close() {
$this->buf .= "(end)\n";
}
}
?> HtmlBuilder.php <?php
require_once('AbstractContent.php');
class HtmlBuilder extends AbstractContent {
protected function makeTitle($title) {
$this->buf .= "<html>\n<head>\n<title>" . $title
. "</title>\n</head>\n<body>\n";
$this->buf .= "<h3>" . $title . "</h3>\n";
}
protected function makeJapanese($japanese) {
$this->buf .= "<span>" + $japanese + "</span>\n";
}
protected function makeFlangs($flangs) {
$this->buf .= "<ul>\n";
for ($i = 0; $i < count($flangs); $i++)
$this->buf .= "<li>" . $flangs[$i] . "</li>\n";
$this->buf .= "</ul>\n";
}
protected function close() {
$this->buf .= "</body>\n</html>\n";
}
}
?> Main.php <?php
require_once('TextBuilder.php');
require_once('HtmlBuilder.php');
$txt = new TextBuilder();
$txt->construct();
print $txt->get();
$htm = new HtmlBuilder();
$htm->construct();
print $htm->get();
?>
|
Builderパターンを使用した例 AbstractDirector.php <?php
abstract class AbstractDirector {
public function __construct($builder) {
$this->builder = $builder;
}
public abstract function construct();
}
?> Director.php <?php
require_once('AbstractDirector.php');
class Director extends AbstractDirector {
private static $title = "いろいろな国の言葉";
private static $japanese = ["こんにちは", "ありがとう"];
private static $flangs = [
[ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ],
[ "Thank you", "Merci", "Danke", "Grazie", "Gracias" ]
];
public function __construct($builder) {
parent::__construct($builder);
}
public function construct() {
$this->builder->makeTitle(self::$title);
for ($i = 0; $i < count(self::japanese); $i++) {
$this->builder->makeJapanese(self::$japanese[$i]);
$this->builder->makeFlangs(self::$flangs[$i]);
}
$this->builder->close();
}
}
?> AbstractBuilder.php <?php
abstract class AbstractBuilder {
public abstract function makeTitle(String $title);
public abstract function makeJapanese(String $japanese);
public abstract function makeFlangs(String[] $flangs);
public abstract function close();
public String get() {
return $this->buf;
}
}
?> TextBuilder.php <?php
require_once('AbstractBuilder.php');
class TextBuilder extends AbstractBuilder {
public function makeTitle($title) {
$this->buf .= "*** " . title . " ***\n";
}
public function makeJapanese(String japanese) {
$this->buf .= "■" . japanese . "\n";
}
public function makeFlangs(String[] flangs) {
for ($i = 0; $i < count($flangs); $i++)
$this->buf .= " ○" . $flangs[$i] . "\n";
}
public function close() {
$this->buf .= "(end)\n";
}
}
?> HtmlBuilder.php <?php
require_once('AbstractBuilder.php');
class HtmlBuilder extends AbstractBuilder {
public function makeTitle($title) {
$this->buf .= "<html>\n<head>\n<title>" . $title
. "</title>\n</head>\n<body>\n";
$this->buf .= "<h3>" . $title . "</h3>\n";
}
public function makeJapanese($japanese) {
$this->buf .= "<span>" . $japanese . "</span>\n");
}
public function makeFlangs($flangs) {
$this->buf .= "<ul>\n";
for ($i = 0; $i < count($flangs); $i++)
$this->buf .= "<li>" + $flangs[$i] + "</li>\n";
$this->buf .= "</ul>\n";
}
public function close() {
$this->buf .= "</body>\n</html>\n";
}
}
?> Main.php <?php
require_once('TextBuilder.php');
require_once('HtmlBuilder.php');
require_once('Director.php');
$txt = new TextBuilder();
$director = new Director($txt);
$director->construct();
print $txt->get();
$htm = new HtmlBuilder();
$director = new Director($htm);
$director->construct();
print $htm->get();
?>
|
|
この例は Template Method パターンで書かれています。 処理の枠組みを記述したスーパークラスが AbstractContent で、それを継承して処理の具体的内容を記述したのが TextBuilder と HtmlBuilder です。インスタンスの生成はTextBuilder と HtmlBuilder について行われ、それらのクラスにある、AbstractContent から継承した construct() メソッドを呼び出しています。 しかし、 TextBuilder と HtmlBuilder は、処理手順の書かれた AbstractContent のサブクラスとして作成されていますので、処理手順と表現方法を自由に組み合わせたり変更したりができません。 例えば、HTML文章を今は「処理手順1」で出していたけど、次は「処理手順5」で出そうというようなことができないわけです。 処理手順である AbstractContent を継承して、TextBuilder はプレーンテキストで出す、HtmlBuilder はHTMLで出す、としているので、処理手順は変更できないのです。 |
「作成過程」を決定する Director と呼ばれるものと「表現形式」を決定する Builder と呼ばれるものを組み合わせて実現しています。 Template Method パターンと同様、 Director には処理の枠組みが記述されており、 Builder には処理の具体的内容が記述されています。 ただし、 Template Method パターンと異なるところは、インスタンスの生成が両方について行われることです。まず、Builder を継承した TextBuilder や HtmlBuilder のインスタンスが生成され、Director のインスタンス生成時にそれらが引き渡されます。そして、 Director クラスの construct() メソッドを呼び出します。 そして、引き渡されたTextBuilder や HtmlBuilder のインスタンスに従った文書が作成されるわけです。例えば、 HtmlBuilder のインスタンスがDirector に渡された場合は、 Director から呼ばれている makeTitle、makeJapanese、makeFlangs、close はすべてHtmlBuilder のものが使われ、HTML文書が出来上がることになります。 Builderパターンでは、Template Method パターンと違って、処理手順を変更できます。Director クラスの代わりに別の処理手順が書かれたクラスのインスタンスを生成すればよいからです。 それでは Director クラスを別のものに替えて見ましょう。 Director.php <?php
require_once('AbstractDirector.php');
class Director extends AbstractDirector {
protected static $title = "中国語";
protected static $japanese = "ありがとう";
protected static $flangs = ["謝謝", "多謝", "唔該"];
public function __construct($builder) {
parent::__construct($builder);
}
public function construct() {
$this->builder->makeTitle(self::$title . "の" . self::$japanese);
$this->builder->makeFlangs(self::$flangs);
$this->builder->close();
}
}
|
|
Builderパターンを使用しない例 AbstractContent.ts export
abstract class AbstractContent {
protected buf:string;
protected title:string = "いろいろな国の言葉";
protected japanese:string[] = ["こんにちは", "ありがとう"];
protected flangs:string[][] = [
[ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ],
[ "Thank you", "Merci", "Danke", "Grazie", "Gracias" ]
];
protected abstract makeTitle(title:string):void;
protected abstract makeJapanese(japanese:string):void;
protected abstract makeFlangs(flangs:string[]):void;
protected abstract close():void;
public get():string {
return this.buf;
}
public construct():void {
this.makeTitle(this.title);
for (let i:number = 0; i < this.japanese.length; i++) {
this.makeJapanese(this.japanese[i]);
this.makeFlangs(this.flangs[i]);
}
this.close();
}
}
TextBuilder.ts import {AbstractContent} from "./AbstractContent";
export
class TextBuilder extends AbstractContent {
protected makeTitle(title:string):void {
this.buf = "*** " + title + " ***\n";
}
protected makeJapanese(japanese:string):void {
this.buf += "■" + japanese + "\n";
}
protected makeFlangs(flangs:string[]):void {
for (let i:number = 0; i < flangs.length; i++)
buf + " ○" + flangs[i] + "\n";
}
protected close():void {
this.buf += "(end)\n";
}
}
HtmlBuilder.ts import {AbstractContent} from "./AbstractContent";
export
class HtmlBuilder extends AbstractContent {
protected makeTitle(title:string):void {
this.buf = "<html>\n<head>\n<title>" + title + "</title>\n</head>\n<body>\n";
this.buf += "<h3>" + title + "</h3>\n";
}
protected makeJapanese(japanese:string):void {
this.buf += "<span>" + japanese + "</span>\n";
}
protected makeFlangs(flangs:string[]):void {
this.buf += "<ul>\n";
for (i:number = 0; i < flangs.length; i++)
this.buf += "<li>" + flangs[i] + "</li>\n";
buf += "</ul>\n";
}
protected close():void {
this.buf += "</body>\n</html>\n";
}
}
Main.ts import {TextBuilder} from "./TextBuilder";
import {HtmlBuilder} from "./HtmlBuilder";
let txt:TextBuilder = new TextBuilder();
txt.construct();
process.stdout.write(txt.get());
let htm:HtmlBuilder = new HtmlBuilder();
htm.construct();
process.stdout.write(htm.get());
}
}
|
Builderパターンを使用した例 AbstractDirector.ts import {AbstractBuilder} from "./AbstractBuilder";
export
abstract class AbstractDirector {
protected builder:AbstractBuilder;
public constructor(builder:AbstractBuilder) {
this.builder = builder;
}
public abstract construct():void;
}
Director.ts import {AbstractDirector} from "./AbstractDirector";
import {AbstractBuilder} from "./AbstractBuilder";
export
class Director extends AbstractDirector {
private title:string = "いろいろな国の言葉";
private japanese:string[] = ["こんにちは", "ありがとう"];
private flangs:string[][] = [
[ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ],
[ "Thank you", "Merci", "Danke", "Grazie", "Gracias" ]
];
public constructor(builder:AbstractBuilder) {
super(builder);
}
public construct():void {
this.builder.makeTitle(this.title);
for (i:number = 0; i < this.japanese.length; i++) {
this.builder.makeJapanese(this.japanese[i]);
this.builder.makeFlangs(this.flangs[i]);
}
this.builder.close();
}
}
AbstractBuilder.ts export
abstract class AbstractBuilder {
protected buf:string;
public abstract makeTitle(title:string):void;
public abstract makeJapanese(japanese:string):void;
public abstract makeFlangs(flangs:string[]):void;
public abstract close():void;
public get():string {
return this.buf;
}
}
TextBuilder.ts import {AbstractBuilder} from "./AbstractBuilder";
export
class TextBuilder extends AbstractBuilder {
public makeTitle(title:string):void {
this.buf = "*** " + this.title + " ***\n";
}
public makeJapanese(japanese:string):void {
this.buf += "■" + japanese + "\n";
}
public makeFlangs(flangs:string[]):void {
for (let i:number = 0; i < flangs.length; i++)
this.buf += " ○" + flangs[i] + "\n";
}
public close():void {
buf += "(end)\n";
}
}
HtmlBuilder.ts import {AbstractBuilder} from "./AbstractBuilder";
export
class HtmlBuilder extends AbstractBuilder {
public makeTitle(title:string):void {
buf = "<html>\n<head>\n<title>" + title + "</title>\n</head>\n<body>\n";
buf += "<h3>" + title + "</h3>\n";
}
public makeJapanese(japanese:string):void {
buf += "<span>" + japanese + "</span>\n";
}
public makeFlangs(flangs:string[]):void {
buf += "<ul>\n";
for (i:number = 0; i < flangs.length; i++)
buf += "<li>" + flangs[i] + "</li>\n";
buf += "</ul>\n";
}
public close():void {
buf += "</body>\n</html>\n";
}
} Main.ts import {TextBuilder} from "./TextBuilder";
import {HtmlBuilder} from "./HtmlBuilder";
import {AbstractDirector} from "./AbstractDirector";
import {Director} from "./Director";
let director:AbstractDirector = null;
txt:TextBuilder = new TextBuilder();
director = new Director(txt);
director.construct();
process.stdout.write(txt.get());
let htm:HtmlBuilder = new HtmlBuilder();
director = new Director(htm);
director.construct();
process.stdout.write(htm.get());
|
|
この例は Template Method パターンで書かれています。 処理の枠組みを記述したスーパークラスが AbstractContent で、それを継承して処理の具体的内容を記述したのが TextBuilder と HtmlBuilder です。インスタンスの生成はTextBuilder と HtmlBuilder について行われ、それらのクラスにある、AbstractContent から継承した construct() メソッドを呼び出しています。 しかし、 TextBuilder と HtmlBuilder は、処理手順の書かれた AbstractContent のサブクラスとして作成されていますので、処理手順と表現方法を自由に組み合わせたり変更したりができません。 例えば、HTML文章を今は「処理手順1」で出していたけど、次は「処理手順5」で出そうというようなことができないわけです。 処理手順である AbstractContent を継承して、TextBuilder はプレーンテキストで出す、HtmlBuilder はHTMLで出す、としているので、処理手順は変更できないのです。 |
「作成過程」を決定する Director と呼ばれるものと「表現形式」を決定する Builder と呼ばれるものを組み合わせて実現しています。 Template Method パターンと同様、 Director には処理の枠組みが記述されており、 Builder には処理の具体的内容が記述されています。 ただし、 Template Method パターンと異なるところは、インスタンスの生成が両方について行われることです。まず、Builder を継承した TextBuilder や HtmlBuilder のインスタンスが生成され、Director のインスタンス生成時にそれらが引き渡されます。そして、 Director クラスの construct() メソッドを呼び出します。 そして、引き渡されたTextBuilder や HtmlBuilder のインスタンスに従った文書が作成されるわけです。例えば、 HtmlBuilder のインスタンスがDirector に渡された場合は、 Director から呼ばれている makeTitle、makeJapanese、makeFlangs、close はすべてHtmlBuilder のものが使われ、HTML文書が出来上がることになります。 Builderパターンでは、Template Method パターンと違って、処理手順を変更できます。Director クラスの代わりに別の処理手順が書かれたクラスのインスタンスを生成すればよいからです。 それでは Director クラスを別のものに替えて見ましょう。 Director.ts import {AbstractDirector} from "./AbstractDirector";
import {AbstractBuilder} from "./AbstractBuilder";
export
class Director extends AbstractDirector {
private title:string = "中国語";
private japanese:string = "ありがとう";
private flangs:string[] = ["謝謝", "多謝", "唔該"];
public constructor(builder:AbstractBuilder) {
super(builder);
}
public construct():void {
this.builder.makeTitle(this.title + "の" + this.japanese);
this.builder.makeFlangs(this.flangs);
this.builder.close();
}
}
|
|
Builderパターンを使用しない例 AbstractContent.swift public class AbstractContent {
internal var buf:String
internal let title:String = "いろいろな国の言葉"
internal let japanese:[String] = ["こんにちは", "ありがとう"]
internal let flangs:[[String]] = [
[ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ],
[ "Thank you", "Merci", "Danke", "Grazie", "Gracias" ]
]
internal func makeTitle(_ title:String) {
fatalError("makeTitle メソッドを定義してください。")
}
internal func makeJapanese(_ japanese:String) {
fatalError("makeJapanese メソッドを定義してください。")
}
internal func makeFlangs(_ flangs:[String]) {
fatalError("makeFlangs メソッドを定義してください。")
}
internal func close() {
fatalError("close メソッドを定義してください。")
}
public func get() -> String {
return buf
}
public func construct() {
makeTitle(title)
for i in 0..<japanese.count {
makeJapanese(japanese[i])
makeFlangs(flangs[i])
}
close()
}
}
TextBuilder.swift public class TextBuilder : AbstractContent {
internal override func makeTitle(_ title:String) {
buf = "*** " + title + " ***\n"
}
internal override func makeJapanese(_ japanese:String) {
buf += "■" + japanese + "\n"
}
internal override func makeFlangs(_ flangs:[String]) {
for i in 0..<flangs.count {
buf + " ○" + flangs[i] + "\n"
}
internal override func close() {
buf += "(end)\n"
}
}
HtmlBuilder.swift public class HtmlBuilder : AbstractContent {
internal override func makeTitle(_ title:String) {
buf = "<html>\n<head>\n<title>" + title + "</title>\n</head>\n<body>\n"
buf += "<h3>" + title + "</h3>\n"
}
internal override func makeJapanese(_ japanese:String) {
buf += "<span>" + japanese + "</span>\n"
}
internal override func makeFlangs(_ flangs:[String]) {
buf += "<ul>\n"
for i in 0..<flangs.count {
buf += "<li>" + flangs[i] + "</li>\n"
buf += "</ul>\n"
}
internal override func close() {
buf += "</body>\n</html>\n"
}
}
Main.swift let txt:TextBuilder = TextBuilder()
txt.construct()
print(txt.get())
let htm:HtmlBuilder = HtmlBuilder()
htm.construct()
print(htm.get())
}
}
|
Builderパターンを使用した例 AbstractDirector.swift public class AbstractDirector {
internal var builder:AbstractBuilder
public init(_ builder:AbstractBuilder) {
self.builder = builder
}
internal func construct() {
fatalError("construct メソッドを定義してください。")
}
}
Director.swift public class Director : AbstractDirector {
internal let title:String = "いろいろな国の言葉"
internal let japanese:[String] = ["こんにちは", "ありがとう"]
internal let flangs:[[String]] = [
[ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ],
[ "Thank you", "Merci", "Danke", "Grazie", "Gracias" ]
]
public override init(_ builder:AbstractBuilder) {
super.init(builder)
}
public override func construct() {
builder.makeTitle(title)
for i in 0..<japanese.count {
builder.makeJapanese(japanese[i])
builder.makeFlangs(flangs[i])
}
builder.close()
}
}
AbstractBuilder.swift public class AbstractBuilder {
internal var buf:String = ""
internal func makeTitle(_ title:String) {
fatalError("makeTitle メソッドを定義してください。")
}
internal func makeJapanese(_ japanese:String) {
fatalError("makeJapanese メソッドを定義してください。")
}
internal func makeFlangs(_ flangs:[String]) {
fatalError("makeFlangs メソッドを定義してください。")
}
internal func close() {
fatalError("close メソッドを定義してください。")
}
public func get() -> String {
return buf
}
}
TextBuilder.swift public class TextBuilder : AbstractBuilder {
internal override func makeTitle(_ title:String) {
buf = "*** " + title + " ***\n"
}
internal override func makeJapanese(_ japanese:String) {
buf += "■" + japanese + "\n"
}
internal override func makeFlangs(_ flangs:[String]) {
for i in 0..<flangs.count {
buf += " ○" + flangs[i] + "\n"
}
internal override func close() {
buf += "(end)\n"
}
}
HtmlBuilder.swift public class HtmlBuilder : AbstractBuilder {
internal override func makeTitle(_ title:String) {
buf = "<html>\n<head>\n<title>" + title + "</title>\n</head>\n<body>\n"
buf += "<h3>" + title + "</h3>\n"
}
internal override func makeJapanese(_ japanese:String) {
buf += "<span>" + japanese + "</span>\n"
}
internal override func makeFlangs(_ flangs:[String]) {
buf += "<ul>\n"
for i in 0..<flangs.count {
buf += "<li>" + flangs[i] + "</li>\n";
buf += "</ul>\n"
}
internal override func close() {
buf += "</body>\n</html>\n"
}
}
Main.swift var director:AbstractDirector
let txt:TextBuilder = TextBuilder();
director = Director(txt)
director.construct()
print(txt.get())
let htm:HtmlBuilder = HtmlBuilder()
director = Director(htm)
director.construct()
print(htm.get())
|
|
この例は Template Method パターンで書かれています。 処理の枠組みを記述したスーパークラスが AbstractContent で、それを継承して処理の具体的内容を記述したのが TextBuilder と HtmlBuilder です。インスタンスの生成はTextBuilder と HtmlBuilder について行われ、それらのクラスにある、AbstractContent から継承した construct() メソッドを呼び出しています。 しかし、 TextBuilder と HtmlBuilder は、処理手順の書かれた AbstractContent のサブクラスとして作成されていますので、処理手順と表現方法を自由に組み合わせたり変更したりができません。 例えば、HTML文章を今は「処理手順1」で出していたけど、次は「処理手順5」で出そうというようなことができないわけです。 処理手順である AbstractContent を継承して、TextBuilder はプレーンテキストで出す、HtmlBuilder はHTMLで出す、としているので、処理手順は変更できないのです。 |
「作成過程」を決定する Director と呼ばれるものと「表現形式」を決定する Builder と呼ばれるものを組み合わせて実現しています。 Template Method パターンと同様、 Director には処理の枠組みが記述されており、 Builder には処理の具体的内容が記述されています。 ただし、 Template Method パターンと異なるところは、インスタンスの生成が両方について行われることです。まず、Builder を継承した TextBuilder や HtmlBuilder のインスタンスが生成され、Director のインスタンス生成時にそれらが引き渡されます。そして、 Director クラスの construct() メソッドを呼び出します。 そして、引き渡されたTextBuilder や HtmlBuilder のインスタンスに従った文書が作成されるわけです。例えば、 HtmlBuilder のインスタンスがDirector に渡された場合は、 Director から呼ばれている makeTitle、makeJapanese、makeFlangs、close はすべてHtmlBuilder のものが使われ、HTML文書が出来上がることになります。 Builderパターンでは、Template Method パターンと違って、処理手順を変更できます。Director クラスの代わりに別の処理手順が書かれたクラスのインスタンスを生成すればよいからです。 それでは Director クラスを別のものに替えて見ましょう。 Director.swift class Director : AbstractDirector {
internal var title:String = "中国語"
internal let japanese:String = "ありがとう"
internal let flangs:String[] = ["謝謝", "多謝", "唔該"]
public override init(_ builder:AbstractBuilder) {
super.init(builder)
}
public override func construct() {
builder.makeTitle(title + "の" + japanese)
builder.makeFlangs(flangs)
builder.close()
}
}
|
|
Builderパターンを使用しない例 AbstractContent.kt abstract class AbstractContent {
protected var buf = StringBuffer()
protected var title = "いろいろな国の言葉"
protected var japanese = arrayOf("こんにちは", "ありがとう")
protected var flangs = arrayOf(
arrayOf( "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ),
arrayOf( "Thank you", "Merci", "Danke", "Grazie", "Gracias" )
)
protected abstract fun makeTitle(title: String)
protected abstract fun makeJapanese(japanese: String)
protected abstract fun makeFlangs(flangs: Array<String>)
protected abstract fun close()
fun get(): String {
return buf.toString()
}
open fun construct() {
makeTitle(title)
for (i in japanese.indices) {
makeJapanese(japanese[i])
makeFlangs(flangs[i])
}
close()
}
}
TextBuilder.kt class TextBuilder : AbstractContent() {
override fun makeTitle(title: String) {
buf.append("*** $title ***\n")
}
override fun makeJapanese(japanese: String) {
buf.append("■$japanese\n")
}
override fun makeFlangs(flangs: Array<String>) {
for (i in flangs.indices)
buf.append(" ○${flangs[i]}\n")
}
override fun close() {
buf.append("(end)\n")
}
}
HtmlBuilder.kt class HtmlBuilder : AbstractContent() {
protected fun makeTitle(title: String) {
buf.append("<html>\n<head>\n<title>$title</title>\n</head>\n<body>\n")
buf.append("<h3>$title</h3>\n")
}
protected fun makeJapanese(japanese: String) {
buf.append("<span>$japanese</span>\n")
}
protected fun makeFlangs(flangs: Array<String>) {
buf.append("<ul>\n")
for (i in flangs.indices)
buf.append("<li>"${flangs[i]}</li>\n")
buf.append("</ul>\n")
}
protected fun close(){
buf += "</body>\n</html>\n"
}
}
Main.kt fun main() {
val txt = TextBuilder()
txt.construct()
print(txt.get())
val htm = HtmlBuilder()
htm.construct()
print(htm.get())
}
|
Builderパターンを使用した例 AbstractDirector.kt abstract class AbstractDirector(open val builder:AbstractBuilder) {
abstract fun construct()
}
Director.kt class Director(override val builder: AbstractBuilder) : AbstractDirector(builder) {
private title = "いろいろな国の言葉";
private japanese = arrayOf("こんにちは", "ありがとう")
private flangs = arrayOf(
arrayOf("Hello", "Bonjour", "Guten Tag", "Ciao", "Hola"),
arrayOf("Thank you", "Merci", "Danke", "Grazie", "Gracias")
)
override fun construct() {
builder.makeTitle(title)
for (i in japanese.indices) {
builder.makeJapanese(japanese[i])
builder.makeFlangs(flangs[i])
}
builder.close()
}
}
AbstractBuilder.kt abstract class AbstractBuilder {
protected var buf = StringBuffer()
internal abstract fun makeTitle(title: String)
internal abstract fun makeJapanese(japanese: String)
internal abstract fun makeFlangs(flangs: Array<String>)
internal abstract fun close()
fun get(): String {
return buf.toString()
}
}
TextBuilder.kt class TextBuilder : AbstractBuilder() {
override fun makeTitle(title: String) {
buf.append("***$title ***\n")
}
override fun makeJapanese(japanese: String) {
buf.append("■$japanese\n")
}
override fun makeFlangs(flangs: Array<String>) {
for (i in flangs.indices)
buf.append(" ○${flangs[i]}\n")
}
override fun close() {
buf.append("(end)\n")
}
}
HtmlBuilder.kt class HtmlBuilder : AbstractBuilder() {
override fun makeTitle(title: String) {
buf.append("<html>\n<head>\n<title>$title</title>\n</head>\n<body>\n")
buf.append("<h3>$title</h3>\n")
}
override fun makeJapanese(japanese: String) {
buf.append("<span>$japanese</span>\n")
}
override fun makeFlangs(flangs: Array<String>) {
buf.append("<ul>\n")
for (i in flangs.indices)
buf.append("<li>${flangs[i]}</li>\n")
buf.append("</ul>\n")
}
override fun close() {
buf.append("</body>\n</html>\n")
}
}
Main.kt fun main() {
var director:AbstractDirector? = null
val txt = TextBuilder()
director = Director(txt)
director.construct()
print(txt.get())
val htm = HtmlBuilder()
director = Director(htm)
director.construct()
print(htm.get())
}
|
|
この例は Template Method パターンで書かれています。 処理の枠組みを記述したスーパークラスが AbstractContent で、それを継承して処理の具体的内容を記述したのが TextBuilder と HtmlBuilder です。インスタンスの生成はTextBuilder と HtmlBuilder について行われ、それらのクラスにある、AbstractContent から継承した construct() メソッドを呼び出しています。 しかし、 TextBuilder と HtmlBuilder は、処理手順の書かれた AbstractContent のサブクラスとして作成されていますので、処理手順と表現方法を自由に組み合わせたり変更したりができません。 例えば、HTML文章を今は「処理手順1」で出していたけど、次は「処理手順5」で出そうというようなことができないわけです。 処理手順である AbstractContent を継承して、TextBuilder はプレーンテキストで出す、HtmlBuilder はHTMLで出す、としているので、処理手順は変更できないのです。 |
「作成過程」を決定する Director と呼ばれるものと「表現形式」を決定する Builder と呼ばれるものを組み合わせて実現しています。 Template Method パターンと同様、 Director には処理の枠組みが記述されており、 Builder には処理の具体的内容が記述されています。 ただし、 Template Method パターンと異なるところは、インスタンスの生成が両方について行われることです。まず、Builder を継承した TextBuilder や HtmlBuilder のインスタンスが生成され、Director のインスタンス生成時にそれらが引き渡されます。そして、 Director クラスの construct() メソッドを呼び出します。 そして、引き渡されたTextBuilder や HtmlBuilder のインスタンスに従った文書が作成されるわけです。例えば、 HtmlBuilder のインスタンスがDirector に渡された場合は、 Director から呼ばれている makeTitle、makeJapanese、makeFlangs、close はすべてHtmlBuilder のものが使われ、HTML文書が出来上がることになります。 Builderパターンでは、Template Method パターンと違って、処理手順を変更できます。Director クラスの代わりに別の処理手順が書かれたクラスのインスタンスを生成すればよいからです。 それでは Director クラスを別のものに替えて見ましょう。 Director.kt class Director(override val builder: AbstractBuilder) : AbstractDirector(builder) {
private val title = "中国語"
private val japanese = "ありがとう"
private val flangs = arrayOf("謝謝", "多謝", "唔該")
override fun construct() {
builder.makeTitle("${title}の$japanese")
builder.makeFlangs(flangs)
builder.close()
}
}
|
|
Builderパターンを使用しない例 AbstractContent.scala abstract class AbstractContent {
protected var buf = new StringBuffer()
protected var title = "いろいろな国の言葉"
protected var japanese = Array[String]("こんにちは", "ありがとう")
protected var flangs = Array[Array[String]](
Array( "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ),
Array( "Thank you", "Merci", "Danke", "Grazie", "Gracias" )
)
protected def makeTitle(title: String)
protected def makeJapanese(japanese: String)
protected def makeFlangs(flangs: Array<String>)
protected def close()
def get(): String {
return buf.toString()
}
def construct() {
makeTitle(title)
for (i <- 0 until japanese.length) {
makeJapanese(japanese(i))
makeFlangs(flangs(i))
}
close()
}
}
TextBuilder.scala class TextBuilder extends AbstractContent() {
protected def makeTitle(title) {
buf.append("*** " + title + " ***\n")
}
protected def makeJapanese(japanese: String) {
buf.append("■" + japanese + "\n")
}
protected def makeFlangs(flangs: Array<String>) {
for (i <- 0 until flangs.length) {
buf.append(" ○" + flangs(i) + "\n")
}
protected def close() {
buf.append("(end)\n")
}
}
HtmlBuilder.scala class HtmlBuilder extends AbstractContent() {
protected extends makeTitle(title) {
buf.append("<html>\n<head>\n<title>" + title + "</title>\n</head>\n<body>\n")
buf.append("<h3>" + title + "</h3>\n")
}
protected fun makeJapanese(japanese: String) {
buf.append("<span>" + japanese + "</span>\n")
}
protected fun makeFlangs(flangs: Array<String>) {
buf.append("<ul>\n")
for (i <- 0 until flangs.length) {
buf.append("<li>" + flangs(i) + "</li>\n")
buf.append("</ul>\n")
}
protected fun close(){
buf += "</body>\n</html>\n"
}
}
Main.scala object Main {
def main(args: Array[String]) {
val txt = new TextBuilder()
txt.construct()
System.out.print(txt.get())
val htm = new HtmlBuilder()
htm.construct()
System.out.print(htm.get())
}
}
|
Builderパターンを使用した例 AbstractDirector.scala abstract class AbstractDirector(val builder: AbstractBuilder) {
def construct()
}
Director.scala class Director(builder: AbstractBuilder) extends AbstractDirector(builder) {
private val title = "いろいろな国の言葉";
private val japanese = Array[String] ("こんにちは", "ありがとう")
private val flangs = Array[Array[String]](
Array("Hello", "Bonjour", "Guten Tag", "Ciao", "Hola"),
Array("Thank you", "Merci", "Danke", "Grazie", "Gracias")
)
def construct() {
builder.makeTitle(title)
for (i <- 0 until japanese.length) {
builder.makeJapanese(japanese(i))
builder.makeFlangs(flangs(i))
}
builder.close()
}
}
AbstractBuilder.scala abstract class AbstractBuilder {
var buf = new StringBuffer()
def makeTitle(title: String)
def makeJapanese(japanese: String)
def makeFlangs(flangs: Array[String])
def close()
def get(): String = buf.toString()
}
}
TextBuilder.scala class TextBuilder extends AbstractBuilder() {
override def makeTitle(title: String) {
buf.append("***" + title + " ***\n")
}
override def makeJapanese(japanese: String) {
buf.append("■" + japanese + "\n")
}
override def makeFlangs(flangs: Array[String]) {
for (i <- 0 until flangs.length)
buf.append(" ○" + flangs(i) + "\n")
}
override def close() {
buf.append("(end)\n")
}
}
HtmlBuilder.scala class HtmlBuilder extends AbstractBuilder() {
override def makeTitle(title: String) {
buf.append("<html>\n<head>\n<title>" + title + "</title>\n</head>\n<body>\n")
buf.append("<h3>" + title + "</h3>\n")
}
override def makeJapanese(japanese: String) {
buf.append("<span>" + japanese + "</span>\n")
}
override def makeFlangs(flangs: Array<String>) {
buf.append("<ul>\n")
for (i <- 0 until flangs.length)
buf.append("<li>" + flangs(i) + "</li>\n")
buf.append("</ul>\n")
}
override def close() {
buf.append("</body>\n</html>\n")
}
}
Main.scala object Main {
def main(args: Array[String]) {
var director:AbstractDirector = null
val txt = new TextBuilder()
director = new Director(txt)
director.construct()
System.out.print(txt.get())
val htm = new HtmlBuilder()
director = new Director(htm)
director.construct()
System.out.print(htm.get())
}
}
|
|
この例は Template Method パターンで書かれています。 処理の枠組みを記述したスーパークラスが AbstractContent で、それを継承して処理の具体的内容を記述したのが TextBuilder と HtmlBuilder です。インスタンスの生成はTextBuilder と HtmlBuilder について行われ、それらのクラスにある、AbstractContent から継承した construct() メソッドを呼び出しています。 しかし、 TextBuilder と HtmlBuilder は、処理手順の書かれた AbstractContent のサブクラスとして作成されていますので、処理手順と表現方法を自由に組み合わせたり変更したりができません。 例えば、HTML文章を今は「処理手順1」で出していたけど、次は「処理手順5」で出そうというようなことができないわけです。 処理手順である AbstractContent を継承して、TextBuilder はプレーンテキストで出す、HtmlBuilder はHTMLで出す、としているので、処理手順は変更できないのです。 |
「作成過程」を決定する Director と呼ばれるものと「表現形式」を決定する Builder と呼ばれるものを組み合わせて実現しています。 Template Method パターンと同様、 Director には処理の枠組みが記述されており、 Builder には処理の具体的内容が記述されています。 ただし、 Template Method パターンと異なるところは、インスタンスの生成が両方について行われることです。まず、Builder を継承した TextBuilder や HtmlBuilder のインスタンスが生成され、Director のインスタンス生成時にそれらが引き渡されます。そして、 Director クラスの construct() メソッドを呼び出します。 そして、引き渡されたTextBuilder や HtmlBuilder のインスタンスに従った文書が作成されるわけです。例えば、 HtmlBuilder のインスタンスがDirector に渡された場合は、 Director から呼ばれている makeTitle、makeJapanese、makeFlangs、close はすべてHtmlBuilder のものが使われ、HTML文書が出来上がることになります。 Builderパターンでは、Template Method パターンと違って、処理手順を変更できます。Director クラスの代わりに別の処理手順が書かれたクラスのインスタンスを生成すればよいからです。 それでは Director クラスを別のものに替えて見ましょう。 Director.scala class Director(builder: AbstractBuilder) extends AbstractDirector(builder) {
private val title = "中国語"
private val japanese = "ありがとう"
private val flangs = Array[String]("謝謝", "多謝", "唔該")
def construct() {
builder.makeTitle(title + "の" + japanese)
builder.makeFlangs(flangs)
builder.close()
}
}
|
|
Builderパターンを使用しない例 AbstractContent.groovy abstract class AbstractContent {
protected StringBuffer buf = new StringBuffer()
protected final String title = "いろいろな国の言葉"
protected final String[] japanese = [ "こんにちは", "ありがとう" ]
protected final String[][] flangs = [
[ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ],
[ "Thank you", "Merci", "Danke", "Grazie", "Gracias" ] ]
abstract void makeTitle(String title)
abstract void makeJapanese(String japanese)
abstract void makeFlangs(String[] flangs)
abstract void close()
String get() {
return buf.toString()
}
void construct() {
makeTitle(title)
for (int i in 0..<japanese.length) {
makeJapanese(japanese[i])
makeFlangs(flangs[i])
}
close()
}
}
TextBuilder.groovy class TextBuilder extends AbstractContent {
void makeTitle(String title) {
buf.append("*** " + title + " ***\n")
}
void makeJapanese(String japanese) {
buf.append("■" + japanese + "\n")
}
void makeFlangs(String[] flangs) {
for (String flang in flangs)
buf.append(" ○" + flang + "\n")
}
void close() {
buf.append("(end)\n")
}
}
HtmlBuilder.groovy class HtmlBuilder extends AbstractContent {
void makeTitle(String title) {
buf.append("<html>\n<head>\n<title>" + title + "</title>\n</head>\n<body>\n")
buf.append("<h3>" + title + "</h3>\n")
}
void makeJapanese(String japanese) {
buf.append("<span>" + japanese + "</span>\n")
}
void makeFlangs(String[] flangs) {
buf.append("<ul>\n")
for (String flang in flangs)
buf.append("<li>" + flang + "</li>\n")
buf.append("</ul>\n")
}
void close() {
buf.append("</body>\n</html>\n")
}
}
Main.groovy class Main {
static void main(String[] args) {
TextBuilder txt = new TextBuilder()
txt.construct()
System.out.print(txt.get())
HtmlBuilder htm = new HtmlBuilder()
htm.construct()
System.out.print(htm.get())
}
}
|
Builderパターンを使用した例 AbstractDirector.groovy abstract class AbstractDirector {
protected AbstractBuilder builder
AbstractDirector() {}
AbstractDirector(AbstractBuilder builder) {
this.builder = builder
}
abstract void construct()
}
Director.groovy class Director extends AbstractDirector {
private final String title = "いろいろな国の言葉"
private final String[] japanese = new String[] {
"こんにちは", "ありがとう" }
private final String[][] flangs = [
[ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ],
[ "Thank you", "Merci", "Danke", "Grazie", "Gracias" ] ]
Director(AbstractBuilder builder) {
super(builder)
}
void construct() {
builder.makeTitle(title)
for (int i in 0..<japanese.length) {
builder.makeJapanese(japanese[i])
builder.makeFlangs(flangs[i])
}
builder.close()
}
}
AbstractBuilder.groovy abstract class AbstractBuilder {
protected StringBuffer buf = new StringBuffer()
abstract void makeTitle(String title)
abstract void makeJapanese(String japanese)
abstract void makeFlangs(String[] flangs)
abstract void close()
String get() {
return buf.toString()
}
}
TextBuilder.groovy class TextBuilder extends AbstractBuilder {
void makeTitle(String title) {
buf.append("*** " + title + " ***\n")
}
void makeJapanese(String japanese) {
buf.append("■" + japanese + "\n")
}
void makeFlangs(String[] flangs) {
for (String flang in flangs)
buf.append(" ○" + flang + "\n")
}
void close() {
buf.append("(end)\n")
}
}
HtmlBuilder.groovy class HtmlBuilder extends AbstractBuilder {
void makeTitle(String title) {
buf.append("<html>\n<head>\n<title>" + title + "</title>\n</head>\n<body>\n")
buf.append("<h3>" + title + "</h3>\n")
}
void makeJapanese(String japanese) {
buf.append("<span>" + japanese + "</span>\n")
}
void makeFlangs(String[] flangs) {
buf.append("<ul>\n")
for (String flang in flangs)
buf.append("<li>" + flang + "</li>\n")
buf.append("</ul>\n")
}
void close() {
buf.append("</body>\n</html>\n")
}
}
Main.groovy class Main {
public static void main(String[] args) {
AbstractDirector director = null
TextBuilder txt = new TextBuilder()
director = new Director(txt)
director.construct()
System.out.print(txt.get())
HtmlBuilder htm = new HtmlBuilder()
director = new Director(htm)
director.construct()
System.out.print(htm.get())
}
}
|
|
この例は Template Method パターンで書かれています。 処理の枠組みを記述したスーパークラスが AbstractContent で、それを継承して処理の具体的内容を記述したのが TextBuilder と HtmlBuilder です。インスタンスの生成はTextBuilder と HtmlBuilder について行われ、それらのクラスにある、AbstractContent から継承した construct() メソッドを呼び出しています。 しかし、 TextBuilder と HtmlBuilder は、処理手順の書かれた AbstractContent のサブクラスとして作成されていますので、処理手順と表現方法を自由に組み合わせたり変更したりができません。 例えば、HTML文章を今は「処理手順1」で出していたけど、次は「処理手順5」で出そうというようなことができないわけです。 処理手順である AbstractContent を継承して、TextBuilder はプレーンテキストで出す、HtmlBuilder はHTMLで出す、としているので、処理手順は変更できないのです。 |
「作成過程」を決定する Director と呼ばれるものと「表現形式」を決定する Builder と呼ばれるものを組み合わせて実現しています。 Template Method パターンと同様、 Director には処理の枠組みが記述されており、 Builder には処理の具体的内容が記述されています。 ただし、 Template Method パターンと異なるところは、インスタンスの生成が両方について行われることです。まず、Builder を継承した TextBuilder や HtmlBuilder のインスタンスが生成され、Director のインスタンス生成時にそれらが引き渡されます。そして、 Director クラスの construct() メソッドを呼び出します。 そして、引き渡されたTextBuilder や HtmlBuilder のインスタンスに従った文書が作成されるわけです。例えば、 HtmlBuilder のインスタンスがDirector に渡された場合は、 Director から呼ばれている makeTitle、makeJapanese、makeFlangs、close はすべてHtmlBuilder のものが使われ、HTML文書が出来上がることになります。 Builderパターンでは、Template Method パターンと違って、処理手順を変更できます。Director クラスの代わりに別の処理手順が書かれたクラスのインスタンスを生成すればよいからです。 それでは Director クラスを別のものに替えて見ましょう。 Director.groovy class Director extends AbstractDirector {
private final String title = "中国語"
private final String japanese = "ありがとう"
private final String[] flangs = [ "謝謝", "多謝", "唔該" ]
Director(AbstractBuilder builder) {
super(builder)
}
void construct() {
builder.makeTitle(title + "の" + japanese)
builder.makeFlangs(flangs)
builder.close()
}
}
|
|
Builderパターンを使用しない例 AbstractContent.go import "errors"
type IBuilder interface {
MakeTitle(string)
MakeJapanese(string)
MakeFlangs([]string)
Close()
}
type AbstractContent struct {
buf string
title string
japanese = []string
flangs = [][]string
}
func (*AbstractContent) MakeTitle(title string) {
panic(errors.New("MakeTitle メソッドを定義してください。"))
}
func (*AbstractContent) MakeJapanese(japanese) {
panic(errors.New("MakeJapanese メソッドを定義してください。"))
}
func (*AbstractContent) MakeFlangs(String[] flangs) {
panic(errors.New("MakeFlangs メソッドを定義してください。"))
}
func (*AbstractContent) Close() {
panic(errors.New("Close メソッドを定義してください。"))
}
func (self *AbstractContent) Get() string {
return self.buf
}
func (self *AbstractContent) Construct(builder IBuilder) {
builder.MakeTitle(self.title)
for i:=0; i<len(japanese); i++ {
builder.MakeJapanese(self.japanese[i])
builder.MakeFlangs(self.flangs[i])
}
builder.Close()
}
func NewAbstractContent() *AbstractContent {
return &AbstractContent {
title: "いろいろな国の言葉",
japanese: []string {"こんにちは", "ありがとう"},
flangs: [][]string {
{ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" },
{ "Thank you", "Merci", "Danke", "Grazie", "Gracias" },
},
}
}
TextBuilder.go type TextBuilder struct {
IBuilder
*AbstractContent
}
func (self *TextBuilder) MakeTitle(title string) {
self.buf += "*** " += title + " ***\n"
}
func (self *TextBuilder) MakeJapanese(japanese string) {
buf. += "■" + japanese + "\n"
}
func (self *TextBuilder) MakeFlangs(flangs []string) {
for i:=0; i<len(flangs); i++ {
buf *= " ○" + flangs[i] + "\n"
}
}
func (self *TextBuilder) Close() {
buf += "(end)\n"
}
func NewTextBuilder() *TextBuilder {
return &TextBuilder {
AbstractContent : NewAbstractContent(),
}
}
HtmlBuilder.go type HtmlBuilder struct {
IBuilder
*AbstractContent
}
func (self *HtmlBuilder) MakeTitle(title string) {
self.buf += "<html>\n<head>\n<title>" + title + "</title>\n</head>\n<body>\n"
self.buf += "<h3>" + title + "</h3>\n"
}
func (self *HtmlBuilder) MakeJapanese(japanese string) {
self.buf += "<span>" + japanese + "</span>\n"
}
func (self *HtmlBuilder) MakeFlangs(flangs []string) {
self.buf += "<ul>\n"
for i:=0; i<len(flangs); i++ {
self.buf += "<li>" + flang[i] + "</li>\n"
}
self.buf += "</ul>\n"
}
func (self *HtmlBuilder) Close() {
self.buf += "</body>\n</html>\n"
}
func NewHtmlBuilder() *HtmlBuilder {
return &HtmlBuilder {
AbstractContent : NewAbstractContent(),
}
}
Main.go func main() {
var txt = NewTextBuilder()
txt.Construct(txt)
fmt.Println(txt.Get())
var htm = NewHtmlBuilder()
htm.Construct(htm)
fmt.Println(htm.Get())
}
|
Builderパターンを使用した例 AbstractDirector.go import "errors"
type IDirector interface {
Construct()
}
type AbstractDirector struct {
IDirector
builder IBuilder
}
func (self *AbstractDirector) Construct() {
panic(errors.New("Construct メソッドを定義してください。"))
}
func NewAbstractDirector(builder IBuilder) *AbstractDirector {
return &AbstractDirector {
builder: builder,
}
}
Director.go type Director struct {
*AbstractDirector
buf string
title string
japanese []string
flangs [][]string
}
func (self *Director) Construct() {
self.builder.MakeTitle(self.title)
for i:=0; i<len(self.japanese); i++ {
self.builder.MakeJapanese(self.japanese[i])
self.builder.MakeFlangs(self.flangs[i])
}
self.builder.Close()
}
func NewDirector(builder IBuilder) *Director {
return &Director {
title: "いろいろな国の言葉",
japanese = []string { "こんにちは", "ありがとう" }
flangs = [][]string {
{ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" },
{ "Thank you", "Merci", "Danke", "Grazie", "Gracias" },
},
AbstractDirector: NewAbstractDirector(builder),
}
}
AbstractBuilder.go import (
"fmt"
"os"
)
type IBuilder interface {
MakeTitle(string)
MakeJapanese(string)
MakeFlangs([]string)
Close()
}
type AbstractBuilder {
buf string
}
func (*AbstractBuilder) MakeTitle(string) {
panic(errors.New("MakeTitle メソッドを定義してください。"))
}
func (*AbstractBuilder) MakeJapanese(string) {
panic(errors.New("MakeJapanese メソッドを定義してください。"))
}
func (*AbstractBuilder) MakeFlangs([]string) {
panic(errors.New("MakeFlangs メソッドを定義してください。"))
}
func (*AbstractBuilder) Close() {
panic(errors.New("Close メソッドを定義してください。"))
}
func (*AbstractBuilder) Get() string {
return self.buf
}
TextBuilder.go type TextBuilder struct {
*AbstractBuilder
}
func (self *TextBuilder) MakeTitle(title string) {
self.buf += "*** " + title + " ***\n"
}
func (self *TextBuilder) MakeJapanese(japanese string) {
self.buf += "■" + japanese + "\n"
}
func (self *TextBuilder) MakeFlangs(flangs []string) {
for i:=0; i<len(flangs); i++ {
self.buf += " ○" + flang + "\n"
}
}
func (self *TextBuilder) Close() {
self.buf += "(end)\n"
}
func NewTextBuilder() *TextBuilder {
return &TextBuilder{
AbstractBuilder: &AbstractBuilder{},
}
}
HtmlBuilder.go type HtmlBuilder struct {
*AbstractBuilder
}
func (self *HtmlBuilder) MakeTitle(title string) {
self.buf += "<html>\n<head>\n<title>" + title + "</title>\n</head>\n<body>\n"
self.buf += "<h3>" + title + "</h3>\n"
}
func (self *HtmlBuilder) MakeJapanese(japanese string) {
self.buf += "<span>" + japanese + "</span>\n"
}
func (self *HtmlBuilder) MakeFlangs(flangs []string) {
self.buf += "<ul>\n"
for i:=0; i<len(flangs); i++ {
self.buf += "<li>" + flang + "</li>\n"
}
self.buf += "</ul>\n"
}
func (self *HtmlBuilder) Close() {
self.buf += "</body>\n</html>\n"
}
func NewHtmlBuilder() *HtmlBuilder {
return &HtmlBuilder{
AbstractBuilder: &AbstractBuilder{},
}
}
Main.go import "fmt"
func main() {
var director IDirector
var txt = NewTextBuilder()
director = NewDirector(txt)
director.Construct()
fmt.Println(txt.Get())
var htm = NewHtmlBuilder()
director = NewDirector(htm)
director.Construct()
fmt.Println(htm.Get())
}
|
|
この例は Template Method パターンで書かれています。 処理の枠組みを記述したスーパークラスが AbstractContent で、それを継承して処理の具体的内容を記述したのが TextBuilder と HtmlBuilder です。インスタンスの生成はTextBuilder と HtmlBuilder について行われ、それらのクラスにある、AbstractContent から継承した construct() メソッドを呼び出しています。 しかし、 TextBuilder と HtmlBuilder は、処理手順の書かれた AbstractContent のサブクラスとして作成されていますので、処理手順と表現方法を自由に組み合わせたり変更したりができません。 例えば、HTML文章を今は「処理手順1」で出していたけど、次は「処理手順5」で出そうというようなことができないわけです。 処理手順である AbstractContent を継承して、TextBuilder はプレーンテキストで出す、HtmlBuilder はHTMLで出す、としているので、処理手順は変更できないのです。 |
「作成過程」を決定する Director と呼ばれるものと「表現形式」を決定する Builder と呼ばれるものを組み合わせて実現しています。 Template Method パターンと同様、 Director には処理の枠組みが記述されており、 Builder には処理の具体的内容が記述されています。 ただし、 Template Method パターンと異なるところは、インスタンスの生成が両方について行われることです。まず、Builder を継承した TextBuilder や HtmlBuilder のインスタンスが生成され、Director のインスタンス生成時にそれらが引き渡されます。そして、 Director クラスの construct() メソッドを呼び出します。 そして、引き渡されたTextBuilder や HtmlBuilder のインスタンスに従った文書が作成されるわけです。例えば、 HtmlBuilder のインスタンスがDirector に渡された場合は、 Director から呼ばれている makeTitle、makeJapanese、makeFlangs、close はすべてHtmlBuilder のものが使われ、HTML文書が出来上がることになります。 Builderパターンでは、Template Method パターンと違って、処理手順を変更できます。Director クラスの代わりに別の処理手順が書かれたクラスのインスタンスを生成すればよいからです。 それでは Director クラスを別のものに替えて見ましょう。 Director.go type Director struct {
*AbstractDirector
buf string
title string
japanese string
flangs []string
}
func (self *Director) Construct() {
self.builder.MakeTitle(self.title + "の" + self.japanese)
self.builder.MakeFlangs(self.flangs)
self.builder.Close()
}
func NewDirector(builder IBuilder) *Director {
return &Director {
title: "中国語",
japanese: "ありがとう",
flangs: []string {"謝謝", "多謝", "唔該"},
AbstractDirector: NewAbstractDirector(builder),
}
}
|
|
Builderパターンを使用しない例 abstractcontent.d public abstract class AbstractContent {
protected string buf = "";
protected const string title = "いろいろな国の言葉";
protected const string[] japanese = [ "こんにちは", "ありがとう" ];
protected const string[][] flangs = [
[ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ],
[ "Thank you", "Merci", "Danke", "Grazie", "Gracias" ]
];
protected abstract void makeTitle(in string title);
protected abstract void makeJapanese(in string japanese);
protected abstract void makeFlangs(in string[] flangs);
protected abstract void close();
public string get() {
return buf;
}
public void construct() {
makeTitle(title);
foreach (int i; 0..japanese.length) {
makeJapanese(japanese[i]);
makeFlangs(flangs[i]);
}
close();
}
}
textbuilder.d import abstractcontent;
public class TextBuilder : AbstractContent {
protected override void makeTitle(in string title) {
buf ~= "*** " ~ title ~ " ***\n";
}
protected override void makeJapanese(in string japanese) {
buf ~= "■" ~ japanese ~ "\n";
}
protected override void makeFlangs(in string[] flangs) {
foreach (int i; 0..flangs.length)
buf ~= " ○" ~ flangs[i] ~ "\n";
}
protected override void close() {
buf ~= "(end)\n";
}
}
htmlbuilder.d import abstractcontent;
public class HtmlBuilder : AbstractContent {
protected override void makeTitle(in string title) {
buf ~= "<html>\n<head>\n<title>" ~ title ~ "</title>\n</head>\n<body>\n";
buf ~= "<h3>" ~ title ~ "</h3>\n";
}
protected override void makeJapanese(in string japanese) {
buf ~= "<span>" ~ japanese ~ "</span>\n";
}
protected override void makeFlangs(in string[] flangs) {
buf ~= "<ul>\n";
foreach (int i; 0..flangs.length)
buf ~= "<li>" + flangs[i] + "</li>\n";
buf ~= "</ul>\n";
}
protected override void close() {
buf ~= "</body>\n</html>\n";
}
}
main.d import textbuilder;
import htmlbuilder;
public int main() {
TextBuilder txt = new TextBuilder();
txt.construct();
printfln(txt.get());
HtmlBuilder htm = new HtmlBuilder();
htm.construct();
printfln(htm.get());
}
return 0;
}
private void printfln(T...)(T args) { // Shift JIS 出力
import std;
import std.windows.charset;
import core.vararg;
std.stdio.write(to!(string)(toMBSz(std.format.format(args))) ~ "\n");
}
|
Builderパターンを使用した例 abstractdirector.d import abstractbuilder;
public abstract class AbstractDirector {
protected AbstractBuilder builder;
public this(AbstractBuilder builder) {
this.builder = builder;
}
public abstract void construct();
}
director.d import abstractdirector;
import abstractbuilder;
public class Director : AbstractDirector {
private const string title = "いろいろな国の言葉";
private const string[] japanese = [ "こんにちは", "ありがとう" ];
private const string[][] flangs = [
[ "Hello", "Bonjour", "Guten Tag", "Ciao", "Hola" ],
[ "Thank you", "Merci", "Danke", "Grazie", "Gracias" ]
];
public this(AbstractBuilder builder) {
super(builder);
}
public override void construct() {
builder.makeTitle(title);
foreach (int i; 0..japanese.length) {
builder.makeJapanese(japanese[i]);
builder.makeFlangs(flangs[i]);
}
builder.close();
}
}
abstractbuilder.d public abstract class AbstractBuilder {
protected string buf = "";
public abstract void makeTitle(in string title);
public abstract void makeJapanese(in string japanese);
public abstract void makeFlangs(in string[] flangs);
public abstract void close();
public string get() {
return buf;
}
}
textBuilder.d import abstractbuilder;
public class TextBuilder : AbstractBuilder {
public override void makeTitle(in string title) {
buf ~= "*** " ~ title ~ " ***\n";
}
public override void makeJapanese(in string japanese) {
buf ~= "■" ~ japanese ~ "\n";
}
public override void makeFlangs(in string[] flangs) {
foreach (int i; 0..flangs.length)
buf ~= " ○" ~ flangs[i] ~ "\n";
}
public override void close() {
buf ~= "(end)\n";
}
}
htmlBuilder.d import abstractbuilder;
public class HtmlBuilder : AbstractBuilder {
protected override void makeTitle(in string title) {
buf ~= "<html>\n<head>\n<title>" ~ title ~ "</title>\n</head>\n<body>\n";
buf ~= "<h3>" ~ title ~ "</h3>\n";
}
protected override void makeJapanese(in string japanese) {
buf ~= "<span>" ~ japanese ~ "</span>\n";
}
protected override void makeFlangs(in string[] flangs) {
buf ~= "<ul>\n";
foreach (int i; 0..flangs.length)
buf ~= "<li>" ~ flangs[i] ~ "</li>\n";
buf ~= "</ul>\n";
}
protected override void close() {
buf ~= "</body>\n</html>\n";
}
}
main.d import abstractdirector;
import director;
import abstractbuilder;
import textbuilder;
import htmlbuilder;
public int main() {
AbstractDirector director = null;
TextBuilder txt = new TextBuilder();
director = new Director(txt);
director.construct();
printfln(txt.get());
HtmlBuilder htm = new HtmlBuilder();
director = new Director(htm);
director.construct();
printfln(htm.get());
return 0;
}
private void printfln(T...)(T args) { // Shift JIS 出力
import std;
import std.windows.charset;
import core.vararg;
std.stdio.write(to!(string)(toMBSz(std.format.format(args))) ~ "\n");
}
|
|
この例は Template Method パターンで書かれています。 処理の枠組みを記述したスーパークラスが AbstractContent で、それを継承して処理の具体的内容を記述したのが TextBuilder と HtmlBuilder です。インスタンスの生成はTextBuilder と HtmlBuilder について行われ、それらのクラスにある、AbstractContent から継承した construct() メソッドを呼び出しています。 しかし、 TextBuilder と HtmlBuilder は、処理手順の書かれた AbstractContent のサブクラスとして作成されていますので、処理手順と表現方法を自由に組み合わせたり変更したりができません。 例えば、HTML文章を今は「処理手順1」で出していたけど、次は「処理手順5」で出そうというようなことができないわけです。 処理手順である AbstractContent を継承して、TextBuilder はプレーンテキストで出す、HtmlBuilder はHTMLで出す、としているので、処理手順は変更できないのです。 |
「作成過程」を決定する Director と呼ばれるものと「表現形式」を決定する Builder と呼ばれるものを組み合わせて実現しています。 Template Method パターンと同様、 Director には処理の枠組みが記述されており、 Builder には処理の具体的内容が記述されています。 ただし、 Template Method パターンと異なるところは、インスタンスの生成が両方について行われることです。まず、Builder を継承した TextBuilder や HtmlBuilder のインスタンスが生成され、Director のインスタンス生成時にそれらが引き渡されます。そして、 Director クラスの construct() メソッドを呼び出します。 そして、引き渡されたTextBuilder や HtmlBuilder のインスタンスに従った文書が作成されるわけです。例えば、 HtmlBuilder のインスタンスがDirector に渡された場合は、 Director から呼ばれている makeTitle、makeJapanese、makeFlangs、close はすべてHtmlBuilder のものが使われ、HTML文書が出来上がることになります。 Builderパターンでは、Template Method パターンと違って、処理手順を変更できます。Director クラスの代わりに別の処理手順が書かれたクラスのインスタンスを生成すればよいからです。 それでは Director クラスを別のものに替えて見ましょう。 director.d import abstractdirector;
import abstractbuilder;
public class Director : AbstractDirector {
private const string title = "中国語";
private const string japanese = "ありがとう";
private const string[] flangs = [ "謝謝", "多謝", "唔該" ];
public this(AbstractBuilder builder) {
super(builder);
}
public override void construct() {
builder.makeTitle(title ~ "の" ~ japanese);
builder.makeFlangs(flangs);
builder.close();
}
}
|
|
Builderパターンを使用しない例 AbstractContent.pas unit UnitAbstractContent;
interface
type
AbstractContent = class
protected
var buf:string;
const title:string = 'いろいろな国の言葉';
const japanese:array of string = ['こんにちは', 'ありがとう'];
const flangs:array of array of string = [
['Hello', 'Bonjour', 'Guten Tag', 'Ciao', 'Hola'],
['Thank you', 'Merci', 'Danke', 'Grazie', 'Gracias']
];
procedure makeTitle(title:string); virtual; abstract;
procedure makeJapanese(japanese:string); virtual; abstract;
procedure makeFlangs(flangs:array of string); virtual; abstract;
procedure close(); virtual; abstract;
public
function get():string;
procedure construct();
end;
implementation
function AbstractContent.get():string;
begin
Result := buf;
end;
procedure AbstractContent.construct();
var i:integer;
begin
makeTitle(title);
for i := 0 to Length(japanese)-1 do begin
makeJapanese(japanese[i]);
makeFlangs(flangs[i]);
end;
close();
end;
end.
TextBuilder.pas unit UnitTextBuilder;
interface
uses
UnitAbstractContent;
type
TextBuilder = class(AbstractContent)
const CRLF = #13#10;
protected
procedure makeTitle(title:string); override;
procedure makeJapanese(japanese:string); override;
procedure makeFlangs(flangs:array of string); override;
procedure close(); override;
end;
implementation
procedure TextBuilder.makeTitle(title:string);
begin
buf := '*** ' + title + ' ***' + CRLF;
end;
procedure TextBuilder.makeJapanese(japanese:string);
begin
buf := buf + '■' + japanese + CRLF;
end;
procedure TextBuilder.makeFlangs(flangs:array of string);
var f:string;
begin
for f in flangs do begin
buf := buf + ' ○' + f + CRLF;
end;
end;
procedure TextBuilder.close();
begin
buf := buf + '(end)' + CRLF;
end;
end.
HtmlBuilder.pas unit UnitHtmlBuilder;
interface
uses
UnitAbstractContent;
type
HtmlBuilder = class(AbstractContent)
const CRLF = #13#10;
protected
procedure makeTitle(title:string); override;
procedure makeJapanese(japanese:string); override;
procedure makeFlangs(flangs:array of string); override;
procedure close(); override;
end;
implementation
procedure HtmlBuilder.makeTitle(title:string);
begin
buf := '<html>' + CRLF + '<head>' + CRLF + '<title>'
+ title + '</title>' + CRLF + '</head>' + CRLF + '<body>' + CRLF;
buf := buf + '<h3>' + title + '</h3>' + CRLF;
end;
procedure HtmlBuilder.makeJapanese(japanese:string);
begin
buf := buf + '<span>' + japanese + '</span>' + buf;
end;
procedure HtmlBuilder.makeFlangs(flangs:array of string);
var f:string;
begin
buf := buf + '<ul>' + CRLF;
for f in flangs do begin
buf := buf + '<li>' + f + '</li>' + CRLF;
end;
buf := buf + '</ul>' + CRLF;
end;
procedure HtmlBuilder.close();
begin
buf := buf + '</body>' + CRLF + '</html>' + CRLF;
end;
end.
Main.dpr program Main;
uses
System.SysUtils,
UnitTextBuilder,
UnitHtmlBuilder;
var txt:TextBuilder;
var htm:HtmlBuilder;
begin
txt := TextBuilder.Create();
txt.construct();
Write(txt.get());
htm := HtmlBuilder.Create();
htm.construct();
Write(htm.get());
txt.Free;
htm.Free;
end.
|
Builderパターンを使用した例 AbstractDirector.pas unit UnitAbstractDirector;
interface
uses
UnitAbstractBuilder;
type
AbstractDirector = class
protected
var builder:AbstractBuilder;
public
constructor Create(builder:AbstractBuilder); virtual;
procedure construct(); virtual; abstract;
end;
implementation
constructor AbstractDirector.Create(builder:AbstractBuilder);
begin
self.builder := builder;
end;
end.
Director.pas unit UnitDirector;
interface
uses
UnitAbstractDirector,
UnitTextBuilder,
UnitAbstractBuilder;
type
Director = class(AbstractDirector)
const title:string = 'いろいろな国の言葉';
const japanese:array of string = ['こんにちは', 'ありがとう'];
const flangs:array of array of string = [
['Hello', 'Bonjour', 'Guten Tag', 'Ciao', 'Hola'],
['Thank you', 'Merci', 'Danke', 'Grazie', 'Gracias']
];
public
constructor Create(builder:AbstractBuilder); override;
procedure construct(); override;
end;
implementation
constructor Director.Create(builder:AbstractBuilder);
begin
inherited Create(builder);
end;
procedure Director.construct();
var i:integer;
begin
builder.makeTitle(title);
for i := 0 to Length(japanese)-1 do begin
builder.makeJapanese(japanese[i]);
builder.makeFlangs(flangs[i]);
end;
builder.close();
end;
end.
AbstractBuilder.pas unit UnitAbstractBuilder;
interface
type
AbstractBuilder = class
public
var buf:string;
procedure makeTitle(title:string); virtual; abstract;
procedure makeJapanese(japanese:string); virtual; abstract;
procedure makeFlangs(flangs:array of string); virtual; abstract;
procedure close(); virtual; abstract;
function get():string;
end;
implementation
function AbstractBuilder.get():string;
begin
Result := buf;
end;
end.
TextBuilder.pas unit UnitTextBuilder;
interface
uses
UnitAbstractBuilder;
type
TextBuilder = class(AbstractBuilder)
const CRLF = #13#10;
public
procedure makeTitle(title:string); override;
procedure makeJapanese(japanese:string); override;
procedure makeFlangs(flangs:array of string); override;
procedure close(); override;
end;
implementation
procedure TextBuilder.makeTitle(title:string);
begin
buf := '*** ' + title + ' ***' + CRLF;
end;
procedure TextBuilder.makeJapanese(japanese:string);
begin
buf := buf + '■' + japanese + CRLF;
end;
procedure TextBuilder.makeFlangs(flangs:array of string);
var f:string;
begin
for f in flangs do begin
buf := buf + ' ○' + f + CRLF;
end;
end;
procedure TextBuilder.close();
begin
buf := buf + '(end)' + CRLF;
end;
end.
HtmlBuilder.pas unit UnitHtmlBuilder;
interface
uses
UnitAbstractBuilder;
type
HtmlBuilder = class(AbstractBuilder)
const CRLF = #13#10;
public
procedure makeTitle(title:string); override;
procedure makeJapanese(japanese:string); override;
procedure makeFlangs(flangs:array of string); override;
procedure close(); override;
end;
implementation
procedure HtmlBuilder.makeTitle(title:string);
begin
buf := '<html>' + CRLF + '<head>' + CRLF + '<title>'
+ title + '</title>' + CRLF + '</head>' + CRLF + '<body>' + CRLF;
buf := buf + '<h3>' + title + '</h3>' + CRLF;
end;
procedure HtmlBuilder.makeJapanese(japanese:string);
begin
buf := buf + '<span>' + japanese + '</span>' + CRLF;
end;
procedure HtmlBuilder.makeFlangs(flangs:array of string);
var f:string;
begin
buf := buf + '<ul>' + CRLF;
for f in flangs do begin
buf := buf + '<li>' + f + '</li>' + CRLF;
end;
buf := buf + '</ul>' + CRLF;
end;
procedure HtmlBuilder.close();
begin
buf := buf + '</body>' + CRLF + '</html>' + CRLF;
end;
end.
Main.dpr program Main;
uses
System.SysUtils,
UnitAbstractDirector,
UnitDirector,
UnitTextBuilder,
UnitHtmlBuilder;
var _director:AbstractDirector;
var txt:TextBuilder;
var htm:HtmlBuilder;
begin
txt := TextBuilder.Create();
_director := Director.Create(txt);
_director.construct();
Write(txt.get());
txt.Free();
_director.Free();
htm := HtmlBuilder.Create();
_director := Director.Create(htm);
_director.construct();
Write(htm.get());
htm.Free();
_director.Free();
end.
|
|
この例は Template Method パターンで書かれています。 処理の枠組みを記述したスーパークラスが AbstractContent で、それを継承して処理の具体的内容を記述したのが TextBuilder と HtmlBuilder です。インスタンスの生成はTextBuilder と HtmlBuilder について行われ、それらのクラスにある、AbstractContent から継承した construct() メソッドを呼び出しています。 しかし、 TextBuilder と HtmlBuilder は、処理手順の書かれた AbstractContent のサブクラスとして作成されていますので、処理手順と表現方法を自由に組み合わせたり変更したりができません。 例えば、HTML文章を今は「処理手順1」で出していたけど、次は「処理手順5」で出そうというようなことができないわけです。 処理手順である AbstractContent を継承して、TextBuilder はプレーンテキストで出す、HtmlBuilder はHTMLで出す、としているので、処理手順は変更できないのです。 |
「作成過程」を決定する Director と呼ばれるものと「表現形式」を決定する Builder と呼ばれるものを組み合わせて実現しています。 Template Method パターンと同様、 Director には処理の枠組みが記述されており、 Builder には処理の具体的内容が記述されています。 ただし、 Template Method パターンと異なるところは、インスタンスの生成が両方について行われることです。まず、Builder を継承した TextBuilder や HtmlBuilder のインスタンスが生成され、Director のインスタンス生成時にそれらが引き渡されます。そして、 Director クラスの construct() メソッドを呼び出します。 そして、引き渡されたTextBuilder や HtmlBuilder のインスタンスに従った文書が作成されるわけです。例えば、 HtmlBuilder のインスタンスがDirector に渡された場合は、 Director から呼ばれている makeTitle、makeJapanese、makeFlangs、close はすべてHtmlBuilder のものが使われ、HTML文書が出来上がることになります。 Builderパターンでは、Template Method パターンと違って、処理手順を変更できます。Director クラスの代わりに別の処理手順が書かれたクラスのインスタンスを生成すればよいからです。 それでは Director クラスを別のものに替えて見ましょう。 Director.pas unit UnitDirector;
interface
uses
UnitAbstractDirector,
UnitTextBuilder,
UnitAbstractBuilder;
type
Director = class(AbstractDirector)
const title:string = '中国語';
const japanese:string = 'ありがとう';
const flangs:array of string = ['謝謝', '多謝', '唔該'];
public
constructor Create(builder:AbstractBuilder); override;
procedure construct(); override;
end;
implementation
constructor Director.Create(builder:AbstractBuilder);
begin
inherited Create(builder);
end;
procedure Director.construct();
begin
builder.makeTitle(title + 'の' + japanese);
builder.makeFlangs(flangs);
builder.close();
end;
end.
|
|
この Director クラスでは、次のように表示されます。
実行結果 (一部分です)
|