>  기사  >  백엔드 개발  >  SOLID: 4부 - 종속성 반전 원칙

SOLID: 4부 - 종속성 반전 원칙

PHPz
PHPz원래의
2023-09-01 19:49:061051검색

단일 책임(SRP), 개방형/폐쇄형(OCP), Liskov 대체, 인터페이스 격리 및 종속성 반전. 코드를 작성할 때마다 안내해야 하는 5가지 민첩한 원칙.

어떤 SOLID 원칙이 다른 원칙보다 더 중요하다고 말하는 것은 불공평할 것입니다. 그러나 종속성 반전 원칙(DIP)보다 코드에 직접적이고 심오한 영향을 미치는 것은 없을 것입니다. 다른 원칙을 이해하거나 적용하기 어렵다면 이 원칙부터 시작한 다음 이미 DIP를 따르는 코드에 나머지 원칙을 적용하세요.

정의

A. 상위 수준 모듈은 하위 수준 모듈에 의존해서는 안 됩니다. 둘 다 추상화에 의존해야 합니다.

B. 추상화는 세부사항에 의존해서는 안 됩니다. 세부 사항은 추상화에 따라 달라집니다.

이 원칙은 로버트 C. 마틴(Robert C. Martin)이 그의 저서 "Agile Software Development, Principles, Patterns, and Practices"에서 정의했으며 나중에 C# 버전의 "Agile Princips, Patterns, and Practices in C#"에 다시 출판되었습니다. 5가지 SOLID Agile 원칙 중 마지막 원칙입니다.

실제 세계에서의 딥

코딩을 시작하기 전에 한 가지 이야기를 들려드리고 싶습니다. Syneto에서는 코드에 항상 그렇게 주의를 기울이지는 않습니다. 몇 년 전만 해도 우리는 아는 것이 거의 없었고 최선을 다했지만 모든 프로젝트가 그렇게 좋은 것은 아니었습니다. 우리는 지옥과 역경을 겪었고 시행착오를 통해 많은 것을 배웠습니다.

Bob 삼촌(Robert C. Martin)의 SOLID 원칙과 아키텍처 단순성 원칙은 우리에게 게임 체인저였으며 설명하기 어려운 방식으로 코딩 방식을 변경했습니다. 간단히 말해서, 우리 프로젝트에 큰 영향을 미친 DIP에 의해 구현된 주요 아키텍처 결정 중 일부를 설명하려고 노력할 것입니다.

대부분의 웹 프로젝트에는 HTML, PHP 및 SQL의 세 가지 주요 기술이 포함되어 있습니다. 우리가 이야기하고 있는 이러한 애플리케이션의 특정 버전이나 사용하는 SQL 구현 유형은 중요하지 않습니다. 문제는 HTML 양식의 정보가 어떻게든 데이터베이스에 저장되어야 한다는 것입니다. 둘 사이의 연결은 PHP로 제공될 수 있습니다.

가장 중요한 것은 이 세 가지 기술이 사용자 인터페이스, 비즈니스 로직, 지속성이라는 세 가지 아키텍처 계층을 매우 잘 표현한다는 것입니다. 나중에 이 레이어의 의미에 대해 논의하겠습니다. 이제 이러한 기술을 함께 작동시키기 위해 이상하지만 자주 접하게 되는 몇 가지 솔루션에 초점을 맞춰 보겠습니다.

HTML 파일 내의 PHP 태그에 SQL 코드를 사용하거나 HTML 페이지를 에코하고 $_GET$_POST전역 변수를 직접 해석하는 PHP 코드를 사용하는 프로젝트를 여러 번 보았습니다. 그런데 이것이 왜 나쁜가요?

SOLID: 第四部分 - 依赖倒置原则SOLID: 4부 - 종속성 반전 원칙SOLID: 第四部分 - 依赖倒置原则

