依赖倒置原理及组成

Dependency inversion principle and composition

我正在阅读 SOLID 原则,我在“依赖倒置原则” 上停下来,这意味着对象应该已经实例化到另一个对象,这意味着 composition 不能应用 依赖倒置原则 对吗?或者有什么我想念的? 更新 ************************************************* * 假设你有一个 class 并且这个 class 有一个引用另一个对象的属性,我们有 2 个解决方案(对我来说):

  1. 在 class 之外创建对象并将其传递给 class。(依赖)
  2. 在 class 内部创建对象 it self(composition)。

谢谢。

已拍摄 from Wikipedia:

A. High-level modules should not depend on low-level modules. Both should depend on abstractions.

B. Abstractions should not depend on details. Details should depend on abstractions.

你说:

which means the objects should passed already instantiated to another object

Dependency Inversion 原则与 class 构造函数 等编程实现细节无关,它们旨在初始化对象正在建设中。

除非您将构造函数参数定义为实现而不是抽象,and/or被注入的依赖项比目标依赖项处于更高层,否则您不是违反了整个原则。

你的困惑来自于你对构图的理解。另一个人拥有的对象取决于拥有对象的生命周期。这并不意味着您必须在拥有 class.

内创建拥有的对象

如果您在 class 中创建对象,则此 class 与创建的 class 紧密耦合。您不能在不更改创建另一个的 class 的情况下交换实现。

示例:

在上图中,您有 class 客户端,它使用 class 服务器。可以说这是一个组合,客户端具有服务器类型的属性。

如果您在客户端 class 中创建 class 服务器的实例,它可能如下所示:

public class Client {
    private Server server;

    public Client(){
        this.server = new Server();
    }
}

现在假设您要交换服务器的实现。您需要更改客户端 class 的实现,因为交换它的唯一方法是创建另一个 class(可能称为 AnotherServer)的实例。

public class Client {
    private AnotherServer anotherServer;

    public Client(){
        this.anotherServer = new AnotherServer();
    }
}

这表明客户端 class 高度依赖于 class 服务器。

要轻松更改服务器的使用实现,从而修改客户端的行为,最好从抽象(抽象 classes 或接口)中组合客户端。这样做意味着您无法在拥有 class 中创建所需的对象,因为您只能创建具体的 classes。创建 classes 意味着调用构造函数并依赖于所创建的 class。

实现组合的更好方法(– 客户端由服务器组成 –)是通过 setter 方法或构造函数注入它。像这样,您可以将实现 class 隐藏在接口后面。

示例:

在第二张图片中,我们保护客户端不了解服务器的具体实现。它仅取决于服务器接口。这种依赖性并不那么显着,因为客户端定义了接口。他决定服务器接口所需的功能。为了表明服务器的接口属于客户端,它被称为 "ClientServer".

要编写您的客户端,您必须在 class 之外为 ClientServer 接口创建具体的 classes,并通过构造函数或 setter 方法注入它。

...
FirstServer first = new FirstServer();
Client client = new Client(first);

client.setServer(new SecondServer());
...

像这样您可以轻松地在客户端中交换使用过的服务器实现,甚至在运行时也是如此。

这种机制称为依赖倒置原则(DIP)。但为什么?客户端 class 仍然依赖于服务器接口。如果界面改变了,客户端也必须改变。是的,这是正确的。但是客户决定他在该界面中需要哪些功能。所以通常界面会改变,当客户说它需要改变时。界面变了,因为客户端变了。

因为具体服务器 "FirstServer" 和 "SecondServer" 实现接口 ClientServer 它们也依赖于该接口。并且因为继承是比组合更强的依赖性,所以具体服务器 classes 比客户端 class.

更依赖于接口。

这就是依赖关系颠倒的原因。具体服务器 classes 现在依赖于 "Client-ClientServer"-conglomerate。

所以你的问题的答案是:当你在另一个 class 中创建你的 class 时,你无法到达 DIP。但是您可以通过定义一个接口并注入继承该接口的具体 classes 来实现组合 DIP。