序文
この章では、LSP(依存関係の反転原則)であるSolid JavaScript言語の5つの主要な原則の実装の第5章を説明します。
オリジナル英語のテキスト:http://freshbrewedcode.com/derekgreeer/2012/01/22/solid-javascript-the-pedency-inversion-principle/
信頼反転原理
依存関係の反転の原則の説明は次のとおりです。
A.高レベルのモジュールは、低レベルのモジュールに依存してはなりません。どちらも抽象化に依存する必要があります。
高レベルのモジュールは低レベルのモジュールに依存してはならず、どちらも抽象化に依存する必要があります
B.抽象化は詳細に依存してはなりません。詳細は抽象化に依存する必要があります。
要約は詳細に依存しないでください、詳細は抽象化に依存する必要があります
依存関係の原則の最も重要な問題は、アプリケーションまたはフレームワークの主なコンポーネントが、重要でない基礎コンポーネントの実装の詳細から切り離されることを保証することです。
この原則の最初の部分は、高レベルモジュールと低レベルモジュール間の結合に関するものです。従来の部門アーキテクチャでは、高レベルのモジュール(プログラムのコアビジネスロジックをカプセル化する)は、常にいくつかの低レベルモジュール(いくつかの基本的なポイント)に依存しています。依存関係の反転の原理が適用されると、関係は逆になります。低レベルモジュールに依存する高レベルモジュールとは異なり、依存関係の反転により、低レベルのモジュールは高レベルモジュールで定義されたインターフェイスに依存します。たとえば、プログラムのデータを保持する場合、従来の設計は、コアモジュールが永続的なモジュールのAPIに依存することです。依存関係の反転の原則に従って再構築した後、コアモジュールは永続的なAPIインターフェイスを定義する必要があり、その後、永続的な実装インスタンスは、コアモジュールによって定義されたAPIインターフェイスを実装する必要があります。
この原則の2番目の部分は、抽象化と詳細の間の正しい関係を説明しています。この部分を理解することは、C ++言語を理解することにより、その適用性がより明白であるため、より役立ちます。
いくつかの静的にタイプされた言語とは異なり、C ++はインターフェイスを定義する言語レベルの概念を提供しません。クラスの定義とクラスの実装との関係は何ですか? C ++では、クラスはヘッダーファイルの形で定義されており、ソースファイルが実装する必要があるクラスメンバーのメソッドと変数を定義します。すべての変数とプライベートメソッドはヘッダーファイルで定義されているため、実装の詳細の前にそれらを抽象化および分離するために使用できます。インターフェイスの概念は、抽象的なメソッドのみを定義することによって実装されます(C ++の抽象的なベースクラス)は、クラスを実装するために使用されます。
ディップとJavaScript
JavaScriptは動的な言語であるため、デカップリングのために抽象化する必要はありません。したがって、抽象化は詳細に依存してはなりません。この変更はJavaScriptにあまり影響を与えませんが、高レベルのモジュールは低レベルのモジュールに依存するのではなく、大きな影響を与えるべきです。
静的にタイプされた言語のコンテキストで依存関係の反転の原理を議論するとき、結合の概念にはセマンティックと物理が含まれます。これは、高レベルのモジュールが低レベルモジュールに依存する場合、セマンティックインターフェイスだけでなく、基礎となるモジュールで定義されている物理インターフェイスも結びつけることを意味します。言い換えれば、高レベルのモジュールは、サードパーティライブラリからだけでなく、ネイティブの低レベルモジュールからも切り離される必要があります。
これを説明するために、.NETプログラムには、低レベルの永続的なモジュールに依存する非常に便利な高レベルモジュールが含まれている可能性があると想像してください。著者が依存関係の反転原理が使用されているかどうかに関係なく、Persistence APIに同様のインターフェイスを追加する必要がある場合、この低レベルモジュールの新しいインターフェイスを再実装する前に、高レベルモジュールを他のプログラムで再利用できません。
JavaScriptでは、依存関係の反転の原理の適用性は、高レベルモジュールと低レベルモジュール間のセマンティック結合に限定されています。たとえば、DIPは、低レベルモジュールで定義された暗黙のインターフェイスを結合する代わりに、必要に応じてインターフェイスを追加できます。
これを理解するには、次の例を見てみましょう。
コードコピーは次のとおりです。
$ .fn.trackmap = function(options){
var defaults = {
/ *デフォルト */
};
options = $ .extend({}、defaults、options);
var mapoptions = {
センター:新しいGoogle.maps.latlng(options.latitude、options.longitude)、
ズーム:12、
maptypeid:google.maps.maptypeid.roadmap
}、
map = new Google.maps.map(this [0]、mapoptions)、
pos = new Google.maps.latlng(options.latitude、options.longitude);
var marker = new google.maps.marker({
ポジション:PO、
タイトル:options.title、
アイコン:options.icon
});
Marker.setMap(Map);
options.feed.update(function(緯度、経度){
Marker.setMap(null);
var newlatlng = new Google.maps.latlng(緯度、経度);
Marker.position = newlatlng;
Marker.setMap(Map);
map.setcenter(newlatlng);
});
これを返します。
};
var updater =(function(){
//私有地
戻る {
更新:function(callback){
updatemap = callback;
}
};
})();
$( "#map_canvas")。トラックマップ({
緯度:35.044640193770725、
経度:-89.98193264007568、
アイコン: 'http://bit.ly/zjngde'、
タイトル: '追跡番号:12345'、
フィード:アップデーター
});
上記のコードには、Divをマップに変換して現在追跡されている位置情報を表示する小さなJSクラスライブラリがあります。トラックマップ関数には、サードパーティのGoogleマップAPIとロケーションフィードの2つの依存関係があります。フィードオブジェクトの責任は、アイコンの位置が更新され、緯度緯度と精度経度に合格したときにコールバックコールバック(初期化時に提供)を呼び出すことです。 Google Maps APIは、インターフェイスをレンダリングするために使用されます。
フィードオブジェクトのインターフェイスは、インストールトラックマップ関数の要件に従って設計されていないか、設計されていない場合があります。実際、その役割は非常に単純であり、単純な異なる実装に焦点を当てており、Googleマップにそれほど依存する必要はありません。トラックマップセマンティクスは、GoogleマップAPIに結合されています。さまざまなマッププロバイダーに切り替える必要がある場合は、トラックマップ機能を書き換えて、異なるプロバイダーに適応できるようにする必要があります。
Google Mapsクラスライブラリのセマンティックカップリングを反転するには、デザイントラックマップ関数をセマンティック結合に書き換える必要があります。また、GoogleマップAPIに適合した実装オブジェクトも必要です。以下は、リファクタリングされたトラックマップ関数です。
コードコピーは次のとおりです。
$ .fn.trackmap = function(options){
var defaults = {
/ *デフォルト */
};
options = $ .extend({}、defaults、options);
options.provider.showmap(
この[0]、
options.latitude、
options.longitude、
options.icon、
options.title);
options.feed.update(function(緯度、経度){
options.provider.updatemap(緯度、経度);
});
これを返します。
};
$( "#map_canvas")。トラックマップ({
緯度:35.044640193770725、
経度:-89.98193264007568、
アイコン: 'http://bit.ly/zjngde'、
タイトル: '追跡番号:12345'、
フィード:アップデーター、
プロバイダー:trackmap.googlemapsprovider
});
このバージョンでは、トラックマップ関数と必要なMAPプロバイダーインターフェイスを再設計し、実装の詳細を個別のGoogleMapsProviderコンポーネントに移動しました。これが私のGoogleMapsProviderの実装です:
コードコピーは次のとおりです。
trackmap.googlemapsprovider =(function(){
varマーカー、MAP;
戻る {
showmap:function(要素、緯度、経度、アイコン、タイトル){
var mapoptions = {
センター:新しいGoogle.maps.latlng(緯度、経度)、
ズーム:12、
maptypeid:google.maps.maptypeid.roadmap
}、
pos = new Google.maps.latlng(緯度、経度);
map = new Google.maps.map(element、mapoptions);
Marker = new Google.maps.marker({
ポジション:PO、
タイトル:タイトル、
アイコン:アイコン
});
Marker.setMap(Map);
}、
updatemap:function(緯度、経度){
Marker.setMap(null);
var newlatlng = new Google.maps.latlng(緯度、経度);
Marker.position = newlatlng;
Marker.setMap(Map);
map.setcenter(newlatlng);
}
};
})();
上記の変更を加えた後、トラックマップ関数は非常に柔軟になり、GoogleマップAPIに依存する必要はありません。代わりに、他のマッププロバイダーは自由に交換できます。つまり、どのマッププロバイダーもプログラムのニーズに応じて適応できます。
依存関係はいつですか?
それは少し無関係です。実際、依存関係注射の概念は、依存関係の反転の原理としばしば混合されます。この違いを明確にするためには、説明する必要があります。
依存関係は、制御の反転の特別な形式であり、反転とはコンポーネントが依存関係を獲得する方法を意味します。依存関係の噴射とは、依存関係を取得するためにコンポーネントではなくコンポーネントに依存関係が提供されます。これは、依存関係のインスタンスを作成し、工場を介した依存関係を要求し、サービスロケーターまたはコンポーネント自体を介した依存関係を要求することを意味します。依存関係の反転原理と依存関係の注入はどちらも依存関係に焦点を当てており、どちらも反転に使用されます。ただし、依存関係の反転の原則は、コンポーネントが依存関係を獲得する方法ではなく、低レベルモジュールからハイレベルモジュールがどのように分離されているかにのみ焦点を当てています。ある意味では、依存関係の反転の原理は、制御反転の別の形式です。ここで、反転は、モジュールがインターフェイスを定義するものです(低レベルから定義された、反転、より高いレベルへ)。
要約します
これは、5つの主要な原則の最後の記事です。これらの5つの記事では、JavaScriptで固体がどのように実装されているかがわかります。 JavaScriptのさまざまな角度からさまざまな原則が説明されています。 (おじさんのメモ:実際、それは少し不適切ですが、別の観点からは、一般原則は実際にはさまざまな言語で同じであると思います。)