JavaScript での AOP プログラミングの基本実装

JavaScript での AOP プログラミングの基本実装

AOP の紹介

AOP (アスペクト指向プログラミング) の主な機能は、コアビジネスロジックモジュールに関連しないいくつかの機能を抽出することです。ビジネスロジックに関連しないこれらの機能には、通常、ログ統計、セキュリティ制御、例外処理などが含まれます。これらの関数は抽出された後、「動的ウィービング」を通じてビジネス ロジック モジュールに統合されます。

アスペクト指向プログラミングは、ターゲットロジックを変更せずに既存の関数またはオブジェクトにコードを挿入する方法を提供します。

必須ではありませんが、挿入されたコードは、ログ機能の追加、メタデータのデバッグ、または他のあまり一般的ではないが追加の動作など、横断的な関心事を持つことを意図しており、元のコードの内容に影響を与えずに挿入できます。

良い例を挙げると、ビジネス ロジックを作成したが、ログ記録コードを追加していないことに気付いたとします。通常のアプローチは、ログ記録ロジックを新しいモジュールに集中させ、機能ごとにログ記録情報を追加することです。

ただし、ログに記録する各メソッドの実行の特定の時点で、同じロガーに 1 行のコードを挿入することができれば、作業は間違いなくずっと簡単になります。そうじゃない?

側面、アドバイス、ポイントカット(何、いつ、どこ)

上記の定義をより正式なものにするために、ロガーを例にとり、AOP に関する 3 つの概念を紹介しましょう。このパラダイムをさらに探求することに決めた場合は、次のものが役立ちます。

  • アスペクト (それが何であるか): これは、ターゲット コードに挿入する「アスペクト」または動作です。私たちのコンテキスト (JavaScript) では、これは追加する動作をカプセル化する関数を指します。
  • 通知 (何時に): この側面をいつ実行しますか? 「アドバイス」は、「before」、「after」、「around」、「whenThrowing」など、アスペクト コードを実行する一般的なタイミングを指定します。それらは、コードの実行に関連する時点を指します。コード実行後に参照される部分については、このアスペクトは戻り値をインターセプトし、必要に応じて上書きする可能性があります。
  • ポイントカット (where): アスペクトを挿入するターゲット コード内の場所を参照します。理論的には、ターゲット コード内の任意の場所でアスペクト コードを実行するように明示的に指定できます。これは実際には実用的ではありませんが、たとえば「オブジェクト内のすべてのメソッド」や「この特定のメソッドのみ」、あるいは「get_ で始まるすべてのメソッド」などを指定することもできます。

この説明を読めば、既存の OOP ベースのビジネス ロジックにログ記録ロジックを追加するための AOP ベースのライブラリを作成するのは比較的簡単であることがわかるはずです (例)。必要なのは、ターゲット オブジェクトの既存の一致メソッドを、適切なタイミングでアスペクト ロジックを追加して元のメソッドを呼び出すカスタム関数に置き換えることだけです。

基本的な実装

私は視覚的に学習するタイプなので、AOP ベースの動作を追加するための切面アプローチを実装する方法の基本的な例を示すのは困難だと思いました。

次の例では、実装がいかに簡単か、そしてコードにどのような利点をもたらすかを説明します。

`/** オブジェクト内のすべてのメソッドを取得するためのヘルパー関数*/ const getMethods = (obj) => Object.getOwnPropertyNames(Object.getPrototypeOf(obj)).filter(item => typeof obj[item] === 'function')

/** アドバイスが指示したときにアスペクトを呼び出すカスタム関数で元のメソッドを置き換えます */ function replaceMethod(target, methodName, aspect, advice) { const originalCode = target[methodName] target[methodName] = (...args) => { if(["before", "around"].includes(advice)) { aspect.apply(target, args) } const returnedValue = originalCode.apply(target, args) if(["after", "around"].includes(advice)) { aspect.apply(target, args) } if("afterReturning" == advice) { return aspect.apply(target, [returnedValue]) } else { return returnedValue
 } } }

module.exports = { // エクスポートの主な方法: 必要なときに必要な場所にアスペクトをターゲットに注入する inject: function(target, aspect, advice, pointcut, method = null) { if(pointcut == "method") { if(method != null) { replaceMethod(target, method, aspect, advice)
} else { throw new Error("メソッドにアスペクトを追加しようとしましたが、メソッドが指定されていません") } } if(pointcut == "methods") { const methods = getMethods(target) methods.forEach( m => { replaceMethod(target, m, aspect, advice) 
}) } } }`

