7回目の今回はBuilder「複雑なインスタンスを組み立てる」です。複雑な構造のプログラムも大まかなところから細かいところへ分けて考えると楽にできますねというパターンです。一言でいってデカルトパターンということです。(謎)
このコード書いていて思い出したのは高校のときのデッサンの授業です。初心者の人はいきなりディティールの描き込みから入っちゃうのだけど、全体の構図やおおまかな明暗とかマッスのベースを作って、モチーフとの印象を確認しながら描くと対象に近づきやすくなります。今回はそんなパターン。
デッサンとかだと各工程が有機的につながってるからあまり良くない例だったかな。
例えば、、、
クライアントが「これ作ってね。」と依頼してきた。Directorはおおまかな仕事の進め方はわかるので、とりあえず「ほいきた。」と仕事を引き受ける。でもって実務は下請け業者(TextBUilder、HTMLBuilder)に流してるかんじ?平たく言えば中抜きやってる人。こんな商売なら、クライアントのニーズが変わっても下請け業者を切り替えるだけでよい→うまー!って。。
例えが悪すぎ。軽くへこんだ。
orz
まじめな話今回のパターンは切り替えが容易+後で具体的なことを考えられる、ってのが大きな利点だと思います。覚えて損なし。
作ったクラスとそれぞれの役割は以下。
- Builder.as
インターフェースです。 - Director.as
おおまかな処理の流れを定義してます。中抜き業者です。 - TextBuilder.as
下請け業者1。テキスト作ります。 - HTMLBUilder.as
下請け業者2。HTML作ります。 - Main.as
クライアントです。Directorに「わかんないけど、とにかくこれで作って」と頼んでます。
今回の例だと、あるタイトルがあって、見出しがあって、項目があってと構造化された文章をを作るという作業自体の大枠を先に構造化しています。見出しの作業はこれ、項目はこれ、etc.といった具合に。具体的な処理は出力結果によってインスタンス化されたサブクラスに任せています(委譲-お任せパターン)。
ではソース。
// Builder.as
interface Builder{
function makeTitle(title:String);
function makeString(str:String);
function makeItems(items:Array);
function Close();
}
// Director.as
class Director{
private var builder:Builder;
function Director(b:Builder){
builder = b;
}
function construct(){
builder.makeTitle("Greeting");
builder.makeString("朝から昼にかけて");
builder.makeItems( new Array(
"おはようございます。",
"こんにちは。"));
builder.makeString("夜に");
builder.makeItems( new Array(
"こんばんは。",
"おやすみなさい。",
"さようなら。"));
builder.Close();
}
}
// TextBuilder.as
class TextBuilder implements Builder{
private var buffer:String = new String();
function makeTitle(title:String){
buffer = "====================¥n";
buffer = buffer + "『" + title + "』¥n";
buffer = buffer + "¥n";
}
function makeString(str:String){
buffer = buffer + "■" + str + "¥n";
buffer = buffer + "¥n";
}
function makeItems(items:Array){
for (var i = 0; i < items.length; i++) {
buffer = buffer + " ・" + items[i] + "¥n";
}
buffer = buffer + "¥n";
}
function Close(){
buffer = buffer + "====================¥n";
}
function getResult():String {
return buffer;
}
}
// HTMLBuilder.as
class HTMLBuilder implements Builder{
private var buffer:String = new String();
function makeTitle(title:String){
buffer = buffer + "<body><h1>" + title + "</h1><br />";
}
function makeString(str:String){
buffer = buffer + "<p>" + str + "</p>";
}
function makeItems(items:Array){
buffer = buffer + "<ul>";
for (var i = 0; i < items.length; i++) {
buffer = buffer + "<li>" + items[i] + "</li>";
}
buffer = buffer + "</ul>";
}
function Close(){
buffer = buffer + "</body>";
}
function getResult():String {
return buffer;
}
}
//Main.as
class Main{
// メインクラス
function Main(path :MovieClip ) {
// 準備
// plain作成
var textbuilder:TextBuilder = new TextBuilder();
var director:Director = new Director(textbuilder);
director.construct();
var tmp:String = textbuilder.getResult();
// html作成
var htmlbuilder:HTMLBuilder = new HTMLBuilder();
var director2:Director = new Director(htmlbuilder);
director2.construct();
tmp = tmp + htmlbuilder.getResult();
// 表示
path.createTextField("tf", 1, 5, 5, 290, 290);
path.tf.border = true;
path.tf.multiline= true;
path.tf.wordWrap= true;
path.tf.html= true;
path.tf.htmlText = tmp;
}
static function main() {
var t :Main= new Main(_root);
}
}
path.tf.html= true; path.tf.htmlText = tmp;
と書くとテキストフィールドに簡単なHTMLが出力できます。
今回はちょっとステージの大きさを大きくしてみるので以下みたいに感じで。
mtasc -swf builder.swf -main Main.as -header 300:300:30
ということで、また。