我正在自学 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”。
这是正确的解释吗?
最佳答案
这可能会澄清一些事情:
请注意图像是针对 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/