【问题标题】:Dependency inversion principle and composition依赖倒置原理及组成
【发布时间】:2017-01-30 03:39:48
【问题描述】:

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

  1. 在类外创建对象并将其传递给类。(依赖)
  2. 在它自己的类中创建对象(组合)。

谢谢。

【问题讨论】:

  • 我在这里没有看到任何矛盾。一个对象是由构造函数中传递给它的一些其他对象组成的,那又如何呢?
  • 我猜你正在混淆类之间的依赖关系和对象之间的依赖关系。当然,组合对象取决于其组件。但这并不意味着如果您使用抽象(接口),则类之间存在依赖关系。
  • @FrankPuffer 我可以使用依赖注入的组合吗?

标签: oop dependency-injection solid-principles


【解决方案1】:

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

如果您在类中创建对象,则该类与创建的类紧密耦合。如果不更改创建另一个类的类,就无法交换实现。

示例:

在上图中,您有类 Client,它使用类 Server。假设这是一个组合,客户端具有服务器类型的属性。

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

public class Client {
    private Server server;

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

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

public class Client {
    private AnotherServer anotherServer;

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

这向您表明,Client 类高度依赖于 Server 类。

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

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

示例:

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

要组成您的客户端,您必须在类外部为 ClientServer 接口创建具体类,并通过构造函数或 setter 方法将其注入。

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

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

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

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

因为具体的服务器“FirstServer”和“SecondServer”实现了接口ClientServer,所以它们也依赖于该接口。而且由于继承比组合更依赖,具体的服务器类比客户端类更依赖接口。

这就是依赖倒置的原因。具体的服务器类现在依赖于“Client-ClientServer”-conglomerate。

因此,您的问题的答案是:当您在另一个班级中创建班级时,您无法达到 DIP。但是你可以通过定义一个接口并注入继承这个接口的具体类来实现 DIP。

【讨论】:

  • 如果我需要使用 .NET Framework 中的类。我必须将其注入课堂吗?
【解决方案2】:

拍摄from Wikipedia

A.高级模块不应该依赖于低级模块。两者都应该依赖于抽象。

B.抽象不应该依赖于细节。细节应该取决于抽象。

你说:

这意味着对象应该已经实例化传递给另一个对象

依赖倒置原则不反对像类构造函数这样的编程实现细节,它旨在初始化正在构造的对象。

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

【讨论】:

  • 很高兴知道为什么我得到了反对票来改进我的答案。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-09
  • 2013-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-20
  • 1970-01-01
相关资源
最近更新 更多