アダプター
アダプターパターンでは、ニーズに合うようにインターフェイスを変換(適応)させます。それには、必要なインターフェイスを備えたオブジェクトを別途作成し、そのオブジェクトを、インターフェイスを変更したいオブジェクトに接続します。

図1.アダプターパターンの構造
アダプターを必要とする理由
非常によくあることですが、アプリケーションの開発や保守を行っていて、アプリケーションのチャンク(例えばログやその種のデータの保管に使用しているライブラリ)を置き換える必要があると判断したとします。新しく置き換えるために用意したライブラリが、古いライブラリとまったく同じインターフェイスを持っている可能性は低いでしょう。この先の作業については、次の2つの選択肢があります。
- コード全体を確認し、古いライブラリを参照している部分をすべて変更する
- 新しいライブラリで古いライブラリとまったく同じインターフェイスを使用できるようにアダプターを作成する
アプリケーションが小さかったり、古いライブラリの参照が少ししかない場合は、新しい抽象化層でコードをコンパイルするよりも、コード全体を見直して新しいライブラリに合うようにコードを変更した方がよいと思えることもあるでしょう。とはいえ、多くの場合は、アダプターを作成した方が現実的で時間の節約になります。
アダプターの例
それでは、このコードサンプルに、上述の仮想のロガーシナリオを適用してみましょう。元の自分のコードで、ログの生成用にブラウザーに組み込まれているコンソールを使用しているかもしれませんが、それには若干問題があります。コンソールはすべてのブラウザーに組み込まれているわけではないので(特に古いブラウザーにはないことが多い)、自分のアプリケーションを他のユーザーが使用した場合に生成されるログを見ることができず、自己テストで検出できなかった問題を調べられないのです。そこで、ロガーを導入し、AJAXを使用してそれらのログをサーバーに転送して処理してもらうことにしました。新しい
AjaxLoggerライブラリのAPIは以下のようになります。AjaxLogger.sendLog(arguments);
AjaxLogger.sendInfo(arguments);
AjaxLogger.sendDebug(arguments);
etc...
見たところ、このライブラリの作成者は、開発者がコンソールの置き換えにこのコードを使用することを想定していなかったため、各メソッド名の先頭に「send」を付ける必要があると考えたようです。そこで、「ライブラリを編集して、メソッド名を変更すれば済む話ではないか?」という疑問が出てきます。しかし、次の2つの理由により、その方法はお勧めしません。ライブラリをアップデートする必要が出てきたときに変更が上書きされてしまうので、開発者は再び名前変更の作業をやり直すことになります。また、ライブラリをコンテンツデリバリーネットワークからプルダウンする場合に名前を編集できないからです。そこで、新しいライブラリをコンソールと同じインターフェイスに適応させるオブジェクトを作成することにしましょう。
var AjaxLoggerAdapter = {
log: function() {
AjaxLogger.sendLog(arguments);
},
info: function() {
AjaxLogger.sendInfo(arguments);
},
debug: function() {
AjaxLogger.sendDebug(arguments);
},
...
};使い方
コンソールを使用する開発者はたいてい、参照によって直接コンソールを呼び出すものです。そこで、
console.xxxの呼び出しごとに、コンソールではなく、新しいアダプターを参照するにはどうすればよいでしょう。ファクトリのような抽象化を使用していた場合、抽象化層に変更を加えるだけで済みますが、上で述べたとおり、皆が単にconsoleを直接参照しているのです。さて、JavaScriptは動的な言語であり、実行時に変更を行うことができます。そこで、新しいAjaxLoggerAdapterでコンソールをオーバーライドしてみたらどうでしょうか。window.console = AjaxLoggerAdapter;
このやり方は簡単ですが、それだけに注意が必要です。他の人によって使用される前提のコードに対してこのようにすると、コンソールは、それらのユーザーの期待どおりには機能しなくなります。また、このコード例の単純さにだまされないでください。多くの場合、メソッドが簡単に対応し合う(
sendLogとlogのように)ことはありません。新しいライブラリと互換性を保つようにインターフェイスを変換するには、実際に自分のロジックを多少実装する必要があるかもしれません。
0 件のコメント:
コメントを投稿