JavaScript jQueryで依存性逆転の原則を説明するのを手伝ってくれる人はいますか?
これらの2つのポイントを強調して説明します。
A.高レベルのモジュールは低レベルのモジュールに依存するべきではありません。どちらも抽象化に依存する必要があります。
B.抽象化は詳細に依存するべきではありません。詳細は抽象化に依存する必要があります。
抽象化または高/低レベルモジュールとは何ですか?
これは私の理解に本当に役立ちます、ありがとう!
JavaScript jQueryで依存性逆転の原則を説明するのを手伝ってくれる人はいますか?
これらの2つのポイントを強調して説明します。
A.高レベルのモジュールは低レベルのモジュールに依存するべきではありません。どちらも抽象化に依存する必要があります。
B.抽象化は詳細に依存するべきではありません。詳細は抽象化に依存する必要があります。
抽象化または高/低レベルモジュールとは何ですか?
これは私の理解に本当に役立ちます、ありがとう!
DIPは、ほとんどのプログラミング言語に適用されるのとほぼ同じ方法でJavaScriptに適用されると思いますが、ダックタイピングの役割に注意する必要があります。私が何を意味するかを確認するために例を見てみましょう...
サーバーにデータを問い合わせたいとしましょう。DIPを適用しない場合、これは次のようになります。
$.get("/address/to/data", function (data) {
$("#thingy1").text(data.property1);
$("#thingy2").text(data.property2);
});
DIPを使用すると、代わりに次のようなコードを記述できます。
fillFromServer("/address/to/data", thingyView);
ここで、 jQueryのAjaxを使用したい特定のケースの抽象化fillFromServer
は次のように実装できます。
function fillFromServer(url, view) {
$.get(url, function (data) {
view.setValues(data);
});
}
また、IDを持つ要素に基づいて、ビューの特定のケースに対して抽象化をview
実装できます。thingy1
thingy2
var thingyView = {
setValues: function (data) {
$("#thingy1").text(data.property1);
$("#thingy2").text(data.property2);
}
};
原則A:
fillFromServer
低レベルのモジュールに属し、サーバーとビューの間の低レベルの相互作用を処理します。たとえば、settingsUpdater
オブジェクトは上位レベルのモジュールの一部であり、抽象化に依存しますfillFromServer
---この場合はjQueryを介して実装される詳細には依存しません。fillFromServer
その作業を実行するためにDOM要素とそのIDの詳細に依存しません。代わりに、それはの抽象化に依存します。view
その目的のためには、setValues
メソッドを持つ任意のタイプです。(これが「ダックタイピング」の意味です。)原則B:
これは、ダックタイピングを使用しているため、JavaScriptでは少し見づらいです。特に、のようなものview
は、ある種のviewInterface
タイプから派生していません(つまり、依存しています)。しかし、私たちの特定のインスタンスであるthingyView
、は、抽象化に「依存する」詳細view
であると言えます。
現実的には、呼び出し元がどの種類のメソッドを呼び出す必要があるかを理解しているという事実、つまり呼び出し元が適切な抽象化を認識しているという事実に「依存」しています。通常のオブジェクト指向言語ではthingyView
、抽象化自体への明示的な依存関係を確認する方が簡単です。このような言語では、抽象化はインターフェイス(たとえば、IView
C#またはViewable
Java)で具体化され、明示的な依存関係は継承(class ThingyView : IView
またはclass ThingyView implements Viewable
)を介して行われます。ただし、同じ感情が当てはまります。
なんでこんなにかっこいいの?text1
ある日、サーバーデータをIDとのtext2
代わりに<span />
IDのテキストボックスに入れる必要があったthingy1
としましょうthingy2
。さらに、このコードが非常に頻繁に呼び出され、ベンチマークにより、jQueryを使用することで重要なパフォーマンスが失われていることが明らかになったとします。view
次に、次のように、抽象化の新しい「実装」を作成できます。
var textViewNoJQuery = {
setValues: function (data) {
document.getElementById("text1").value = data.property1;
document.getElementById("text2").value = data.property2;
}
};
次に、ビュー抽象化のこの特定のインスタンスを抽象化に挿入しますfillFromServer
。
fillFromServer("/address/to/data", textViewNoJQuery);
これはコードの変更を必要としませんでした。これは、メソッドを使用したafillFromServer
の抽象化のみに依存し、DOMの詳細やアクセス方法には依存しないためです。これは、コードを再利用できるという点で満足のいくものであるだけでなく、懸念事項を明確に分離し、非常に将来性のあるコードを作成したことも示しています。view
setValues
編集:
これは、生のJavaScriptでのDIPの使用法と、不完全なjQueryの例を示しています。ただし、以下の説明はjQueryに簡単に適用できます。下部にあるjQueryの例を参照してください。
最良の方法は、「ラッパー」とも呼ばれる「アダプターパターン」を利用することです。
アダプタは基本的に、依存関係に同じ一貫したインターフェイスを提供するようにオブジェクトまたはモジュールをラップする方法です。これにより、依存クラス(通常は上位クラス)が同じタイプのモジュールを簡単に交換できます。
この例は、Geo / Mappingモジュールに依存する高レベル(または上記)モジュールです。
これを分析してみましょう。上記のモジュールがすでにGoogleMapsを使用しているが、管理者がLeafletMapsを使用する方が安価であると判断した場合、からなどgMap.showMap(user, latLong)
へのすべてのメソッド呼び出しを書き直す必要はありませんleaflet.render(apiSecret,latLong, user)
。これは、アプリケーションをあるフレームワークから別のフレームワークにこの方法で移植しなければならないという悪夢です。
必要なもの:上記のモジュールに同じ一貫したインターフェイスを提供する「ラッパー」が必要です。これは、すべての下位レベルのモジュール(またはインフラモジュール)に対して実行されます。
さまざまな簡単な例を次に示します。
var infra1 = (function(){
function alertMessage(message){
alert(message);
}
return {
notify: alertMessage
};
})();
var infra2 = (function(){
function logMessage(message){
console.log(message);
}
return {
notify: logMessage
};
})();
var Supra = function(writer){
var notifier = writer;
function writeMessage(msg){
notifier.notify(msg);
}
this.writeNotification = writeMessage;
};
var supra;
supra = new Supra(infra1);
supra.writeNotification('This is a message');
supra = new Supra(infra2);
supra.writeNotification('This is a message');
使用する低レベルモジュールの「書き込み」のタイプ(この場合はinfra1
およびinfra2
)に関係なく、高レベルモジュールの実装を書き直す必要がないことに注意してくださいSupra
。これは、DIPが「IoC」(制御の反転)と「DI」(依存性注入)という2つの異なるソフトウェア設計原則を利用しているためです。
私が出くわした最も良い例えは、以下に示す写真です。
すべての電源は、それに接続する必要があるもののタイプに固有のインターフェースに依存しています。
jQueryの説明:
このパターンは、jQueryなどのフレームワークの使用に簡単に適用できます。1つの例は、単純なDOM-Queryハンドルです。DIPを使用してルーズカップリングを可能にすることで、フレームワークを切り替えたり、ネイティブDOM-Queryメソッドに依存したりする場合でも、メンテナンスが簡単になります。
var jQ = (function($){
return {
getElement: $
};
})(jQuery);
var nativeModule = (function(){
return {
getElement: document.querySelector
};
})();
var SupraDOMQuery = function(api){
var helper = api, thus = this;
function queryDOM(selector){
el = helper.getElement(selector);
return thus;
}
this.get = queryDOM;
};
var DOM;
DOM = new SupraDOMQuery(jQ);
DOM.get('#id.class');
DOM = new SupraDOMQuery(nativeModule);
DOM.get('#id.class');
明らかに、この例が実用的であるためには、より多くの機能が必要になりますが、それが意味を理解することを願っています。
基本的に、アダプタとファサードの違いはやや些細なものになります。ファサードでは、おそらくAPIまたは別のモジュールをラップする単一のモジュールを見ています。一方、アダプタは、モジュールごとに一貫性のあるFacade APIを作成し、この手法を利用して密結合を回避します。
JavaScriptデザインパターンの本のほとんどは、アダプターパターンを超えています。特に「jQueryアダプタ」を取り上げているのは、 O'Reillyによって公開されているAddyOsmaniによるLearningJavaScriptDesignPatternsです。ただし、Apressが発行したDustinDiazとRossHarmesによるProJavaScriptDesignPatternsを調べることもお勧めします。チェックしてください。それでも、jQueryに関連してDIPを実装する予定のコンテキストを理解することが重要だと思います。
これが物事を明確にするのに役立つことを願っています:)
これが私の理解であり、フィードバックをいただければ幸いです。重要なテストは「誰が力を持っているか」です。
従来の実装では
高レベル(HL)コード->低レベル(LL)コード。
だから例えば
LLコード
function LLdoAlert(text) { alert(message); }
function LLdoConsole(text) { console.log(message); }
HLコード
LLdoAlert('Hi there');
LLdoConsole('Hi there');
ここでLLコードに力があります。LL関数名を変更します。たとえば、HLコードが壊れます。
依存性逆転の原則
高レベル(HL)コード-> HL / LLサービスインターフェース<-低レベル(LL)コード。
HLコードがサービスインターフェイスも所有している場合。だから例えば
HLコード
var HLdoOutputSI = {
exec: function(method, text) {
if (this[method]) this[method](text);
},
register: function(name, fn) {
this[name] = fn;
}
}
HLdoOutputSI.exec('alert', 'Hi there');
HLdoOutputSI.exec('console', 'Hi there');
LLコード:
HLdoOutputSI.register('alert', function(text) { alert(message); });
HLdoOutputSI.register('console', function(text) { console.log(message); }
ここで、関数を登録するLLコード項目をいくつでも持つことができますが、HLコードを壊すものはありません。(登録されていない場合、機能はスキップされます)。LLコードを再生したい場合は、HLコード方式に従う必要があります。つまり、パワーがLLからHLにシフトしました。
JavaScriptjQueryの依存性逆転の原則
DIとjQueryの間には何の関係もありません。DIは、コンポーネントからの構造と組み立てアプリケーションに関するものです。jQueryはDOMの便利なラッパーであり、構造やコンポーネントはありません。
DIを使用してJavaScriptアプリケーションをアセンブリできますが、jQueryを使用するかどうかに関係なく、ほとんど同じように見えます。