徒然電脳

日々のプログラミング(とその他)忘備録 このサイトは独自研究のみに基づきます マサカリ歓迎しますというかよろしくお願いします

デザインパターン[Adapter]

最近良く見る共有

 ここ5年くらいで、「共有」できるサービスが増えている。例えばTwitterだとかLineだとかFacebookのこと。
 今回はFacebookとLineの共有はこのプロジェクトで実装したけど、前のプロジェクトで作っていたTwitterを再利用したいな。っていうシナリオで考えてみた。Adapterパターンはこういった「緊急的措置」の時にとても良く使えるが、逆に最初からAdapterパターンを考えているようなシステムは基本的によろしくないとのこと(以下のページを参照)。
 PHPで使うGoFパターン ひとり Advent Calendar - アダプター - Qiita

 今回は継承関係のAdapterパターンで実装した。保持関係にあるAdapterパターンもあるが、そちらは今回は省略する。


 とりあえず、簡単なクラス図。
f:id:TempProg:20151226015523j:plain

ソースコード

 以下にソースコードを示す。なお、GitHubにも同一のソースコードをアップロードした。
P-denshin/DesignPattern · GitHub


IShare.cs

using System;

namespace Adapter {
    interface IShare {
        void Share(String s);
    }
}

 IShareがTargetの役をしている。これはShare(共有)を一般化するためのインターフェイスとして作った。

Line.cs

using System;

namespace Adapter {
    class Line : IShare{
        void IShare.Share(string s) {
            Console.WriteLine("\"" + s + "\"" + "とLINEに投稿!てかLINEやってる?");
        }
    }
}

 LINEにシェアするためのクラス。今回のプロジェクトで作ったのでShareメソッドに直接LINEにシェアするコードを書く。(今回はWriteLineだけでご勘弁)

Facebook.cs

using System;

namespace Adapter {
    class Facebook : IShare{
        void IShare.Share(string s) {
            Console.WriteLine("\"" +  s + "\"" + "をFacebookに投稿!いいね!");
        }
    }
}

 Facebookにシェアするためのクラス。LINEクラスと同じ。

Twitter.cs

using System;

namespace Adapter {
    class Twitter {
        public void Tweet(String s) {
            Console.WriteLine("\"" + s  + "\"" + "ってツイートしたよ。");
        }

        public void Like(String s) {
            Console.WriteLine("\"" + s + "\"" + "をいいねしたよ。");
        }
    }
}

 Twitterに「ツイート」するクラス。Adapteeだ。ここで注意して欲しいのは「別プロジェクト」から持ってきたためIShareを実装していないのだ。
つまり、ここまでだとMainでは次のようなコードを書かなきゃいけなくなる。

IShare fb = new Facebook();
IShare ln = new Line();

fb.Share("安倍首相と繋がりがあります。企業に興味があります。");
ln.Share("イツメンとスタバでコーヒーわず");

Twitter tw = new Twitter();
tw.Tweet("キエエエエエェェェェェェェェェエエエエ");

 fb, ln変数とtw変数の型に注目してほしい。fb, lnはIShare型だ。シェアするだけなので、IShare型とすることで「シェアするんだ!」という意図をわかりやすくしている。
 対してtwはどうだろうか。型はTwitterメソッド名はTweetだし、シェアとは無関係のLikeメソッドが見えている。これでも目的の動作はするが、これが積み重なるとおそらく保守性に欠けたプログラムになるんじゃないかと思う。
 そこで、Adapterクラスを別に用意する。

TwitterAdapter.cs

using System;

namespace Adapter {
    class TwitterAdapter : Twitter, IShare{
        void IShare.Share(string s) {
            this.Tweet(s);
        }
    }
}

 TwitterAdapterはTwitterクラスを継承し、かつIShareを実装するようなクラスだ。こうすればツイッターに「シェア」できるようになる。Likeメソッドも見えない。上に書いたような少々気持ち悪いコードも次のMainのようにかけるようになっている。

Program.cs

using System;

namespace Adapter {
    class Program {
        static void Main(string[] args) {
            IShare fb = new Facebook();
            IShare ln = new Line();

            fb.Share("安倍首相と繋がりがあります。企業に興味があります。");
            ln.Share("イツメンとスタバでコーヒーわず");

            IShare tw = new TwitterAdapter();
            tw.Share("キエエエエエェェェェェェェェェエエエエ");
        }
    }
}

使いどころ

 正直なところ本だけでは使いどころがよくわからなかったが、調べ書いてるうちになんとなくわかった気がする。
 今回の記事を書くにあったっては以下のページが大きく参考になった。
Adapterパターンを使ってみた。今あるクラスを再利用してみる。 - 感謝のプログラミング 10000時間
 基本的にデザインパターンを紹介するサイトは一般化しすぎてよくわからない物が多い。実際使うときはmethod1とか使うわけ無いはずなのに。そんな中、このように具体例を示してくれるページや結城さんの本は大いに助かっている。