Heim  >  Artikel  >  Backend-Entwicklung  >  SOLID: Teil 4 – Prinzip der Abhängigkeitsinversion

SOLID: Teil 4 – Prinzip der Abhängigkeitsinversion

PHPz
PHPzOriginal
2023-09-01 19:49:061051Durchsuche

Single Responsibility (SRP), Open/Closed (OCP), Liskov-Substitution, Schnittstellenisolation und Abhängigkeitsumkehr. Fünf agile Prinzipien, die Sie jedes Mal leiten sollten, wenn Sie Code schreiben.

Es wäre unfair, Ihnen zu sagen, dass ein SOLIDEs Prinzip wichtiger ist als ein anderes. Allerdings hat vielleicht keines so direkte und tiefgreifende Auswirkungen auf Ihren Code wie das Dependency Inversion Principle, kurz DIP. Wenn es Ihnen schwer fällt, andere Prinzipien zu verstehen oder anzuwenden, beginnen Sie mit diesem und wenden Sie dann die restlichen Prinzipien auf Code an, der bereits dem DIP folgt.

Definition

A. High-Level-Module sollten nicht von Low-Level-Modulen abhängen. Beide sollten sich auf Abstraktionen stützen.

B. Abstraktionen sollten nicht von Details abhängen. Die Details sollten von der Abstraktion abhängen.

Dieses Prinzip wurde von Robert C. Martin in seinem Buch „Agile Software Development, Principles, Patterns, and Practices“ definiert und später in der C#-Version im Buch „Agile Principles, Patterns, and Practices in C#“ erneut veröffentlicht letztes Prinzip der fünf SOLID-Agile-Prinzipien.

TAUCHEN Sie in die reale Welt ein

Bevor wir mit dem Codieren beginnen, möchte ich Ihnen eine Geschichte erzählen. Bei Syneto gehen wir mit unserem Code nicht immer so vorsichtig um. Vor ein paar Jahren wussten wir sehr wenig und obwohl wir unser Bestes gaben, waren nicht alle Projekte so gut. Wir sind durch die Hölle und zurück gegangen und haben durch Versuch und Irrtum viel gelernt.

Onkel Bobs (Robert C. Martin) SOLID-Prinzipien und architektonische Einfachheitsprinzipien waren für uns bahnbrechend und haben die Art und Weise, wie wir programmieren, auf eine Weise verändert, die schwer zu beschreiben ist. Kurz gesagt, ich werde versuchen, einige der wichtigsten von DIP umgesetzten Architekturentscheidungen zu veranschaulichen, die einen erheblichen Einfluss auf unser Projekt hatten.

Die meisten Webprojekte enthalten drei Haupttechnologien: HTML, PHP und SQL. Es spielt keine Rolle, um welche spezifische Version dieser Anwendungen es sich handelt oder welche Art von SQL-Implementierung Sie verwenden. Das Problem ist, dass die Informationen aus dem HTML-Formular irgendwie in der Datenbank landen müssen. Den Kleber zwischen den beiden kann PHP bereitstellen.

Das Wichtigste ist, dass diese drei Technologien drei verschiedene Architekturebenen sehr gut abbilden: Benutzeroberfläche, Geschäftslogik und Persistenz. Wir werden später besprechen, was diese Ebenen bedeuten. Konzentrieren wir uns nun auf einige seltsame, aber oft anzutreffende Lösungen, um diese Technologien zusammenarbeiten zu lassen.

Ich habe oft gesehen, dass Projekte SQL-Code in PHP-Tags in HTML-Dateien verwenden, oder PHP-Code, der die HTML-Seite widerspiegelt und $_GET$_POSTglobale Variablen direkt interpretiert. Aber warum ist das schlimm?

SOLID: 第四部分 - 依赖倒置原则SOLID: Teil 4 – Prinzip der AbhängigkeitsinversionSOLID: 第四部分 - 依赖倒置原则

Das Bild oben stellt die Originalversion dar, die wir im vorherigen Absatz beschrieben haben. Die Pfeile stellen verschiedene Abhängigkeiten dar und wir können daraus schließen, dass im Grunde alles von allem abhängt. Wenn wir Änderungen an einer Datenbanktabelle vornehmen müssen, müssen wir möglicherweise die HTML-Datei bearbeiten. Oder wenn wir ein Feld im HTML ändern, ändern sich möglicherweise auch die Spaltennamen in der SQL-Anweisung. Oder wenn wir uns das zweite Muster ansehen: Wenn sich der HTML-Code ändert, müssen wir höchstwahrscheinlich PHP ändern, oder in einem sehr schlimmen Fall, wenn wir den gesamten HTML-Inhalt aus der PHP-Datei generieren, müssen wir definitiv Änderungen vornehmen die PHP-Datei zum Ändern von HTML-Inhalten. Es besteht also kein Zweifel daran, dass die Abhängigkeiten zwischen Klassen und Modulen kompliziert sind. Aber damit war es noch nicht getan. Kann Prozeduren speichern; PHP-Code in SQL-Tabellen.

