アダプターデザインパターン

アダプター設計パターンの実現テストします

アダプターパターンとはどのようなものでしょうか
たとえば、日本とイギリスのコンセントが形が違いますが、間にアダプターを入れると電気機器は使えるようになります
このようにシステムで考えると既存のシステムの仕組みと新しく作成された仕組みの間に入れることで既存の仕組みを変更することなく動作させる設計パターンのことを指します

シナリオ

カモ(Duck)と七面鳥(Turkey)のパターンで考えます
カモと七面鳥は違いますが、間にアダプター(TurkeyAdapter)を入れて変換します
七面鳥をアダプターでラップしているクラス図になります

クラス図

DuckTestDriveコード

using P237Adapter.Duck;
using P237Adapter.Turkey;

namespace P237Adapter
{
    class DuckTestDrive
    {
        public static void Main()
        {
            // かもを作成します
            IDuck duck = new MallardDuck();

            // 七面鳥を作成します
            ITurkey turkey = new WildTurkey();
            // この七面鳥をアダプターでラップします
            // アダプターは七面鳥をカモのように見せてくれます
            IDuck turkeyAdapter = new TurkeyAdapter(turkey);

            Console.WriteLine("Turkeyの出力");
            // 七面鳥のテストをしましょう
            // ゴロゴロ鳴かせて飛ばせます
            turkey.Gobble();
            turkey.Fly();

            Console.WriteLine("\nDuckの出力");

            // TestDuck()メソッドを呼び出してカモのテストをします
            // このメソッドはDuckオブジェクトを要求します
            TestDuck(duck);

            Console.WriteLine("\nTurkeyAdapterの出力");

            // これが大事なテストです
            // 七面鳥をカモとして渡してみます
            TestDuck(turkeyAdapter);
        }

        /// <summary>
        /// 引数のカモのQuack()メソッドとFly()メソッドを呼び出します
        /// </summary>
        /// <param name="duck">カモを引数に取ります</param>
        static void TestDuck(IDuck duck)
        {
            duck.Quack();
            duck.Fly();
        }
    }
}

IDuckコード

namespace P237Adapter.Duck
{
    /// <summary>
    /// カモがガーガー鳴いて(Quack)
    /// 飛べるようにするインターフェース
    /// </summary>
    public interface IDuck
    {
        void Quack();
        void Fly();
    }
}

MallardDuckコード

namespace P237Adapter.Duck
{
    /// <summary>
    /// マガモクラス
    /// </summary>
    internal class MallardDuck : IDuck
    {
        public void Fly()
        {
            Console.WriteLine("飛んでいます");
        }

        public void Quack()
        {
            Console.WriteLine("ガーガー");
        }
    }
}

WildTurkeyコード

namespace P237Adapter.Turkey
{
    /// <summary>
    /// Turkeyの具象クラスです
    /// MallardDuckと同様に、その動作を出力しているだけです
    /// </summary>
    public class WildTurkey : ITurkey
    {
        public void Fly()
        {
            Console.WriteLine("短い距離を飛んでいます");
        }

        public void Gobble()
        {
            Console.WriteLine("ゴロゴロ");
        }
    }
}

TurkeyAdapterコード

using P237Adapter.Duck;

namespace P237Adapter.Turkey
{
    /// <summary>
    /// 適合される側のインターフェースを実装する必要があります
    /// クライアントが求めているインターフェースはまさにこれです
    /// </summary>
    public class TurkeyAdapter : IDuck
    {
        ITurkey turkey;

        /// <summary>
        /// 次に適合される側のオブジェクトへの参照を取得する必要があります
        /// ここでは、コンストラクタで取得しています
        /// </summary>
        /// <param name="turkey">適合される七面鳥オブジェクト</param>
        public TurkeyAdapter(ITurkey turkey)
        {
            this.turkey = turkey;
        }

        /// <summary>
        /// インターフェースの全てのメソッドを実装する必要があります
        /// クラス間におけるQuack()の変換は簡単です
        /// Gobble()メソッドを呼び出すだけです
        /// </summary>
        public void Quack()
        {
            turkey.Gobble();
        }

        /// <summary>
        /// どちらのインsターフェースにもFly()メソッドがありますが、
        /// 七面鳥が飛べるのは、短い距離だけで、カモのように長距離は飛べません
        /// IDuckのFly()とITurkeyのFly()を対応させるには、ITurkeyのFly()メソッドを5回
        /// 呼び出して長距離が飛べるように調整する必要がありあります
        /// </summary>
        public void Fly()
        {
            for (int i = 0; i < 5; i++)
            {
                turkey.Fly();
            }
        }
    }
}

