なぜ「対」なの?「vs」ではありません。アスペクト指向プログラミングは関数型プログラミングと組み合わせて使用できますが、オブジェクト指向プログラミングと組み合わせて使用することもできます。「vs」ではなく、「オブジェクト指向プログラミングによるアスペクト指向プログラミング」です。
私にとって、AOP はある種の「メタプログラミング」です。AOP が行うすべてのことは、コードを追加するだけで、AOP がなくても実行できます。AOP は、このコードを書く手間を省くだけです。
ウィキペディアには、このメタプログラミングの最良の例の 1 つがあります。多くの「set...()」メソッドを持つグラフィカル クラスがあるとします。各設定方法の後、グラフィックスのデータが変更されたため、グラフィックスが変更されたため、グラフィックスを画面上で更新する必要があります。「Display.update()」を呼び出す必要があるグラフィックを再描画するとします。古典的なアプローチは、コードを追加することでこれを解決することです。あなたが書く各セットメソッドの最後に
void set...(...) {
:
:
Display.update();
}
set-method が 3 つあれば問題ありません。200 (仮想) がある場合、これをどこにでも追加するのは本当に面倒です。また、新しい set-method を追加するときはいつでも、これを最後に追加することを忘れないようにする必要があります。そうしないと、バグが発生するだけです。
AOP は、大量のコードを追加せずにこれを解決します。代わりに、アスペクトを追加します。
after() : set() {
Display.update();
}
以上です!更新コードを自分で書く代わりに、 set() ポイントカットに達した後、このコードを実行する必要があり、このコードを実行することをシステムに伝えるだけです。200 個のメソッドを更新する必要はありません。新しい set-method にこのコードを追加するのを忘れないようにする必要もありません。さらに、ポイントカットが必要です:
pointcut set() : execution(* set*(*) ) && this(MyGraphicsClass) && within(com.company.*);
どういう意味ですか?つまり、メソッドが何を返すか (最初のアスタリスク) や受け取るパラメーター (3 番目のアスタリスク) に関係なく、メソッドの名前が "set*" (* は set の後に任意の名前が続く可能性があることを意味します)であり、それが MyGraphicsClass のメソッドであり、このclass がパッケージ "com.company.*" の一部である場合、これは set() ポイントカットです。そして、最初のコードは、「ポイントカットが設定されているメソッドを実行した後、次のコードを実行する」ことを示しています。
ここで、AOP が問題をエレガントに解決する方法をご覧ください。実際、ここで説明することはすべてコンパイル時に実行できます。AOP プリプロセッサは、クラス自体をコンパイルする前に、ソースを変更するだけです (たとえば、Display.update() をすべての set-pointcut メソッドの最後に追加する)。
ただし、この例は、AOP の大きな欠点の 1 つも示しています。AOP は、多くのプログラマーが「アンチパターン」と見なすことを実際に行っています。正確なパターンは「遠距離での行動」と呼ばれます。
離れた場所でのアクションはアンチパターン (認識されている一般的なエラー) であり、プログラムのある部分での動作が、プログラムの別の部分での識別が困難または不可能な操作に基づいて大幅に変化します。
プロジェクトの初心者として、表示を更新しないように見えるので、set-method のコードを読んで壊れていると考えるかもしれません。set-method のコードを見ただけでは、それが実行された後、表示を更新するために他のコードが「魔法のように」実行されることはわかりません。これは重大な欠点だと思います!メソッドに変更を加えることで、奇妙なバグが導入される可能性があります。特定のことが正しく機能しているように見えても、明らかではないコードのコード フローをさらに理解することは、非常に困難です。
アップデート
明確にするために: AOP は何か悪いものであり、使用すべきではないと私が言っているという印象を持つ人もいるかもしれません。それは私が言っていることではありません!AOP は実際には優れた機能です。「気をつけて使ってください」とだけ言っておきます。AOP は、同じAspectに対して通常のコードと AOP を混同した場合にのみ問題を引き起こします。上記の例では、グラフィック オブジェクトの値を更新し、更新されたオブジェクトをペイントするアスペクトがあります。それは実際には単一の側面です。その半分を通常のコードとしてコーディングし、残りの半分をアスペクトとしてコーディングすると、問題が追加されます。
ロギングなど、まったく別の側面で AOP を使用する場合、アンチパターンの問題に遭遇することはありません。その場合、プロジェクトの初心者は「これらすべてのログ メッセージはどこから来るのか? コードにログ出力が表示されない」と疑問に思うかもしれませんが、それは大きな問題ではありません。プログラム ロジックに変更を加えてもログ機能が壊れることはほとんどなく、ログ機能に加えられた変更によってプログラム ロジックが壊れることはほとんどありません。これらの側面は完全に分離されています。ロギングに AOP を使用すると、コードが何百ものログ メッセージで散らかることなく、プログラム コードが本来の処理に完全に集中でき、洗練されたロギングを行うことができるという利点があります。また、新しいコードが導入されると、魔法のように適切なタイミングで適切な内容のログ メッセージが表示されます。
したがって、私の例での AOP の適切な使用法は、set メソッドを介して値が更新された場合に常にログを記録することです。これはアンチパターンを作成せず、問題の原因になることはほとんどありません。
AOP を簡単に悪用して非常に多くの問題を引き起こすことができるのであれば、それをすべて使用するのは悪い考えだと言う人もいるかもしれません。しかし、悪用できないテクノロジーはどれですか? データのカプセル化や継承を悪用できます。ほとんどすべての有用なプログラミング技術が悪用される可能性があります。悪用できない機能しか含まないほど制限されたプログラミング言語を考えてみましょう。当初意図されたとおりにしか機能を使用できない言語。そのような言語は非常に制限されているため、実際のプログラミングに使用できるかどうかは議論の余地があります.