アスペクト指向(AOP : Aspect-oriented programming)はオブジェクト指向(OOP : object-oriented programming)とは直行的な
概念で、相補的なものですが、2008年現在、未だ広く普及しているパラダイムではなく、その機能を取り込んだ言語もあるものの
(Javaの拡張であるAspectJ、Rubyの拡張であるAspectRなど)普及しているとは言えない状況です。
近年ではDIコンテナの普及で、AOPを部分的に利用できるようになりました。
オブジェクト指向言語の普及前に、例えば言語としてのオブジェクト指向をサポートしないC言語で、
オブジェクト指向の概念を表現する工夫がなされたと聞きます。
DIコンテナによる部分的なAOPサポートは、言語機能としてAOPがサポートされた言語が普及する「夜明け」に対して、
「前夜」の趣を感じさせるものです。
アスペクト指向が解決しようとしていること
アスペクト指向の解説書でアスペクト(横断的関心事と呼ばれる。後述)の例として、よくロギングが挙げられます。
が、正直な話、私はあまりこの例でピンときませんでした。
横断的関心事とはどういう事象でしょうか?
オブジェクト指向では複数のクラスに跨って存在してしまう機能性ということですが、どういうものがあるのでしょうか?
私がシステム設計をしてきた中で、「あぁ、これが概念としてのアスペクトなのだな」と思ったことは
- SQL injection対策
- XSS対策の出力文字エスケープ
- OS command injection対策
- バッファオーバーラン防止のためのバウンダリチェック
- 例外処理
といったことです。開発でこれらの対策に頭を悩ませている方は多いのではないでしょうか?
これらの事象は、「すべての該当箇所に対して、一律の対応を行う必要がある」という点です。
これこそが、概念としてのアスペクト、横断的関心事なのです。
こうした、XXに全部YYをする、というのは自然言語で表現すると1文にも関わらず、
プログラム言語的には該当箇所を検索して1つずつ虱潰しにコードクローンを挿入する必要があります。
アスペクト指向が解決しようとしているのは、まさにこの部分なのです。
アスペクト指向の概念で重要なのはこのアスペクトという抽象概念を捉える事。
そして、どういったターゲットにウィービング(weaving : 縫い付けるの意。アスペクトを適用させること)
させるのかということです。ウィービングできるポイントをジョインポイントと呼んだりします。
端的には、メソッドが呼ばれる前、および呼ばれた後などをジョインポイントとすることが多いですね。
どのように実装するか
DIコンテナでは部分的にAOPが利用できると述べました。
DIコンテナはオブジェクトの生成をDIコンテナが管理します。
このDIコンテナに管理されたオブジェクトに対してGoFのProxyパターンを利用してAOPを実現しています。
これはOOP的な環境で疑似的にAOPを実現するためのひとつの答えです。
あるクラスのインスタンス生成が制御されうるなら、その段階でProxyを挟むことで、
そのクラスの特定のメソッドの前後に処理を一律に差し挟むことができます。
DIコンテナではコンテナがクラスの生成を管理するためにそれが可能でした。
そうではない場合でも、Factory Method、Abstract Factory、Builder などといった生成にまつわる
GoFデザインパターンと組み合わせることで、一律にProxyを噛ませることができます。
また、ウィービング対象となるオブジェクトが特定の箇所を必ず通過するようなケースでは、
そこでトラップしてProxyを噛ませるような方法論も考えることができます。
ServletでのRequest#setAttribute()のような場所をイメージするとよいでしょう。
実行時による動的なウィービングでなくとも、コンパイル時に機械的に処理を差し挟むような方法論も考えられます。
Java SE 5.0からはアノテーションが使えるようになりました。
これにより、こうした機械的な処理が断然しやすくなった点も見逃せません。
コンパイル時にジョインポイントを自動生成するような仕掛けを作ることで概念としてのAOPを実装することができるわけです。
関連エントリ
Injection 系の脆弱性ってなんで起こるんだろ?
そのやり方はXSSの元としか思えない。
XX Injection と呼ばれる脆弱性に共通するのは、OOPでの解決の行えない横断的関心事であるということでした。
一律に対応するためにはどのように網を張ればよいのか、設計をする人は頭を悩ませていることでしょう。
現時点では決定打に欠けるところですが、概念としてはアスペクトをどのようにして漏れなくウィービングするのかということです。
そのための適切なジョインポイントはどこかということです。
アスペクト指向の問題点
アスペクトというものが横から入り込んでくるわけですから、OOPのソースコードを見ただけでは実行時の動作がわかりません。
そう言った意味でプログラムが複雑化する危険性をはらんでいます。
また、アスペクト同士の干渉が起こることもあり、アスペクトの適応順序によって挙動が変わることもあります。
また、アスペクト指向でウィービングの対象をどう管理するかも疑問が多い。「全ての」の適用範囲はどこまでなのか。
あるいは、特定の範囲だけに適用したいこともあるでしょう。
現行のDIコンテナでのAOPではメソッド名のマッチングによって特定の名称のメソッドの前後に適用、
といったことができますがこれが酷く気持ち悪い。
gattaislime氏のアスペクト指向の問題点では
要するに、現在の典型的なアスペクト指向では、アスペクトを織り込むオブジェクトがホワイトボックスであることを要求するか、逆にアスペクト自体がオブジェクトの実装を規定するか、ということになってしまい、結果としてアスペクトが単なる暗黙的多重TemplateMethodに成り下がっているのではないかと感じてしまうのだ。
このような暗黙のTemplateMethodは非常に厄介で、ソースコードをそのまま追っても処理の流れがつかみにくく、最悪の場合ソースコード全体をメソッド名や属性名でgrepして、関連するすべてのアスペクトを洗い出さなければならない。
と指摘しています。
ウィービング対象は集合論的に抽出されるわけで(つまり、SQLのWhere句のようなイメージ)Javaなどの強い型付け言語でなされる
型の安全性のような安心感がまったくない。
しかし、集合論というとジェネリクスも集合論ですが、型の安全性を確保できている(
参考:ジェネリクスと代入と落とし穴
)わけで、ウィービングのための型のような
システムが必要なのではないかと思う次第。
投稿日時 : 2008年3月25日 10:33