×

[PR]この広告は3ヶ月以上更新がないため表示されています。
ホームページを更新後24時間以内に表示されなくなります。

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

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

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



■Display.cs
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Gushwell.Dejavu;

namespace Gushwell.DesignPatterns {

public abstract class Display : IEnumerable<string> {
public abstract int Columns { get; }
public abstract int Rows { get; }

// 全部表示する
public virtual void Show() {
this.ForEach(s => Console.WriteLine(s));
}

// 指定した行の内容を順に取り出す
public abstract IEnumerator<string> GetEnumerator();

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return this.GetEnumerator();
}
}
}


■StringDisplay.cs
using System;
using System.Text;
using System.Collections.Generic;

namespace Gushwell.DesignPatterns {

public class StringDisplay : Display {
// 表示文字列
private string str;

// コンストラクタ:引数で表示文字列を指定
public StringDisplay(string str) {
this.str = str;
}

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

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

// strのみ返す
public override IEnumerator<string> GetEnumerator() {
yield return str;
}
}
}



■Border.cs
using System;

namespace Gushwell.DesignPatterns {

// Borderには、Displayのインターフェースを受け継がせる
public abstract class Border : Display {
// この飾り枠がくるんでいる「中身」を指す。
// ここが、Decoratorの肝の一つ。
protected internal Display display;

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



■SideBorder.cs
using System;
using System.Collections.Generic;

namespace Gushwell.DesignPatterns {
// コンストラクタで与えた Displayオブジェクトに SideBorderの能力を付加する。
public class SideBorder : Border {
// コンストラクタ
public SideBorder(Display display, char ch)
: base(display) {
this.borderChar = ch;
}

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

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

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


// 指定行の内容は、中身の指定行の両側に飾り文字をつけたもの
public override IEnumerator<string> GetEnumerator() {
foreach (var s in display)
yield return borderChar + s + borderChar;
}
}
}


■FullBorder.cs
using System;
using System.Collections.Generic;

namespace Gushwell.DesignPatterns {

// コンストラクタで与えた Displayオブジェクトに FullBorderの能力を付加する。
public class FullBorder : Border {
// コンストラクタ
public FullBorder(Display display)
: base(display) {
}

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

}

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

// 文字chをcount個連続させた文字列を作る
private string MakeLine(char ch, int count) {
return new string(ch, count);
}

// 指定した行の内容を順に取り出す
public override IEnumerator<string> GetEnumerator() {
yield return "+" + MakeLine('-', display.Columns) + "+";
foreach (var text in display)
yield return "|" + text + "|";
yield return "+" + MakeLine('-', display.Columns) + "+";
}
}
}



■Program.cs
using System;

namespace Gushwell.DesignPatterns {

public class Program {
public static void Main(string[] args) {
Display b1 = new StringDisplay("Hello, world.");

// b1にSiderBorderの能力を付加する。
Display b2 = new SideBorder(b1, '#');

// b2にFullBorderの能力を付加する。
Display b3 = new FullBorder(b2);
b1.Show();
b2.Show();
b3.Show();

// Border(の派生クラス)は、Displayの派生クラスだから、SideBorder, FullBorderには、
// SiderBorder, FullBorderのオブジェクトを渡せる。
Display b4 =
new SideBorder(
new FullBorder(
new FullBorder(
new SideBorder(
new FullBorder(
new StringDisplay("こんにちは。")
),
'*'
)
)
),
'/'
);
b4.Show();
Console.ReadLine();
}
}
}



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

namespace Gushwell.Dejavu {
public static class EnumerableExtentions {
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
foreach (var x in source) {
action(x);
}
}

public static void ForEach<T>(this IEnumerable<T> source, Action<T, int> func) {
int i = 0;
foreach (var x in source) {
func(x, i);
i++;
}
}
}
}