위 이미지는 이전 단락에서 설명한 원본 버전을 나타냅니다. 화살표는 다양한 종속성을 나타내며 기본적으로 모든 것이 모든 것에 의존한다고 결론을 내릴 수 있습니다. 데이터베이스 테이블을 변경해야 하는 경우 HTML 파일을 편집하게 될 수도 있습니다. 또는 HTML의 필드를 변경하면 결국 SQL 문의 열 이름이 변경될 수 있습니다. 또는 두 번째 패턴을 살펴보면 HTML이 변경되면 PHP를 수정해야 할 가능성이 높으며, 매우 나쁜 경우에는 PHP 파일 내부에서 모든 HTML 콘텐츠를 생성할 때 반드시 변경해야 합니다. HTML 콘텐츠를 수정하려면 PHP 파일을 사용하세요. 따라서 클래스와 모듈 간의 종속성이 비뚤어진다는 것은 의심의 여지가 없습니다. 하지만 거기서 끝나지 않았습니다. SQL 테이블에 PHP 코드를 저장할 수 있습니다.

SOLID: 第四部分 - 依赖倒置原则SOLID: 4부 - 종속성 반전 원칙SOLID: 第四部分 - 依赖倒置原则

위 스키마에서 SQL 데이터베이스에 대한 쿼리는 테이블의 데이터를 사용하여 생성된 PHP 코드를 반환합니다. 이러한 PHP 함수 또는 클래스는 다른 PHP 코드를 반환하는 다른 SQL 쿼리를 실행하고 있으며 결국 모든 정보를 가져와서 UI로 다시 반환할 때까지 루프가 계속됩니다.

이 말이 많은 분들에게 터무니없게 들릴 수도 있다는 것을 알고 있지만, 이런 방식으로 고안되고 구현된 프로젝트에 참여하지 않았다면 미래의 경력에서도 분명히 그렇게 할 것입니다. 프로그래밍 언어에 관계없이 대부분의 기존 프로젝트는 관심이 없거나 더 나은 방법을 모르는 프로그래머에 의해 오래된 원칙에 따라 작성되었습니다. 이 튜토리얼을 읽고 있다면 이미 더 높은 수준에 도달했을 가능성이 높습니다. 당신은 당신의 직업을 존중하고, 당신의 기술을 포용하고, 더 나은 일을 할 준비가 되어 있습니다.

대안은 이전 사람들의 실수를 반복하고 그 결과를 겪는 것입니다. Syneto에서는 우리 프로젝트 중 하나가 오래되고 상호 의존적인 아키텍처로 인해 거의 유지 관리가 불가능한 상태에 도달하여 기본적으로 이를 영원히 포기해야 했을 때 더 이상 그 길을 따르지 않기로 결정했습니다. 그 이후로 우리는 SOLID 원칙과 가장 중요하게는 종속성 반전 원칙을 적절히 존중하면서 깔끔한 아키텍처를 갖기 위해 노력해 왔습니다.

SOLID: 第四部分 - 依赖倒置原则SOLID: 4부 - 종속성 반전 원칙SOLID: 第四部分 - 依赖倒置原则

