2006年02月22日

Decorator−飾り枠と中身の同一視

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



Displayクラス
using System;

namespace Gushwell.DesignPatterns {

public abstract class Display {
public abstract int Columns { get; }
public abstract int Rows { get; }

// row番目の文字列を得る
public abstract string GetRowText(int row);

// 全部表示する
public virtual void Show() {
for (int i = 0; i < Rows; i++) {
Console.WriteLine(GetRowText(i));
}
}
}
}


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

namespace Gushwell.DesignPatterns {

public class StringDisplay : Display {

// 文字数
override public int Columns {
get { return Encoding.GetEncoding("shift-jis").GetByteCount(str); }
}

// 行数は1
override public int Rows {
get { return 1; }

}

// 表示文字列
private string str;

// 引数で表示文字列を指定
public StringDisplay(string str) {
this.str = str;
}

// rowが0のときのみ返す
public override string GetRowText(int row) {
if (row == 0) {
return str;
} else {
return null;
}
}
}
}


Borderクラス
using System;

namespace Gushwell.DesignPatterns {

public abstract class Border : Display {
protected internal Display display; // この飾り枠がくるんでいる「中身」を指す

// インスタンス生成時に「中身」を引数で指定
protected internal Border(Display display) {
this.display = display;
}
}
}


SideBorderクラス
using System;

namespace Gushwell.DesignPatterns {

public class SideBorder : Border {
// 文字数は中身の両側に飾り文字分を加えたもの
override public int Columns {
get { return 1 + display.Columns + 1; }

}

// 行数は中身の行数に同じ
override public int Rows {
get { return display.Rows; }

}
private char borderChar; // 飾りとなる文字

public SideBorder(Display display, char ch)
: base(display) {
this.borderChar = ch;
}

// 指定行の内容は、中身の指定行の両側に飾り文字をつけたもの
public override string GetRowText(int row) {
return borderChar + display.GetRowText(row) + borderChar;
}
}
}


FullBorderクラス
using System;

namespace Gushwell.DesignPatterns {

public class FullBorder : Border {

// 文字数は中身の両側に左右の飾り文字分を加えたもの
override public int Columns {
get { return 1 + display.Columns + 1; }

}

// 行数は中身の行数に上下の飾り文字分を加えたもの
override public int Rows {
get { return 1 + display.Rows + 1; }
}

public FullBorder(Display display)
: base(display) {
}

// 指定した行の内容
public override string GetRowText(int row) {
if (row == 0) {
// 上端の枠
return "+" + MakeLine('-', display.Columns) + "+";
} else if (row == display.Rows + 1) {
// 下端の枠
return "+" + MakeLine('-', display.Columns) + "+";
} else {
// それ以外
return "|" + display.GetRowText(row - 1) + "|";
}
}

// 文字chをcount個連続させた文字列を作る
private string MakeLine(char ch, int count) {
System.Text.StringBuilder buf = new System.Text.StringBuilder();
for (int i = 0; i < count; i++) {
buf.Append(ch);
}
return buf.ToString();
}
}
}


Programクラス
using System;

namespace Gushwell.DesignPatterns {

public class Program {
[STAThread]
public static void Main(string[] args) {
Display b1 = new StringDisplay("Hello, world.");
Display b2 = new SideBorder(b1, '#');
Display b3 = new FullBorder(b2);
b1.Show();
b2.Show();
b3.Show();
Display b4 =
new SideBorder(
new FullBorder(
new FullBorder(
new SideBorder(
new FullBorder(
new StringDisplay("こんにちは。")
),
'*'
)
)
),
'/'
);
b4.Show();
Console.ReadLine();
}
}

}


 

この記事へのトラックバックURL