単一責任 (SRP)、オープン/クローズド (OCP)、リスコフ置換、インターフェース分離、および 依存関係反転。コードを書くときに常に指針となるアジャイルの 5 つの原則。
ある堅固な原則が他の原則よりも重要であると言うのは不公平でしょう。ただし、おそらく、依存性反転原則 (略して DIP) ほど、コードに直接的かつ重大な影響を与えるものはありません。他の原則を理解したり適用したりするのが難しい場合は、この原則から始めて、残りの原則をすでに DIP に従うコードに適用してください。
###意味###B. 抽象化は詳細に依存すべきではありません。詳細は抽象化に依存する必要があります。
この原則は、Robert C. Martin の著書『アジャイル ソフトウェア開発、原則、パターン、および実践』で定義され、後に書籍『Agile Principles, Patterns, and Practices in C#』の C# バージョンで再公開されました。これは、SOLID アジャイルの 5 つの原則の最後の原則です。
現実世界でのDIP
ボブおじさん (ロバート C. マーティン) の SOLID 原則とアーキテクチャのシンプルさの原則は、私たちにとって大きな変革をもたらし、説明するのが難しい方法でコーディング方法を変えました。つまり、私たちのプロジェクトに大きな影響を与えた、DIP によって実装された主要なアーキテクチャ上の決定のいくつかを説明してみます。
ほとんどの Web プロジェクトには、HTML、PHP、SQL という 3 つの主要なテクノロジが含まれています。ここで話しているアプリケーションの特定のバージョンや、使用する SQL 実装の種類は関係ありません。問題は、HTML フォームからの情報が何らかの方法でデータベースに保存されなければならないことです。この 2 つの間の接着剤は PHP によって提供されます。
最も重要なことは、これら 3 つのテクノロジが、ユーザー インターフェイス、ビジネス ロジック、永続性という 3 つの異なるアーキテクチャ層をよく表しているということです。これらのレイヤーが何を意味するかについては後ほど説明します。ここで、これらのテクノロジーを連携させるための、奇妙な、しかしよく遭遇する解決策に焦点を当てましょう。
HTML ファイル内の PHP タグで SQL コードを使用しているプロジェクトや、HTML ページをエコーして
$_GET または $_POST
グローバルを直接解釈する PHP コードを使用しているプロジェクトを何度も見てきました。変数。しかし、なぜこれが悪いのでしょうか?
これは多くの人にとってとんでもないことのように聞こえるかもしれませんが、この方法で考案され実行されたプロジェクトに参加したことがない場合は、将来のキャリアで間違いなく参加するでしょう。既存のプロジェクトのほとんどは、プログラミング言語に関係なく、古い原則に基づいて、それを気にしない、またはより良くする方法を知らないプログラマーによって書かれています。これらのチュートリアルを読んでいる場合は、すでに高いレベルに到達している可能性があります。あなたは自分の職業を尊重し、自分の技術を受け入れ、それをより良くする準備ができています、または準備ができています。
もう一つの選択肢は、先人たちの間違いを繰り返し、その結果に苦しむことです。 Syneto では、私たちのプロジェクトの 1 つが、古く相互依存したアーキテクチャーのためにほぼ保守不可能な状態に達し、基本的にそれを永久に放棄しなければならなかったとき、もうその道を歩まないことに決めました。それ以来、私たちは SOLID 原則、そして最も重要なことに依存関係逆転の原則を適切に尊重しながら、クリーンなアーキテクチャを実現するよう努めてきました。
このアーキテクチャの魅力は、依存関係がどのように示されるかです:
従来のアジャイル設計パターンを尊重していれば、依存性反転原則 (DIP) をアーキテクチャ レベルで適用するのは非常に簡単です。ビジネス ロジックの例を示して練習することも簡単で楽しいです。電子書籍リーダーアプリを想定してみます。
リーリー私たちは電子書籍リーダーを PDF リーダーとして開発し始めました。ここまでは順調ですね。 PDFBook
を使用する PDFReader
クラスがあります。リーダーの read()
関数は、書籍の read()
メソッドに委譲します。 PDFBook
の reader()
メソッドによって返された文字列の重要な部分の後で正規表現チェックを行うことで、これを検証しました。
これは単なる例であることに注意してください。 PDF ファイルやその他のファイル形式の読み取りロジックは実装しません。このため、テストではいくつかの基本的な文字列のみをチェックします。実際のアプリケーションを作成する場合、唯一の違いは、さまざまなファイル形式をテストする方法です。依存関係の構造はこの例と非常によく似ています。
拥有一个使用 PDF 书籍的 PDF 阅读器对于有限的应用程序来说可能是一个合理的解决方案。如果我们的范围是编写一个 PDF 阅读器,仅此而已,那么它实际上是一个可以接受的解决方案。但我们想编写一个通用的电子书阅读器,支持多种格式,其中我们第一个实现的版本是 PDF。让我们重命名我们的读者类。
class Test extends PHPUnit_Framework_TestCase { function testItCanReadAPDFBook() { $b = new PDFBook(); $r = new EBookReader($b); $this->assertRegExp('/pdf book/', $r->read()); } } class EBookReader { private $book; function __construct(PDFBook $book) { $this->book = $book; } function read() { return $this->book->read(); } } class PDFBook { function read() { return "reading a pdf book."; } }
重命名没有功能上的反作用。测试仍在通过。
测试于下午 1:04 开始...
PHPUnit 3.7.28 由 Sebastian Bergmann 编写。
时间:13 毫秒,内存:2.50Mb
好的(1 个测试,1 个断言)
进程已完成,退出代码为 0
但它具有严重的设计效果。
我们的读者变得更加抽象。更一般。我们有一个通用的 EBookReader
,它使用非常具体的书籍类型 PDFBook
。抽象取决于细节。我们的书是 PDF 类型这一事实应该只是一个细节,任何人都不应该依赖它。
class Test extends PHPUnit_Framework_TestCase { function testItCanReadAPDFBook() { $b = new PDFBook(); $r = new EBookReader($b); $this->assertRegExp('/pdf book/', $r->read()); } } interface EBook { function read(); } class EBookReader { private $book; function __construct(EBook $book) { $this->book = $book; } function read() { return $this->book->read(); } } class PDFBook implements EBook{ function read() { return "reading a pdf book."; } }
反转依赖关系最常见、最常用的解决方案是在我们的设计中引入一个更抽象的模块。 “OOP 中最抽象的元素是接口。因此,任何其他类都可以依赖于接口并且仍然遵循 DIP”。
我们为读者创建了一个界面。该接口名为 EBook
,代表 EBookReader
的需求。这是尊重接口隔离原则 (ISP) 的直接结果,该原则提倡接口应反映客户端需求的理念。接口属于客户端,因此它们的命名反映了客户端需要的类型和对象,并且它们将包含客户端想要使用的方法。 EBookReader
使用 EBooks
并拥有 read()
方法是很自然的。
我们现在有两个依赖项,而不是单个依赖项。
EBookReader
指向 EBook
接口,并且它是类型用法。 EBookReader
使用 EBooks
。PDFBook
指向相同的 EBook
接口,但它是类型实现。 PDFBook
只是 EBook
的一种特殊形式,因此实现了该接口来满足客户的需求。不出所料,该解决方案还允许我们将不同类型的电子书插入阅读器。所有这些书籍的唯一条件是满足 EBook
接口并实现它。
class Test extends PHPUnit_Framework_TestCase { function testItCanReadAPDFBook() { $b = new PDFBook(); $r = new EBookReader($b); $this->assertRegExp('/pdf book/', $r->read()); } function testItCanReadAMobiBook() { $b = new MobiBook(); $r = new EBookReader($b); $this->assertRegExp('/mobi book/', $r->read()); } } interface EBook { function read(); } class EBookReader { private $book; function __construct(EBook $book) { $this->book = $book; } function read() { return $this->book->read(); } } class PDFBook implements EBook { function read() { return "reading a pdf book."; } } class MobiBook implements EBook { function read() { return "reading a mobi book."; } }
这又将我们引向开闭原则,并且圆圈是闭合的。
依赖倒置原则是引导或帮助我们尊重所有其他原则的原则。尊重 DIP 将:
就是这样。我们完了。所有有关 SOLID 原理的教程均已完成。对我个人来说,发现这些原则并在实施项目时牢记它们是一个巨大的变化。我完全改变了我对设计和架构的思考方式,我可以说从那时起我从事的所有项目都变得更加容易管理和理解。
我认为 SOLID 原则是面向对象设计最基本的概念之一。这些概念必须指导我们使我们的代码变得更好,并使我们作为程序员的生活变得更加轻松。设计良好的代码更容易让程序员理解。计算机很聪明,无论代码多么复杂,它们都可以理解。另一方面,人类能够在活跃、专注的头脑中保存的事物数量有限。更具体地说,此类事物的数量是神奇数字七、正负二。
これらの数値に基づいてコードを構成するように努める必要があります。これを行うのに役立つテクニックがいくつかあります。関数は同時に頭の中に収まるように、最大 4 行 (定義行を含めて 5 行) の長さにする必要があります。くぼみの深さは 5 層を超えません。メソッドが 9 つ以下のクラス。通常、5 ~ 9 クラスのデザイン パターンが使用されます。上記のパターンの高レベルの設計では、4 ~ 5 つのコンセプトが使用されています。 SOLID 原則には 5 つあり、それぞれの原則で 5 ~ 9 つのサブ概念/モジュール/クラスを例示する必要があります。プログラミング チームの理想的な規模は 5 ~ 9 人です。社内の理想的なチーム数は 5 ~ 9 です。
ご覧のとおり、魔法の数字 7 (プラスまたはマイナス 2) は私たちの身の回りに溢れているのに、なぜコードが異なる必要があるのでしょうか?
以上がSOLID: パート 4 - 依存関係逆転の原則の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。