이 아키텍처의 마법은 종속성을 가리키는 방식입니다.

  • 사용자 인터페이스(대부분의 경우 웹 MVC 프레임워크) 또는 프로젝트의 기타 전달 메커니즘은 비즈니스 로직에 따라 달라집니다. 비즈니스 로직은 상당히 추상적입니다. 사용자 인터페이스는 매우 구체적입니다. UI는 프로젝트의 하나의 세부 사항일 뿐이며 많이 변경됩니다. 그 어떤 것도 UI에 의존해서는 안 되며, MVC 프레임워크에 의존해서는 안 됩니다.
  • 우리가 할 수 있는 또 다른 흥미로운 관찰은 비즈니스 로직에 따라 지속성, 데이터베이스, MySQL 또는 PostgreSQL입니다. 귀하의 비즈니스 논리는 데이터베이스에 독립적입니다. 이를 통해 원하는 경우 지속성을 교환할 수 있습니다. 내일 MySQL을 PostgreSQL로 변경하거나 일반 텍스트 파일로 변경하고 싶다면 그렇게 할 수 있습니다. 물론 새로운 지속성 방법을 위해 특정 지속성 계층을 구현해야 하지만 비즈니스 로직에서 코드 한 줄도 수정할 필요는 없습니다. 지속성 주제는 지속성 레이어로의 진화 튜토리얼에서 더 자세히 설명됩니다.
  • 마지막으로 비즈니스 로직 오른쪽에는 비즈니스 로직 클래스를 생성하는 모든 클래스가 있습니다. 이는 애플리케이션의 진입점에서 생성된 팩토리와 클래스입니다. 많은 사람들은 이것이 비즈니스 로직에 속한다고 생각하는 경향이 있지만, 비즈니스 객체를 생성할 때 유일한 이유는 그렇게 하기 위한 것입니다. 이는 다른 클래스를 생성하는 데 도움이 되는 클래스일 뿐입니다. 이들이 제공하는 비즈니스 객체와 논리는 이러한 팩토리와 독립적입니다. 단순 팩토리, 추상 팩토리, 빌더 또는 단순 객체 생성과 같은 다양한 패턴을 사용하여 비즈니스 로직을 제공할 수 있습니다. 그것은 중요하지 않습니다. 비즈니스 객체가 생성되면 해당 작업을 수행할 수 있습니다.

코드 표시

전통적인 애자일 디자인 패턴을 존중한다면 아키텍처 수준에서 DIP(종속성 역전 원칙)를 적용하는 것은 매우 쉽습니다. 비즈니스 로직을 연습하고 예제를 제공하는 것도 쉽고 재미있습니다. 전자책 리더 애플리케이션을 상상해 보겠습니다.

으아악

우리는 e-reader를 PDF 리더로 개발하기 시작했습니다. 여태까지는 그런대로 잘됐다. PDFBookPDFReader 类。读者上的 read() 函数委托给本书的 read() 方法。我们只是通过在 PDFBookreader() 메서드에서 반환된 문자열의 핵심 부분을 사용하여 이를 확인하는 정규식 검사가 있습니다.

이것은 단지 예일 뿐이라는 점을 기억하세요. PDF 파일이나 기타 파일 형식에 대한 읽기 논리는 구현하지 않습니다. 이것이 바로 우리 테스트가 일부 기본 문자열만 검사하는 이유입니다. 실제 애플리케이션을 작성한다면 유일한 차이점은 다양한 파일 형식을 테스트하는 방법뿐입니다. 종속성 구조는 우리의 예와 매우 유사합니다.

SOLID: 第四部分 - 依赖倒置原则SOLID: 4부 - 종속성 반전 원칙SOLID: 第四部分 - 依赖倒置原则

拥有一个使用 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: 4부 - 종속성 반전 원칙SOLID: 第四部分 - 依赖倒置原则

我们的读者变得更加抽象。更一般。我们有一个通用的 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: 4부 - 종속성 반전 원칙SOLID: 第四部分 - 依赖倒置原则

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

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

우리는 이 숫자를 중심으로 코드를 작성하도록 노력해야 하며 이를 수행하는 데 도움이 될 수 있는 몇 가지 기술이 있습니다. 함수의 길이는 우리 머리에 동시에 들어갈 수 있도록 최대 4줄(정의 줄을 포함해 5줄)이어야 합니다. 압입 깊이는 5겹을 초과하지 않습니다. 메서드가 9개 이하인 클래스입니다. 일반적으로 5~9가지 클래스의 디자인 패턴이 사용됩니다. 위 패턴의 고급 디자인에서는 4~5가지 개념을 사용합니다. 5개의 SOLID 원칙이 있으며, 각 원칙에는 5~9개의 하위 개념/모듈/클래스를 예시해야 합니다. 프로그래밍 팀의 이상적인 규모는 5~9명입니다. 회사의 이상적인 팀 수는 5~9개입니다.

보시다시피 마법의 숫자 7, 더하기 또는 빼기 2는 우리 주변에 있는데 왜 코드가 달라야 합니까?

위 내용은 SOLID: 4부 - 종속성 반전 원칙의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.