SOLID: 第四部分 - 依赖倒置原则SOLID: Teil 4 – Prinzip der AbhängigkeitsinversionSOLID: 第四部分 - 依赖倒置原则

Im obigen Schema gibt die Abfrage der SQL-Datenbank PHP-Code zurück, der mithilfe der Daten in der Tabelle generiert wurde. Diese PHP-Funktionen oder -Klassen führen andere SQL-Abfragen aus, die anderen PHP-Code zurückgeben, und die Schleife wird fortgesetzt, bis schließlich alle Informationen abgerufen und zurückgegeben werden ... möglicherweise zurück an die Benutzeroberfläche.

Ich weiß, das mag für viele von Ihnen unverschämt klingen, aber wenn Sie noch nicht an einem auf diese Weise erfundenen und umgesetzten Projekt beteiligt waren, werden Sie dies in Ihrer zukünftigen Karriere auf jeden Fall tun. Die meisten existierenden Projekte, unabhängig von der Programmiersprache, werden nach alten Prinzipien geschrieben, von Programmierern, denen es egal ist oder die nicht wissen, wie sie es besser machen können. Wenn Sie diese Tutorials lesen, stehen die Chancen gut, dass Sie bereits ein höheres Niveau erreicht haben. Sie sind bereit oder bereit, Ihren Beruf zu respektieren, Ihr Handwerk anzunehmen und es besser zu machen.

Die Alternative besteht darin, die Fehler derer zu wiederholen, die vor Ihnen waren, und die Konsequenzen zu tragen. Als bei Syneto eines unserer Projekte aufgrund seiner alten und voneinander abhängigen Architektur einen nahezu unhaltbaren Zustand erreichte und wir es praktisch endgültig aufgeben mussten, entschieden wir uns, diesen Weg nicht mehr zu beschreiten. Seitdem streben wir nach einer sauberen Architektur, die die SOLID-Prinzipien und vor allem das Abhängigkeitsinversionsprinzip angemessen respektiert.

SOLID: 第四部分 - 依赖倒置原则SOLID: Teil 4 – Prinzip der AbhängigkeitsinversionSOLID: 第四部分 - 依赖倒置原则

Die Magie dieser Architektur liegt darin, wie die Abhängigkeiten aufgezeigt werden:

  • Die Benutzeroberfläche (in den meisten Fällen das Web-MVC-Framework) oder ein anderer Bereitstellungsmechanismus des Projekts hängt von der Geschäftslogik ab. Geschäftslogik ist ziemlich abstrakt. Die Benutzeroberfläche ist sehr spezifisch. Die Benutzeroberfläche ist nur ein Detail eines Projekts und verändert sich stark. Nichts sollte von der Benutzeroberfläche abhängen, nichts sollte von Ihrem MVC-Framework abhängen.
  • Eine weitere interessante Beobachtung, die wir machen können, ist Persistenz, Datenbank, MySQL oder PostgreSQL, abhängig von der Geschäftslogik. Ihre Geschäftslogik ist datenbankunabhängig. Dadurch kann die Persistenz bei Bedarf ausgetauscht werden. Wenn Sie morgen MySQL auf PostgreSQL oder nur auf reine Textdateien umstellen möchten, können Sie das tun. Natürlich müssen Sie für die neue Persistenzmethode eine bestimmte Persistenzschicht implementieren, aber Sie müssen keine einzige Codezeile in Ihrer Geschäftslogik ändern. Das Thema Persistenz wird im Tutorial „Evolving to a Persistence Layer“ ausführlicher erläutert.
  • Schließlich haben wir auf der rechten Seite der Geschäftslogik, außerhalb davon, alle Klassen, die die Geschäftslogikklassen erstellen. Dies sind die Fabriken und Klassen, die vom Einstiegspunkt unserer Anwendung erstellt wurden. Viele Leute denken, dass diese zur Geschäftslogik gehören, aber wenn sie Geschäftsobjekte erstellen, besteht ihr einziger Grund darin, dies zu tun. Es sind lediglich Klassen, die uns beim Erstellen anderer Klassen helfen. Die von ihnen bereitgestellten Geschäftsobjekte und Logik sind von diesen Fabriken unabhängig. Wir können Geschäftslogik mithilfe verschiedener Muster bereitstellen, z. B. einfache Fabrik, abstrakte Fabrik, Builder oder einfache Objekterstellung. Es spielt keine Rolle. Sobald Geschäftsobjekte erstellt sind, können sie ihre Arbeit erledigen.

