お久しぶりです。白々です。
先日エンジニアの先輩にデザインパターンをご存知でない!?という冷静なツッコミを頂き、その後結城浩さんが書かれた「Java言語で学ぶデザインパターン入門」を渡されたので勉強することにしました。
ただ、本を一読しても覚えられないので覚書として記事にしようと思いました。
完走できるように頑張ります。
また、「Java言語で学ぶデザインパターン入門」には、サンプルプログラムも有りますが、著作権の都合上省かせて頂きます。御了承ください。
前回は、「Iteratorパターン」に関しての記事を作成しました。
前回の記事は、以下です。
https://qiita.com/sirajirasajiki/items/55269e5d6c6e158de16e
今回は、「Adapterパターン」に関して記載したいと思います。
また、「Java言語で学ぶデザインパターン入門」には、サンプルプログラムも有りますが、著作権の都合上省かせて頂きます。御了承ください。
#第2章 Adapter -皮かぶせて再利用
日本で使っている電化製品があると思います。
この電気製品を海外でコンセントを利用する時に、電圧が違うので、コンセントの変換器を持っていくと思います。
このように、すでに供給されている物をそのまま利用できない場合に、使うことができる形に変換することで利用できるようになります。
このような、変換を行うパターンをAdapterパターンと言うそうです。
「Java言語で学ぶデザインパターン入門」には、
「すでに提供されているもの」と「必要なもの」との「ずれ」を埋めるためのデザインパターン
と言う記載がありました。
このAdapterパターンは、Wrapperパターンとも呼ぶそうです。
##なんでこんなパターンが必要なの?
「Java言語で学ぶデザインパターン入門」にも、記載がありましたが、必要なメソッドがあるなら追加で作ればいいという意見もあると思います。
ただ、全てのメソッドを一から作ると、テストの手間がものすごく増えてしまいます。
例えば、unixtimeを取得しint型で返すメソッドがあるとし、新しくunixtimeを文字列型で返すメソッドを欲しいとします。
こんな簡単な例なら、メソッドの返り値を文字列型でキャストすれば問題ないですが、ここでは新しく時間を文字列型で返すメソッドを作成したとします。
この新しく作成したメソッドでエラーが発生した場合、時間を取得している部分で失敗しているのか、文字列型でキャストしている部分で失敗したかエラーが起きたという部分だけではわからないですよね?
ですが、既存のunixtimeを取得しint型で返すメソッドを使用し、新しく時間を文字列型で返すメソッドを作ってエラーが出た場合は、時間を取得する部分のエラーに関しては、既存のメソッドでないことを確認済みなので、int型から文字列型でキャストする時に失敗しているということがすぐに分かります。
また、メソッドを作成する時に、既存のメソッドを呼ぶだけで済むので簡単に実装することができます。
このように、Adapterパターンを使用することで、実装工数の短縮及び実装時に発生したエラー原因を減らすことができます。
既存のunixtimeを取得しint型で返すメソッドの返り値を文字列型でキャストするように修正する場合も考えてみましょう。
「Java言語で学ぶデザインパターン入門」にも、記載がありましたが、この場合でもAdapterパターンを使用した方が良いです。
理由としては、既存の実装を変更してしまうので、再度このメソッドを使用している部分をテストしなけばならないため、少しの改変でもテストの工数がかかってしまい無駄になります。
「Java言語で学ぶデザインパターン入門」にも、記載がありましたが、機能がかなり離れていたら新規でクラスを作るしかないです。
イメージとしては以下のような場合です。
交流100ボルトの電源を元にして水道の水を出すわけにはいかないですからね
##Adapterパターンの種類
このAdapterパターンは、以下の2種類あるそうです。
・クラスによるAdapterパターン(継承を使用)
・インスタンスによるAdapterパターン(移譲を使用)
例に対してそれぞれのパターンで記載していきたいと思います。
###例
インスタンスを作成した時間のunixtimeを取得しint型で返すメソッドを持つクラスを使用して、string型で返すwrapperを作成することにします。
このクラス図は、PlantUMLというもので記載しています。
私が、書いたPlantUMLのコードは以下のGitHubに記載がありますのでReadMeを読んでお使いください。
該当ファイル名は、class.txtです。
https://github.com/sirajirasajiki/design_pattern_uml/blob/master/adapter/class.txt
PlantUMLのインストール方法と使い方に関しては、後述のappendixに記載しています。
####クラス図を元にPythonで実装
以下に実装したコードを公開しています。Python 3.7で実装しました。
https://github.com/sirajirasajiki/design_pattern_python/tree/master/Adapter/class_case
###インスタンスによるAdapterパターン
####クラス図
クラスによるAdapterパターンと異なるのは、GetTimeStrにてGetTimeの使い方が違います。
このクラス図は、PlantUMLというもので記載しています。
私が、書いたPlantUMLのコードは以下のGitHubに記載がありますのでReadMeを読んでお使いください。
https://github.com/sirajirasajiki/design_pattern_uml/blob/master/adapter/instance.txt
####クラス図を元にPythonで実装
以下に実装したコードを公開しています。Python 3.7で実装しました。
https://github.com/sirajirasajiki/design_pattern_python/tree/master/Adapter/instance_case
#まとめ
既存クラスと使用したい形式が違った場合のズレを吸収する物がAdapterパターンということが分かりました。
#第2章感想
既存実装を使い新しいクラスを作ることによって、新規作成するよりも工数を減らすことができ、新規実装分でエラーが発生した場合、エラーの原因の範囲が少なくて済むので簡単に実装できると思いました。
また、返り値の型を変えるような簡単な修正でも既存実装に修正を加えてしまうとテストをやり直しになってしまうので、そのような場合にこのAdapterパターンは使うんだなということがわかりました。
追記
adapterを作るよりwrapperを作るの方が良く聞くとのことなので、これからは、wrapperを作ると言おうと思います。
#最後に
何か間違っているところがあれば、ご指摘していただけると嬉しいです!
#appendix
##次回の記事
https://qiita.com/sirajirasajiki/items/53e1d2aea166190f9a6f
##PlantUMLに関するサイト
PlantUMLのインストールの時にお世話になったサイトは以下です。
https://qiita.com/kohashi/items/1d2c6e859eeac72ed926
PlantUMLを書くときにお世話になっているサイトは以下です。
https://qiita.com/ogomr/items/0b5c4de7f38fd1482a48
#更新履歴
2020/2/28 感想と例を部分的に更新しました。
2020/3/5 始めにの部分を修正しました。