非常に簡単です。前述したように、上記のコードはすべてのユースケースをカバーしているわけではありませんが、次の例をカバーするには十分なはずです。

しかし、先に進む前に、 replaceMethod関数を見てみましょう。ここで魔法が起こります。新しい関数を作成できるほか、アスペクトをいつ呼び出すか、その戻り値をどのように処理するかを決定することもできます。

次に、このライブラリの使い方を説明します。

`const AOP = require("./aop.js")

クラス MyBusinessLogic {
追加(a, b) {
    console.log("add を呼び出しています")
    a + bを返す
}

連結(a, b) {
    console.log("concat を呼び出しています")
    a + bを返す
}

パワー(a, b) {
    console.log("パワーを呼び出し中")
    a ** b を返す
}
}

const o = 新しい MyBusinessLogic()

function loggingAspect(...args) { console.log("== ロガー関数を呼び出しています ==") console.log("受け取った引数: " + args) }

function printTypeOfReturnedValueAspect(value) { console.log("返された型: " + typeof value) }

AOP.inject(o,loggingAspect,"before","methods") AOP.inject(o,printTypeOfReturnedValueAspect,"afterReturning","methods")

o.add(2,2) o.concat("こんにちは", "さようなら") o.power(2, 3)`

これは 3 つのメソッドを持つ単なる基本オブジェクトであり、特別なものではありません。 2 つの汎用的なアスペクトを挿入します。1 つは受信プロパティをログに記録するためのもので、もう 1 つは戻り値を分析してその型をログに記録するためのものです。 2 つの側面、2 行のコード (6 行である必要はありません)。

これで例は終了です。出力は次のようになります。

https://camo.githubusercontent.com/f18ef187f4acddab8df097c8aa4521d632e17759bc1c0831a22ada934388d7b5/68747470733a2f2f63646e2d696d616765732d312e6d656469756d2e636f6d2f6d61782f323030302f312a394b5a42774f6262714145754a4176314757537279672e706e67

AOPの利点

AOP の概念と目的がわかったら、アスペクト指向プログラミングを使用する理由を推測できるかもしれませんが、簡単にまとめてみましょう。

  • 分野横断的な懸念事項をまとめるのに最適な方法です。私はカプセル化の大ファンです。カプセル化により、プロジェクト間で再利用できるコードが読みやすくなり、保守しやすくなるからです。
  • 柔軟なロジック。アドバイスとポイントカットを中心に実装されたロジックにより、アスペクトを注入する際に大きな柔軟性が得られます。これにより、コード ロジックのさまざまな側面を動的にオン/オフにすることができます (しゃれを意図しています)。
  • プロジェクト間で側面を再利用します。アスペクトはコンポーネント、つまりどこでも実行できる小さな分離されたコード片と考えることができます。アスペクトを正しく記述すれば、異なるプロジェクト間で簡単に共有できます。

AOPの主な問題点

すべてが完璧というわけではないので、このパラダイムには批判的な人もいます。

彼らが提起する主な問題は、その主な利点が実際にはコードのロジックと複雑さを隠すことであり、それが明確でない場合に副作用が生じる可能性があるということです。

よく考えてみると、彼らの言うことはもっともです。AOP は、既存のメソッドに無関係な動作を追加したり、ロジック全体を置き換えたりする大きな力を与えてくれます。もちろん、これがこのパラダイムが導入された正確な理由ではないかもしれませんし、私が上で示した例の意図では決してありませんでした。

ただし、やりたいことは何でもできるので、適切なプログラミング手法を理解していないと、非常に大きな混乱を招く可能性があります。

決まり文句に聞こえないように、ベンおじさんの言葉を言い換えます。

大いなる力には大いなる責任が伴う

AOP を正しく使用するには、ソフトウェア開発のベスト プラクティスを理解する必要があります。