Code anzeigen

Die Anwendung des Dependency Inversion Principle (DIP) auf Architekturebene ist sehr einfach, wenn Sie klassische agile Designmuster respektieren. Es ist auch einfach und macht sogar Spaß, Geschäftslogik zu üben und Beispiele dafür zu geben. Wir stellen uns eine E-Book-Reader-Anwendung vor.

class Test extends PHPUnit_Framework_TestCase {

	function testItCanReadAPDFBook() {
		$b = new PDFBook();
		$r = new PDFReader($b);

		$this->assertRegExp('/pdf book/', $r->read());
	}

}

class PDFReader {

	private $book;

	function __construct(PDFBook $book) {
		$this->book = $book;
	}

	function read() {
		return $this->book->read();
	}

}

class PDFBook {

	function read() {
		return "reading a pdf book.";
	}
}

Wir haben begonnen, den E-Reader zu einem PDF-Reader zu entwickeln. So weit, ist es gut. Wir führen eine Regex-Prüfung durch, um dies anhand des Schlüsselteils der von der PDFBookPDFReader 类。读者上的 read() 函数委托给本书的 read() 方法。我们只是通过在 PDFBookreader()-Methode zurückgegebenen Zeichenfolge zu überprüfen.

Bitte denken Sie daran, dass dies nur ein Beispiel ist. Wir werden keine Leselogik für PDF-Dateien oder andere Dateiformate implementieren. Aus diesem Grund werden in unserem Test nur einige grundlegende Zeichenfolgen überprüft. Wenn wir eine echte Anwendung schreiben würden, bestünde der einzige Unterschied darin, wie wir verschiedene Dateiformate testen. Die Abhängigkeitsstruktur ist unserem Beispiel sehr ähnlich.

SOLID: 第四部分 - 依赖倒置原则SOLID: Teil 4 – Prinzip der AbhängigkeitsinversionSOLID: 第四部分 - 依赖倒置原则

拥有一个使用 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

但它具有严重的设计效果。

SOLID: 第四部分 - 依赖倒置原则SOLID: Teil 4 – Prinzip der AbhängigkeitsinversionSOLID: 第四部分 - 依赖倒置原则

我们的读者变得更加抽象。更一般。我们有一个通用的 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() 方法是很自然的。

SOLID: 第四部分 - 依赖倒置原则SOLID: Teil 4 – Prinzip der AbhängigkeitsinversionSOLID: 第四部分 - 依赖倒置原则

我们现在有两个依赖项,而不是单个依赖项。

  • 第一个依赖项从 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 将:

  • 几乎迫使您遵守 OCP。
  • 允许您分离职责。
  • 让你正确使用子类型。
  • 为您提供隔离界面的机会。

最终想法

就是这样。我们完了。所有有关 SOLID 原理的教程均已完成。对我个人来说,发现这些原则并在实施项目时牢记它们是一个巨大的变化。我完全改变了我对设计和架构的思考方式,我可以说从那时起我从事的所有项目都变得更加容易管理和理解。

我认为 SOLID 原则是面向对象设计最基本的概念之一。这些概念必须指导我们使我们的代码变得更好,并使我们作为程序员的生活变得更加轻松。设计良好的代码更容易让程序员理解。计算机很聪明,无论代码多么复杂,它们都可以理解。另一方面,人类能够在活跃、专注的头脑中保存的事物数量有限。更具体地说,此类事物的数量是神奇数字七、正负二。

Wir sollten danach streben, unseren Code auf diesen Zahlen aufzubauen, und es gibt verschiedene Techniken, die uns dabei helfen können. Funktionen sollten maximal vier Zeilen lang sein (fünf Zeilen inklusive Definitionszeile), damit sie gleichzeitig in unseren Kopf passen. Die Eindringtiefe darf fünf Schichten nicht überschreiten. Klassen mit nicht mehr als neun Methoden. Typischerweise werden fünf bis neun Klassen von Entwurfsmustern verwendet. Unser High-Level-Design im obigen Muster verwendet vier bis fünf Konzepte. Es gibt fünf SOLID-Prinzipien, die jeweils die Veranschaulichung von fünf bis neun Unterkonzepten/Modulen/Klassen erfordern. Die ideale Größe für ein Programmierteam beträgt fünf bis neun Personen. Die ideale Anzahl an Teams in einem Unternehmen liegt bei fünf bis neun.

Wie Sie sehen, ist die magische Zahl sieben, plus oder minus zwei, überall um uns herum. Warum sollte Ihr Code also anders sein?

Das obige ist der detaillierte Inhalt vonSOLID: Teil 4 – Prinzip der Abhängigkeitsinversion. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn