「依存性逆転の原則」の版間の差分
削除された内容 追加された内容
→History: cite_web:+deadlinkdate ほか |
m編集の要約なし |
||
1行目:
[[オブジェクト指向設計]]において
この上位レベル、下位レベルの''両方とも''抽象に依存しなければならないと言う要求により、この設計原理は一部の人々のオブジェクト指向プログラミングに対する考え方を''反転''させる
この原理について述べた上記のポイント A と B の背景にある考えは、上位モジュールと下位モジュールの相互作用を設計する際に、これらの関係が抽象的な相互作用として捉えられるべきであるということであり、これによって上位モジュールだけでなく下位レベルモジュールも設計的な影響を受けることになる
2つのモジュールの間で見出された抽象的な相互関係が一般性を持ち、かつ一般化が意味を持つとき、この設計原理は以下の依存性の逆転コーディングパターンを導く
== 従来のレイヤーパターン ==
伝統的なアプリケーションアーキテクチャーにおいて、下位レベルコンポーネント(e.g. Utility Layer)はより複雑なシステムの構築を可能にする上位レベルコンポーネント(e.g. Policy
[[ファイル:Traditional_Layers_Pattern.png|中央]]
依存性逆転パターンの目指すところは、抽象レイヤーを導入することによってこの高度に結合した状態を回避し、上位の policy layer の再利用性を高めることにある
== 依存性逆転パターン ==
抽象レイヤーを加える事により、上位レベルレイヤーと下位レベルレイヤーの両方とも top から bottom に向かう従来の依存関係を減らす事ができるが、"反転" の概念は下位レベルレイヤーが上位レベルレイヤーに依存することを意味しない
[[ファイル:DIPLayersPattern.png|中央]]
依存性逆転の直接のアプリケーションでは、抽象は上位/policy レイヤーによって所有される
依存性とオーナーシップの逆転は上位/policyレイヤーの再利用性を高め、上位レイヤーは他の低レベルサービスを利用することができるようになる
== 依存性逆転パターンの一般化 ==
多くのプロジェクトにおいて依存性逆転の原則とパターンは一般化されるべき概念であると考えられる
# 優れた考えの原則をコーディングパターンとみなすほうがよりシンプルである
# 多くのユニットテストツールがモックを作成するためにインターフェースに依存しているため、クラス間のジェネリックなインターフェースを利用することは(モジュール間に限った話ではなく一般的にも)ルールになっている
もし、インターフェースのみに依存するモック作成ツールを使用している場合、一般化された依存性逆転パターンが必要になることがあるが、これには大きな欠点がある
# クラスに対して単純にインターフェースを実装するだけでは不十分であり、一般的に結合を減らすことにはならない
# ジェネリックなインターフェースをプロジェクト内の全ての箇所で実装してしまうと、理解してメンテナンスをするのが非常に難しくなる
# インタフェースの一般化はより "plumbing code" である事が要求され、一般的に依存性注入フレームワークに依存するファクトリーなどが特にそれにあたる
#
# インターフェースの一般化はプログラミング言語の利用も制限する
=== 一般化における制約 ===
依存性逆転のパターン(DIP)を達成するためにインターフェースが存在することは、[[Object-oriented programming|オブジェクト指向プログラム]]において他の設計上の制約をもたらす:
* クラス内の全てのメンバー変数はインターフェース、もしくは抽象でなくてはならない
* 全ての具象クラスパッケージはインターフェース、もしくは抽象クラスパッケージを通してのみ結合されなければならない。
* 具象クラスを派生してはならない
* 既に実装済みのメソッドをオーバーライドしてはならない
* 全ての変数のインスタンス化において[[Factory method pattern|factory method]] もしくは[[Factory (object-oriented programming)|factory]]パターンのような[[creational pattern]]の実装が必要になる
=== インターフェースモック化の制約 ===
継承ベースのモック化ツールを使用した場合でも以下の制約が生じる
* 外部公開されている静的メンバーも体系的に依存性性注入されるべきだが、そのための実装はかなり難しい
* テスト可能な全てのモジュールはインターフェースの実装、もしくは抽象定義のオーバーライドを行う必要がある
=== 将来的な方向性 ===
原則は考えるための方法であり、パターンは問題解決のための共通手段である
* プログラミング言語は少なくとも2つの方向で、その使用においてより正確に、より強力になる方向に進化を続けるだろう
* 静的メンバーや非仮想メンバーの置き換えの問題を解決するために
== 実装 ==
DIPの2つの一般的な実装では、さまざまな意味でよく似た論理アーキテクチャを使用する
直接的な実装において、 plicy クラスと service 抽象クラスは一つのライブラリーにパッケージ化される
上位レベルコンポーネントのインターフェースは下位レベルコンポーネントによって実装されるため、コンパイル時に下位レベルコンポーネントが上位レベルコンポーネントに依存する事が必要になる
[[ファイル:Dependency_inversion.png|中央]]
Figures 1 and 2 では同じ機能を実現したコードを表現している
このバージョンの DIP では、下位レイヤーコンポーネントが上位レベルレイヤーのインターフェース/抽象に依存しているため、下位レベルレイヤーの再利用は困難になる
抽象コンポーネントをライブラリやパッケージから独立させて置くと、より柔軟性が増す
[[ファイル:DIPLayersPattern_v2.png|中央]]
83行目:
=== 家系モジュール ===
ある家系システムでは人々の間の関係を第一レベル関係のグラフとして表現するかもしれません
しかし、上位レベルモジュールでは家系をブラウズするためのより簡単な方法が必要になるかもしれません: 人には、子供、父親、母親、兄弟と姉妹(異母兄弟を含む含まないも合わせて)、祖父、祖母、伯父、伯母、従兄弟... などがいるかもしれません
家系モジュールの使用法に応じて、共通の関係を明確で直接的な属性として(グラフを隠して)表示することは上位レベルモジュールと家系モジュールの間の結合を遥かに軽くでき、モジュールの使用になんの影響も与えることなく内部表現を完全に変更することを可能にします
最終的に、もし最初の一般化された拡張可能なグラフアプローチが一番拡張可能に思えるのであれば、家系モジュールの利用は更に特殊化及び単純化された関係の実装がアプリケーションに対して十分であることを示しているかもしれませんし、より効率的なシステムを作成する手助けになるかもしれません
この例でのモジュール間の相互関係の抽象化は下位レベルモジュールのインターフェースの単純化だけでなく、より単純化された実装につながるかもしれません
=== リモートファイルサーバークライアント ===
リモートファイルサーバー(FTP, cloud strage ...)に対するクライアントを実装しなければならないケースを想像してください
# Connection/Disconnection (a connection persistence layer may be needed)
103行目:
# File history management ...
ローカルファイル、リモートファイルの両方が同じ抽象インターフェースを提供する場合、ローカルファイルと完全に実装された依存性逆転パターンを使用するどんな上位レベルモジュールもローカルとリモートの区別なくファイルにアクセスすることが可能になります
ローカルディスクは一般的にフォルダーを使用します、リモートストレージもフォルダーを使用するかもしれません(もしくはタグのみ、フォルダーとタグの両方など). もし可能であればそれらを統一する方法を決めておく必要があります
リモートファイルに対しては、作成と置換のみを行う必要があるかもしれません
ファイル検索は "pluggable" であるかもしれません: ファイル検索は OS、特にタグや全文検索に依存し、異なるシステムでも実装する事ができます
概念的なそれぞれのインターフェースに対してリモートファイルサーバーを設計するときは、上位レベルモジュールが要求するサービスのレベル (必ずしも全てが要求されるわけではない)を良く考える必要があります
必要なインターフェースの設計が完了したら、リモートファイルサーバークライアントはこれらのインターフェースを実装すべきです
また、既に存在するローカルファイルに対しての機能 (例えばファイル更新など)について制限を加えたい場合、同じ抽象インタフェースを提供するローカルまたは他の既存のリモートファイルアクセスモジュール用のアダプタを記述する必要があるかもしれません
これらが完了すると、アプリケーションはドキュメントをローカルとリモートに透過的に保存する事が可能になります
注意: 多くの OS がこの手の機能を実装し始めているため、新規実装のクライアントをこの既に存在している抽象モデルへ適用するのは控えた方が良いかもしれません
この例では、モジュールを抽象インターフェースのセットとして考え、このインターフェースのセットに他のモジュールを適合させることで、様々なファイルストレージシステムに対し、共通のインターフェースを提供する事ができます
=== Model View Controller ===
127行目:
[[ファイル:DIP_concrete_example.png|中央|Example of DIP]]
UI とアプリケーションレイヤーパッケージは主に具象クラスを含んでいて、コントローラーは抽象/インターフェース型を含んでいます
これらの直接的な効果は、UI が直接 ApplicatonLayer や、ICustomerHandler を実装したどの具象パッケージも参照する必要がない事です
== 関連するパターン ==
依存性逆転の原則の適用はアダプターパターンの一例と見ることもできます
Plugin, [[Service locator pattern|Service Locator]], or [[Dependency Injection]] などの様々なパターンは上位レベルコンポーネントに対する選択された下位レベルコンポーネントの "run-time provisioning" を容易にする目的で導入されます
== History ==
The dependency inversion principle was postulated by [[Robert C. Martin]] and described in several publications including the paper ''Object Oriented Design Quality Metrics: an analysis of dependencies'',<ref>{{Cite web|url=https://linux.ime.usp.br/~joaomm/mac499/arquivos/referencias/oodmetrics.pdf|title=Object Oriented Design Quality Metrics: An analysis of dependencies|access-date=2016-10-15|last=Martin|first=Robert C.|date=|website=|publisher=|publication-date=October 1994}}</ref> an article appearing in the C++ Report in May 1996 entitled ''The Dependency Inversion Principle'',<ref>{{Cite web|url=http://www.objectmentor.com/resources/articles/dip.pdf|title=The Dependency Inversion Principle|access-date=|last=Martin|first=Robert C.|date=May 1996|publisher=C++ Report|archiveurl=https://web.archive.org/web/20110714224327/http://www.objectmentor.com/resources/articles/dip.pdf|archivedate=2011-07-14|deadlinkdate=2018-11-12}}</ref> and the books ''Agile Software Development, Principles, Patterns, and Practices'', and ''Agile Principles, Patterns, and Practices in C#''.
==
* [[Adapter pattern]]▼
* [[SOLID (object-oriented design)|SOLID]] – the "D" in "SOLID" stands for the dependency inversion principle▼
{{Reflist}}
==
* [[依存性の注入]]
* [[契約プログラミング]]
* [[インタフェース (情報技術)]]
* [[制御の反転]]
* [[プラグイン]]
* {{仮リンク|Service locator pattern|en|Service locator pattern}}
▲*
== 外部リンク ==
* [https://linux.ime.usp.br/~joaomm/mac499/arquivos/referencias/oodmetrics.pdf Object Oriented Design Quality Metrics: an analysis of dependencies Robert C. Martin, C++ Report, Sept/Oct 1995]
* [https://web.archive.org/web/20110714224327/http://www.objectmentor.com/resources/articles/dip.pdf The Dependency Inversion Principle, Robert C. Martin, C++ Report, May 1996]
160 ⟶ 158行目:
* [http://martinfowler.com/articles/dipInTheWild.html DIP in the Wild, Brett L. Schuchert, May 2013]
* [http://blog.sebaslab.com/tag/dependency-injection/ IoC Container for Unity3D – part 2]
{{SOLID (オブジェクト指向設計)}}
<!--Categories-->
[[カテゴリ:ソフトウェアパターン]]
[[Category:Programming principles]]
|