デザインパターン Adapterパターンについて勉強した
Adapterパターンとは
adapte(アダプター)と聞いて何を思い浮かべるでしょうか。
代表的なものの一つにACアダプターがあります。
ACアダプターはコンセントから供給される100vの交流電流を5vの直流電流に変換したりするものです。
adapterパターンではシグネチャAのメソッドで用意されている機能をシグネチャBで呼び出したいような時に使用します。
簡単に例えると、コンソール出力に毎回System.out.println("hogehuga")を書くと長くなるから新たにprint(Object)メソッドを作るといったイメージです。
public void print(Object object){ System.out.println(object); }
シグネチャAの機能を使うのにシグネチャBを呼び出す。シグネチャBからシグネチャAを呼び出す。
このようにシグネチャAの前に挟まれたシグネチャBがアダプター(変換器)の役割を果たします。
コード例1(継承
adapterパターンでは継承を使用するものと委譲を使用するものの2パターンが存在します。
まずは継承の例から見ていきます。
引数に"年","月","日"を入力すると"yyyy年mm月dd日"の形式でコンソール出力をするprintaDateメソッドを持つPrinterクラスが既に作られているものとします。
そして上記のメソッドと同じ機能を持ったprintCalendarメソッドをMyCalendarクラスで実装したい場合を考えます。
Printerクラス
public class Printer{ public void printDate(int year,int month,int day) { System.out.println(String.format("%d年%d月%d日",year,month,day)); } }
入力された年月日を特定のフォーマットでコンソール出力するメソッドを持っています。
CalendarInterfaceインタフェース
public interface CalendarInterface { void printCalendar(int year,int month,int day); }
printCalendarはyear(年),month(月),day(日)を渡すと何かしらのフォーマットに整えてコンソール出力することを期待して宣言されています。
MyCalendarクラス
public class MyCalendar extends DefaultCalendar implements CalendarInterface{ @Override public void printCalendar(int year, int month, int day) { printDate(year,month,day); } }
CalendarInterfaceで宣言されたprintCalendarメソッドを実装しています。
printCalendarメソッドの実装では、親クラスのprintDateメソッドに全て処理を任せています。
これだけで考えると「最初からPrintクラスのprintDateメソッドを呼ぶか、PrintクラスにCalendarInterfaceを実装すればいいのではないか?MyCalendarクラスは不要ではないか?」と思うかもしれません。
しかし、例えばPrintクラスとCalendarInterfaceインタフェースが既に作られているフレームワークであったりした場合、そのように変更することはできません。
MyCalendarはPrintクラスとCalendarInterfaceインタフェースの橋渡し役として実装されているのです。
実装例1(継承
public class Main { public Main() { CalendarInterface calendar = new MyCalendar(); calendar.printCalendar(2021, 6, 12); } public static void main(String[] args) { new Main(); } }
MyCalendarクラスをインスタンス化し、printCalendarメソッドを呼び出しています。
calendarの型がCalendarInterfaceになっているのは、仮にCalendarInterfaceを実装したDefaultCalendarクラスに置き換えたくなった時でも、即座に書き換えられるようにするためです。
実行してみます。
2021年6月12日
コード例2(委譲
もう一つ、委譲を利用するパターンについても説明してみます。
DefaultCalendarクラス
public class DefaultCalendar implements CalendarInterface{ private Print print = new Print(); @Override public void printCalendar(int year, int month, int day) { print.printDate(year,month,day); } }
こちらはMyCalendarと若干似ていますが、Printクラスを継承せず、代わりに委譲をしています。
実装例2(委譲
public class Main { public Main() { //CalendarInterface calendar = new MyCalendar(); CalendarInterface calendar = new DefaultCalendar(); calendar.printCalendar(2021, 6, 12); } public static void main(String[] args) { new Main(); } }
コンストラクタ1行目では、実装例1で使用したMyCalendarクラスがコメント化されています。
そして2行目では同じ変数名でDefaultCalendarのインスタンスが作られています。
2021年6月12日
実装例1と同じ結果が表示されました。
特徴
Printクラスで実装されているメソッドをCalendarInterfaceインタフェースで宣言されているメソッドで呼び出したい。
しかしPrintクラスにCalendarInterfaceインタフェースを実装することはできない。と言った場面を例に解説してみました。
結構基本的で、誰もが知らないうちに使っているようなパターンではないかと思います。