「依存性逆転の原則」の版間の差分
削除された内容 追加された内容
m bot: 解消済み仮リンクSOLIDを内部リンクに置き換えます |
m Bot作業依頼#Cite webテンプレートのdeadlink、deadlinkdate引数の移行 |
||
(9人の利用者による、間の13版が非表示) | |||
1行目:
[[オブジェクト指向プログラミング|オブジェクト指向]]における従来の依存関係とは、上位モジュールから下位モジュールへの方向性であり、仕様定義を担う上位モジュールを、詳細実装を担う下位モジュールから独立させて、各下位モジュールを別個保存するというものだったが、それに対して依存性逆転原則は以下二点を提唱している<ref name="Martin2003">{{cite book|last1=Martin|first1=Robert C.|title=Agile Software Development, Principles, Patterns, and Practices|url=https://books.google.com/books/about/Agile_Software_Development.html?id=0HYhAQAAIAAJ&redir_esc=y|year=2003|publisher=Prentice Hall|isbn=978-0135974445|pages=127–131}}</ref>。
# 上位モジュールはいかなるものも下位モジュールから持ち込んではならない。双方とも抽象(例としてインターフェース)に依存するべきである。<br/>"High-level modules should not import anything from low-level modules. Both should depend on abstractions (e.g., interfaces)."<ref name=":0">{{Cite web|title=Dependency Inversion Principle|url=http://www.objectmentor.com/resources/articles/dip.pdf|archiveurl=https://web.archive.org/web/20150905081103/http://www.objectmentor.com/resources/articles/dip.pdf|archivedate=5 September 2015|website=objectmentor.com|accessdate=2015-09-05|publisher=}}</ref>
この上位レベル、下位レベルの''両方とも''抽象に依存しなければならないと言う要求により、この設計原理は一部の人々のオブジェクト指向プログラミングに対する考え方を''反転''させる。<ref>{{cite journal|last1=Freeman|first1=Eric|last2=Freeman|first2=Elisabeth|last3=Kathy|first3=Sierra|last4=Bert|first4=Bates|editor2-last=Loukides|editor2-first=Mike|year=2004|title=Head First Design Patterns|url=http://shop.oreilly.com/product/9780596007126.do|volume=1|pages=|publisher=O'REILLY|accessdate=2012-06-21|format=paperback|isbn=978-0-596-00712-6|authorlink1=|authorlink2=|authorlink3=|authorlink4=|editor1-last=Hendrickson|editor1-first=Mike|editor-link1=|editor-link2=}}</ref>▼
# 抽象は詳細に依存してはならない。詳細(具象的な実装内容)が抽象に依存するべきである。<br/>"Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions."<ref name=":0" />
▲この上位
この原理について述べた上記のポイント A と B の背景にある考えは、上位モジュールと下位モジュールの相互作用を設計する際に、これらの関係が抽象的な相互作用として捉えられるべきであるということであり、これによって上位モジュールだけでなく下位レベルモジュールも設計的な影響を受けることになる。下位モジュールは相互作用を念頭に設計されるべきで、その結果自身を使用するためのインターフェースについて変更を行う必要が生じる可能性がある。多くの場合、相互作用を抽象的な概念として捉えることにより追加のコーディングパターンを導入せずにコンポーネント間の結合を減らすことができ、より軽量で実装への依存が少ない総合作用スキーマを用いるだけで済むようになる。▼
▲この
2つのモジュールの間で見出された抽象的な相互関係が一般性を持ち、かつ一般化が意味を持つとき、この設計原理は以下の依存性の逆転コーディングパターンを導く。▼
▲
依存性逆転の原則は、アメリカのソフトウェア技術者{{仮リンク|ロバート・C・マーティン|en|Robert C. Martin|label=}}によって確立され、彼の論文「オブジェクト指向設計品質指標 - Object Oriented Design Quality Metrics」内の「依存性の分析 - an analysis of dependencies」節を含んだ2000年以降の数々の出版物に記載されていた<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>。「Agile Software Development, Principles, Patterns, and Practices」「Agile Principles, Patterns, and Practices in C#」などのアジャイル系がよく知られる。
依存性逆転の原則と銘打たれたのは、1996年5月のC++研究論文の記事内とされている<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|url-status=dead|url-status-date=2018-11-12}}</ref>。
== 従来のレイヤーパターン ==
48 ⟶ 55行目:
* 全ての変数のインスタンス化において[[Factory Method パターン|Factory Method]]もしくは{{仮リンク|Factory パターン|en|Factory (object-oriented programming)}}のような{{仮リンク|生成に関するパターン|en|Creational pattern}}の実装が必要になる。もしくは[[依存性の注入|DI]]フレームワークが必要になる。
=== インターフェース・モック化の制約 ===
継承ベースのモック化ツールを使用した場合でも以下の制約が生じる。
* 外部公開されている静的メンバーも体系的に依存
* テスト可能な全てのモジュールはインターフェースの実装、もしくは抽象定義のオーバーライドを行う必要がある。
63 ⟶ 70行目:
DIPの2つの一般的な実装では、さまざまな意味でよく似た論理アーキテクチャを使用する。
直接的な実装において、
上位レベルコンポーネントのインターフェースは下位レベルコンポーネントによって実装されるため、コンパイル時に下位レベルコンポーネントが上位レベルコンポーネントに依存する事が必要になる。よって従来の依存関係は逆転する。
71 ⟶ 78行目:
Figures 1 and 2 では同じ機能を実現したコードを表現している。しかし、 Figure 2 ではインターフェースは依存性を逆転させるために使用されている。policy コードの再利用性を最大化したり、循環依存を排除するために依存の方向は選択することができる。
このバージョンの DIP では、下位レイヤーコンポーネントが上位レベルレイヤーのインターフェース/抽象に依存しているため、下位レベルレイヤーの再利用は困難になる。 この実装はその
抽象コンポーネントをライブラリやパッケージから独立させて置くと、より柔軟性が増す。
77 ⟶ 84行目:
[[ファイル:DIPLayersPattern_v2.png|中央]]
全てのレイヤーを分離して個別のパッケージに置くことでどのレイヤーの再利用性も向上し、ロバストネス性とモビリティーを得ることができる
== 例 ==
=== 家系モジュール ===
ある家系システムでは人々の間の関係を第一レベル関係のグラフとして表現するかもしれ
しかし、上位レベルモジュールでは家系をブラウズするためのより簡単な方法が必要になるかもしれ
家系モジュールの使用法に応じて、共通の関係を明確で直接的な属性として(グラフを隠して)表示することは上位レベルモジュールと家系モジュールの間の結合を遥かに軽くでき、モジュールの使用になんの影響も与えることなく内部表現を完全に変更することを可能に
最終的に、もし最初の一般化された拡張可能なグラフアプローチが一番拡張可能に思えるのであれば、家系モジュールの利用は更に特殊化及び単純化された関係の実装がアプリケーションに対して十分であることを示しているかもしれ
この例でのモジュール間の相互関係の抽象化は下位レベルモジュールのインターフェースの単純化だけでなく、より単純化された実装につながるかもしれ
=== リモートファイル・サーバ
リモートファイルサーバー(FTP, cloud strage ...)に対するクライアントを実装しなければならないケースを想像
# Connection/Disconnection (a connection persistence layer may be needed)
102 ⟶ 108行目:
# File history management ...
ローカルファイル、リモートファイルの両方が同じ抽象インターフェースを提供する場合、ローカルファイルと完全に実装された依存性逆転パターンを使用するどんな上位レベルモジュールもローカルとリモートの区別なくファイルにアクセスすることが可能にな
ローカルディスクは一般的にフォルダーを使用し
リモートファイルに対しては、作成と置換のみを行う必要があるかもしれ
ファイル検索は "pluggable" であるかもしれ
概念的なそれぞれのインターフェースに対してリモートファイルサーバーを設計するときは、上位レベルモジュールが要求するサービスのレベル (必ずしも全てが要求されるわけではない)を良く考える必要があ
必要なインターフェースの設計が完了したら、リモートファイルサーバークライアントはこれらのインターフェースを実装すべきで
また、既に存在するローカルファイルに対しての機能 (例えばファイル更新など)について制限を加えたい場合、同じ抽象インタフェースを提供するローカルまたは他の既存のリモートファイルアクセスモジュール用のアダプタを記述する必要があるかもしれ
これらが完了すると、アプリケーションはドキュメントをローカルとリモートに透過的に保存する事が可能にな
注意: 多くの OS がこの手の機能を実装し始めているため、新規実装のクライアントをこの既に存在している抽象モデルへ適用するのは控えた方が良いかもしれ
この例では、モジュールを抽象インターフェースのセットとして考え、このインターフェースのセットに他のモジュールを適合させることで、様々なファイルストレージシステムに対し、共通のインターフェースを提供する事ができ
=== Model View Controller ===
[[ファイル:DIP_concrete_example.png|中央|Example of DIP]]
UI とアプリケーションレイヤーパッケージは主に具象クラスを含んでいて、コントローラーは抽象/インターフェース型を含んでい
これらの直接的な効果は、UI が直接 ApplicatonLayer や、ICustomerHandler を実装したどの具象パッケージも参照する必要がない事で
== 関連するパターン ==
依存性逆転の原則の適用はアダプターパターンの一例と見ることもでき
Plugin, [[Service Locator パターン|Service Locator]], or [[依存性の注入|Dependency Injection]] などの様々なパターンは上位レベルコンポーネントに対する選択された下位レベルコンポーネントの "run-time provisioning" を容易にする目的で導入されます。▼
▲Plugin, [[Service Locator パターン|Service Locator]], or [[依存性の注入|Dependency Injection]] などの様々なパターンは上位レベルコンポーネントに対する選択された下位レベルコンポーネントの "run-time provisioning" を容易にする目的で導入され
▲== History ==
==
{{Reflist}}
144 ⟶ 146行目:
* [[Adapter パターン]]
* [[依存性の注入]]
* [[契約プログラミング|契約による設計]]
* [[インタフェース (情報技術)]]
* [[制御の反転]]
* [[プラグイン]]
* {{仮リンク|
* [[SOLID]]
* [[インベンターのパラドックス]]
== 外部リンク ==
157 ⟶ 160行目:
* [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:プログラミング原則]]
|