結果

Turkeyの出力
ゴロゴロ
短い距離を飛んでいます

Duckの出力
ガーガー
飛んでいます

TurkeyAdapterの出力
ゴロゴロ
短い距離を飛んでいます
短い距離を飛んでいます
短い距離を飛んでいます
短い距離を飛んでいます
短い距離を飛んでいます

参考

RemoteLoaderコード

リモコンのスロットにロードされる多数のコマンドオブジェクトを作成します
コマンドオブジェクトは、ホームオートメーションデバイスのリクエストをカプセル化します

namespace P226Command
{
    public class RemoteLoader
    {
        public static void Main()
        {
            RemoteLoader remoteLoader = new RemoteLoader();
            remoteLoader.Run();
        }

        public void Run()
        {
            RemoteControlWithUndo remoteControl = new RemoteControlWithUndo();

            // 照明デバイスを作成します
            Light light = new Light("リビングルーム");
            // テレビデバイスを作成します
            TV tV = new TV("リビングルーム");
            // オーディオデバイスを作成します
            Stereo stereo = new Stereo("リビングルーム");
            // お風呂デバイスを作成します
            Hottab hottab = new Hottab();

            // ライトを制御するコマンドを作成します
            LightOnCommand lightOn = new LightOnCommand(light);
            LightOffCommand lightOff = new LightOffCommand(light);

            // テレビを制御する
            TvOnCommand tvOn = new TvOnCommand(tV);
            TvOffCommand tvOff = new TvOffCommand(tV);

            // オーディオを制御するコマンドを作成します
            StereoOnWithCDCommand stereoOnWithCD = new StereoOnWithCDCommand(stereo);
            StereoOffWithCDCommand stereoOffWithCD = new StereoOffWithCDCommand(stereo);

            // お風呂を制御するコマンドを作成します
            HottabOnCommand hottabOn = new HottabOnCommand(hottab);
            HottabOffCommand hottabOff = new HottabOffCommand(hottab);

            // OnコマンドとOffコマンド用の配列を作成します
            ICommand[] partyOn = { lightOn, stereoOnWithCD, tvOn, hottabOn };
            ICommand[] partyOff = { lightOff, stereoOffWithCD, tvOff, hottabOff };

            // それぞれの配列をもつ2つのマクロを作成します
            MacroCommand partyOnMacro = new MacroCommand(partyOn);
            MacroCommand partyOffMacro = new MacroCommand(partyOff);

            // コマンドが作成できたので、リモコンのスロットにロードできます
            remoteControl.SetCommand(0, partyOnMacro, partyOffMacro);

            Console.WriteLine(remoteControl);

            Console.WriteLine("----マクロのOnを押す----");

            remoteControl.OnButtonWasPushed(0);

            Console.WriteLine("----マクロのOffを押す----");

            remoteControl.OffButtonWasPushed(0);
        }
    }
}

MacroCommandコード

namespace P226Command
{
    internal class MacroCommand : ICommand
    {
        private ICommand[] partyOn;

        public MacroCommand(ICommand[] partyOn)
        {
            this.partyOn = partyOn;
        }

        public void Execute()
        {
            for (int i = 0; i < partyOn.Length; i++)
            {
                partyOn[i].Execute();
            }
        }

        public void Undo()
        {
            for (int i = partyOn.Length - 1; i >= 0; i--)
            {
                partyOn[i].Undo();
            }
        }
    }
}

結果

—– リモコン —–
[スロット0] MacroCommand MacroCommand
[スロット1] NoCommand NoCommand
[スロット2] NoCommand NoCommand
[スロット3] NoCommand NoCommand
[スロット4] NoCommand NoCommand
[スロット5] NoCommand NoCommand
[スロット6] NoCommand NoCommand
[アンドウ] NoCommand
—-マクロのOnを押す—-
リビングルーム照明を点けました
ステレオをOnにしました
CDをセットました
ボリュームを22にしました
リビングルームのテレビを点けました
お風呂を沸かしました
—-マクロのOffを押す—-
リビングルーム照明を消しました
ステレオをOffにました
リビングルームのテレビを消しました
お風呂を消しました

参考