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

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

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



■IDisplayImpl.cs
using System;

namespace Gushwell.DesignPatterns {

// Displayの中身を実装するときに必要となるインターフェース
// 機能とは独立して、実装を変更、拡張できる。
public interface IDisplayImpl {
void RawOpen();
void RawPrint();
void RawClose();
}
}


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

namespace Gushwell.DesignPatterns {

// この実装によって、Displayの動作は変わる。
public class StringDisplayImpl : IDisplayImpl {
private string str; // 表示するべき文字列
private int width; // バイト単位で計算した文字列の「幅」

public StringDisplayImpl(string str) {
//コンストラクタで渡された文字列stringを、
this.str = str; //フィールドに記憶しておく。
this.width = Encoding.GetEncoding("shift-jis").GetByteCount(str);
}

public void RawOpen() {
printLine();
}

public void RawPrint() {
Console.WriteLine("|" + str + "|"); // 前後に"|"をつけて表示
}

public void RawClose() {
printLine();
}

private void printLine() {
Console.Write("+"); // 枠の角を表現する"+"マークを表示する。
width.Times(() => Console.Write("-")); // width個の"-"を表示して、枠線として用いる。
Console.WriteLine("+"); // 枠の角を表現する"+"マークを表示する。
}
}
}



■Display.cs
using System;

namespace Gushwell.DesignPatterns {

// Displayは、機能(インターフェース)を管理
// 具体的に何をするのか(実装)は、IDisplayImpl側で管理
// Displayから派生するのは、is a 関係
// IDisplayImplを実装するクラスは、Displayとは use-a (or made-of)関係になる?
public class Display {
private IDisplayImpl impl;

// コンストラクタでIDisplayImplを受け取る -> これにより動作が変化する。
public Display(IDisplayImpl impl) {
this.impl = impl;
}

public void Open() {
impl.RawOpen();
}

public void Print() {
impl.RawPrint();
}

public void Close() {
impl.RawClose();
}

// オリジナルのメソッド名は 'display'
// クラス名とバッティングするため、Showに変更
public void Show() {
Open();
Print();
Close();
}
}
}


■CountDisplay.cs
using System;
using Gushwell.Dejavu;

namespace Gushwell.DesignPatterns {

// Displayの具象クラス
// Displayにない新しいメソッドMultiDisplayを追加。
public class CountDisplay : Display {
public CountDisplay(IDisplayImpl impl)
: base(impl) {
}

public virtual void MultiDisplay(int times) {
// times回繰り返して表示する
Open();
// 繰返し文をなくすために、Times拡張メソッドを定義し、使ってみた。
times.Times(() => Print());
Close();
}
}
}



■Program.cs
using System;

namespace Gushwell.DesignPatterns {

public class Program {
public static void Main(string[] args) {
Display d1 = new Display(new StringDisplayImpl("Hello, Japan."));
Display d2 = new CountDisplay(new StringDisplayImpl("Hello, World."));
CountDisplay d3 = new CountDisplay(new StringDisplayImpl("Hello, Universe."));
d1.Show();
d2.Show();
d3.Show();
d3.MultiDisplay(5);
}
}
}



■nTimes.cs
using System;

namespace Gushwell.Dejavu {
public static class nTimes {
public static void Times(this int n, Action<int> action) {
for (int i = 0; i < n; i++) {
action(i);
}
}

public static void Times(this int n, Action action) {
for (int i = 0; i < n; i++) {
action();
}
}
}
}