私の意見では、このツールを使用すると多くの害を及ぼす可能性があるからといって、それが悪いツールだというわけではありません。多くの利点ももたらします (つまり、多くの共通ロジックを一元化された場所に抽出し、必要な場所に 1 行のコードでそれを挿入できます)。私にとって、これは学ぶ価値があり、間違いなく使用する価値のある強力なツールです。

アスペクト指向プログラミングは OOP を完璧に補完するものであり、特に JavaScript の動的な性質のおかげで、非常に簡単に実装できます (ここのコードで実証されているように)。大量のロジックをモジュール化および分離し、後でそのロジックを他のプロジェクトと共有するための強力な機能を提供します。

もちろん、正しく使用しないと、大変なことになります。しかし、これを使用すると、多くのコードを簡素化およびクリーンアップできることは間違いありません。これが AOP に関する私の意見ですが、あなたはどう思いますか? AOPって聞いたことありますか?以前に使ったことがありますか?ぜひ下記にコメントを残してあなたの考えを共有してください!

JavaScript での AOP プログラミングに関するこの記事はこれで終わりです。より関連性の高い js AOP プログラミング コンテンツについては、123WORDPRESS.COM で以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後も 123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • JavaScript における AOP 実装の詳細説明 (アスペクト指向プログラミング、デコレータ パターン)
  • JavaScript AOP プログラミング例
  • JavaScript AOP プログラミング例
  • Javascript AOP (アスペクト指向プログラミング) 周辺分析

<<:  Python 仮想環境のインストールとアンインストールの方法と発生する問題

>>:  Spark SQL の 4 つの一般的なデータ ソースの詳細な説明

推薦する

小規模プログラムへのデータキャッシュ機構の応用と実装

ミニプログラムデータキャッシュ関連知識データ キャッシュ: データをキャッシュして、アプレットを終了...

HTML テーブル境界制御実装コード

一般的に、テーブルを使用する場合は、常に <table border="1"...

きちんとした標準的なHTMLタグの書き方を学ぶ

優れた HTML コードは美しい Web サイトの基礎となります。私が CSS を教えるときは、まず...

Linux ディスク パーティションの実装の原理と方法の分析

覚えて: IDE ディスク: 最初のディスクは hda、2 番目のディスクは hdb...最初のディ...

Linux で MySQL データベースのデータ ファイル パスを変更する手順

rpm インストール方法を使用して MySQL データベースをインストールした後、データ ファイルの...

レスポンシブレイアウトについて知っておくべきこと

1. はじめにレスポンシブ Web デザインにより、Web サイトは複数のデバイスと複数の画面に同時...

HTML 画像 img タグ_Powernode Java アカデミー

まとめプロジェクトの説明形式<img src="..."> H2+ ...

mysql8.0.21 のダウンロードとインストールに関する詳細なチュートリアル

公式ウェブサイトアドレス: https://www.mysql.com/インストールの提案: インス...

nginx ssl を設定して https アクセスを実装する手順 (初心者向け)

序文サーバーを展開した後、私は大きな喜びを感じながら自分の Web サイトにアクセスし、見たものすべ...

さまざまなターミナルで Mac が SSH 経由でリモート サーバーに接続する方法の説明

Macはシェル(ターミナル)SSHを使用してリモートサーバーに接続します前提条件: 接続する必要があ...

Webフロントエンドの一般的な操作(JS/HTML/CSSなどの知識を含む)

ul liの前のアイコン1をキャンセルしますクリア値1値を1に設定ラベル中央値1をクリアラベルの中央...

MySQL データベースの最適化に関する 9 つのヒント

目次1. 最も適切なフィールド属性を選択する2. フィールドをNOT NULLに設定してみる3. サ...

MySQL の重要なパフォーマンス インデックスの計算と最適化方法の概要

1 QPS 計算 (1 秒あたりのクエリ数) MyISAMエンジンベースのDBの場合 MySQL&g...

Linux で time(NULL) 関数と localtime() を使用して現在の時刻を取得する方法

time(); 関数関数プロトタイプ: time_t time(time_t *timer)関数の目...

html2canvas を使用して HTML コードを画像に変換する方法

コードを画像に変換するにはhtml2canvas は、ブラウザから Web ページのスクリーンショッ...