LoginSignup
8
3

More than 5 years have passed since last update.

デザインパターン勉強会 第二回:Adapterパターン

Last updated at Posted at 2017-07-28

はじめに

これは某社内で実施するデザインパターン勉強会で使用する資料です。
書籍「Java言語で学ぶデザインパターン」をベースに学習を進めますが、サンプルプログラムはC#に置き換えて解説します。

第一回:Iteratorパターン
第三回:Template Methodパターン


Adapterパターンとは

Adapterパターンとは、目的のクラスに対して既存のクラスがそのまま利用できない場合に、間に入ってズレを埋めるようなデザインパターンです。

Adapterパターンには以下の2種類があります。

  • クラスによるAdapterパターン(継承を使ったもの)
  • インスタンスによるAdapterパターン(委譲を使ったもの)

ここでは文字列を変換して表示するサンプルプログラムで紹介します。


クラスによるAdapterパターン(継承を使ったもの)


サンプルプログラムクラス図

文字列を変換して表示するプログラムを実装したモデルは次の通りです。

継承.png


クラスの役割

クラス名 役割
Banner あらかじめ提供されているクラス
IPrint 必要とされているインターフェース
PrintBanner アダプターの役目を果たすクラス
Program PrintBannerを使って文字列を表示するクラス

Banner

あらかじめ提供されていることを想定したクラスです。
文字列を表示するShowWIthParenメソッド、ShowWithAsterメソッドが実装されていますが、今回はこのまま使用することができません。

    public class Banner
    {
        private readonly string str;
        public Banner(string str)
        {
            this.str = str;
        }
        public void ShowWithParen()
        {
            Console.WriteLine($"({str})");
        }
        public void ShowWithAster()
        {
            Console.WriteLine($"*{str}*");
        }
    }

IPrint

今回必要とされているインターフェースです。

    public interface IPrint
    {
        void PrintWeak();
        void PrintStrong();
    }

PrintBanner

アダプターの役目を果たすクラスです。
Bannerクラスを継承して、ShowWIthParenメソッド、ShowWithAsterメソッドを継承します。
IPrintインターフェースを実装して、PrintWeakメソッド、PrintStrongメソッドを実装します。

    public class PrintBanner : Banner, IPrint
    {
        public PrintBanner(string str) : base(str)
        {
        }

        public void PrintStrong()
        {
            ShowWithAster();
        }

        public void PrintWeak()
        {
            ShowWithParen();
        }
    }

Program

アダプターの役目であるPrintBannerクラスを利用して、Helloという文字列をカッコ付き、また、*で挟んで表示します。

    class Program
    {
        static void Main(string[] args)
        {
            IPrint print = new PrintBanner("Hello");
            print.PrintWeak();
            print.PrintStrong();

            Console.ReadLine();
        }
    }

Program実行結果

Programを実行した結果が以下の通りです。
Helloという文字列がカッコ付き、また、*で挟んで表示されています。

(Hello)
*Hello*

インスタンスによるAdapterパターン(委譲を使ったもの)


サンプルプログラムクラス図

文字列を変換して表示するプログラムを実装したモデルは次の通りです。
先ほどのクラスによるAdapterパターンと異なるのはPrintBannerクラスのみです。

委譲.png


PrintBanner

アダプターの役目を果たすクラスです。
先ほどと異なるのは、Bannerクラスを継承せず、bannerフィールドでBannerクラスのインスタンスを保持していることです。
PrintWeakメソッド、PrintStrongメソッドの処理はフィールドを経由してBannerクラスのインスタンスが行います。

    public class PrintBanner : Print
    {
        private Banner banner;
        public PrintBanner(String str)
        {
            banner = new Banner(str);
        }

        public override void PrintWeak()
        {
            banner.ShowWIthParen();
        }
        public override void PrintStrong()
        {
            banner.ShowWithAster();
        }
    }

Adapterパターンのメリット

Adapterパターンは既存のクラスには手を加えずに目的のインターフェースに合わせるものです。
そのため、既存のクラスが十分にテストされていれば、新規に作成したAdapter役のクラスをテストするのみで良いです。


継承と委譲

ところで、継承と委譲(コンポジション)が登場しましたがどちらを使用するのが良いでしょうか?

私は、基本的に委譲を使うのが良いのではと考えています。
理由は以下の通りです。

  • 継承の場合、子クラスの実装は親クラスを意識して行う必要があり、 意図せずにメンバーの隠匿を行ってしまった場合には動作が変わってしまう。
  • 委譲の場合、既存クラスのインスタンスをフィールドに持ち、 必要なメソッドを呼び出すため、継承のように他のクラスを意識して実装する必要がない。

サンプルコード

以下に公開しています。

クラスによるAdapterパターン(継承を使ったもの)
https://github.com/Nanakusajp/AdapterPattern-Inheritance

インスタンスによるAdapterパターン(委譲を使ったもの)
https://github.com/Nanakusajp/AdapterPattern-Delegation

8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3