java - 依赖倒置原则(适用于 Java)

标签 java oop solid-principles dependency-inversion

我正在自学 S.O.L.I.D. 中涉及的原则。面向对象编程,我无法理解字母 D(依赖倒置原则)中的所有细节。

我正在阅读它在维基百科 (http://en.wikipedia.org/wiki/Dependency_inversion_principle) 中的条目,但我不理解图表中的所有内容:

http://en.wikipedia.org/wiki/Dependency_inversion_principle#/media/File:DIPLayersPattern_v2.png )

我注意到有两种不同类型的箭头 - 一种是虚线,一种是实线。

根据我目前的理解,虚线表示相当于 Java 中的“implements”关键字,而实线表示关键字“extends”。

这是正确的解释吗?

最佳答案

这可能会澄清一些事情:

Explanation of the UML arrows

请注意图像是针对 Visual Studio 的,但我认为大部分信息与大多数 UML 文档等同。

The dashed line represents the equivalent of "implements"

UML 中实体的命名也让我有点困惑...看来 Policy 依赖于一个接口(interface),该接口(interface)描述了 Mechanism 的较低级别模块的契约(Contract)

但是在第二条(实线)上应该代表继承(至少我相信)。 Mechanism 实现接口(interface)(抽象)Policy,而不是在 Policy 引用具体的 Mechanism 之前应用 DIP .

它主要试图传达的是类不应该依赖于其他类,但是它们可以依赖于抽象(接口(interface))而不是具体。

最简单的示例:原始的 Foo/Logger 依赖于较低级别的模块。

// "Low level Module" Mechanism equivilant
public class Logger {
    public void logInformation(String logInfo) {
        System.out.println(logInfo);
    }
}

// "High level module" Policy equivalent.
public class Foo {
    // direct dependency of a low level module.
    private Logger logger = new Logger();

    public void doStuff() {
        logger.logInformation("Something important.");
    }
}

上面的Foo依赖于Logger的具体实现。这可以这样重构(注意有几种方法可以做到这一点,这只是其中一种)

public interface ILogger {
    void logInformation(String logInfo);
}

public class Logger implements ILogger {
    @Override
    public void logInformation(string logInfo) {
        System.out.println(logInfo);
    }
}

public class Foo {
    private ILogger logger;
    public void setLoggerImpl(ILogger loggerImpl) {
        this.logger = loggerImpl;
    }

    public void doStuff() {
        logger.logInformation("Something important.");
    }
}

在此重构中,Foo 不再依赖于 Logger,但现在使用接口(interface) ILogger - 这意味着您可以切换并在运行时输出 ILogger 的实现、对象实例化等。

您可以这样使用 Foo:

Foo foo = new Foo();
ILogger logger = new Logger();
foo.setLoggerImpl(logger);
foo.doStuff();

这当然会打印以控制台“重要的事情”。现在,如果您不想登录到控制台,而是登录到数据库,会发生什么情况?

public class LoggerToDb implements ILogger {
    @Override
    public void logInformation(string logInfo) {
        DbContext databaseContext = new DbContext();
        databaseContext.insertLog(logInfo);
    }
}

现在可以消费为:

Foo foo = new Foo();
ILogger logger = new LoggerToDb();
foo.setLoggerImpl(logger);
foo.doStuff();

请注意,您的 Foo 实现无需任何更改,因为 Foo 不依赖于 Logger,而是依赖于 ILogger - 通过这种方法,我们可以为抽象提供新的具体化,并将其交换为 Foo 而无需触及 Foo!漂亮的 neato IMO。

请注意,在上面的示例中,我正在构建对象并提供实现,这也可以使用 Java 的 Spring 等 IOC 框架来完成。

关于java - 依赖倒置原则(适用于 Java),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29778275/

相关文章:

java - 几个 jar 中的 freemarker 模板

java - PSQL异常 : ERROR: duplicate key value violates unique constraint when using Hibernate

c# - 如何有效地从数据存储加载对象模型?

php - Magento:从数据库中选择

java - 开闭和接口(interface)隔离

java - && 和 || 的区别

java - 同时运行多个Asyntask

javascript - 无需ajax即可预先填写表单中的字段

javascript - 打破 JavaScript 中的依赖关系

c# - 如何避免转换到特定界面