Sar*_*ari 15 java spring inversion-of-control decoupling
假设我们在包A中有A类,在包B中有B类.如果类A的对象引用了类B,那么这两个类被认为在它们之间具有耦合.
为了解决耦合问题,建议在包A中定义一个接口,该接口由包B中的类实现.然后,类A的对象可以引用包A中的接口.这通常是"依赖倒置"的一个例子.
这是"在接口级别解耦两个类"的示例.如果是,那么它如何消除类之间的耦合并在两个类耦合时保留相同的功能?
Tur*_*g85 40
让我们创建一个虚构的例子.
A包装类packageA:
package packageA;
import packageB.B;
public class A {
private B myB;
public A() {
this.myB = new B();
}
public void doSomethingThatUsesB() {
System.out.println("Doing things with myB");
this.myB.doSomething();
}
}
Run Code Online (Sandbox Code Playgroud)
B包装类packageB:
package packageB;
public class B {
public void doSomething() {
System.out.println("B did something.");
}
}
Run Code Online (Sandbox Code Playgroud)
正如我们所见,A取决于B.没有B,A不能用.但是,如果我们想B在未来取代一个BetterB怎么办?为此,我们Inter在packageA以下内容中创建一个接口:
package packageA;
public interface Inter {
public void doSomething();
}
Run Code Online (Sandbox Code Playgroud)
要使用这个接口,我们import packageA.Inter;让B implements Inter在B和替换出现的所有B内A用Inter.结果是这个修改版本A:
package packageA;
public class A {
private Inter myInter;
public A() {
this.myInter = ???; // What to do here?
}
public void doSomethingThatUsesInter() {
System.out.println("Doing things with myInter");
this.myInter.doSomething();
}
}
Run Code Online (Sandbox Code Playgroud)
在这一点上,我们已经看到,从依赖A到B消失:将import packageB.B;不再需要.只有一个问题:我们无法实例化接口的实例.但是控制的反转来拯救:不是实例化某种类型的Interwihtin A的构造函数,构造函数将需要一些implements Inter作为参数的东西:
package packageA;
public class A {
private Inter myInter;
public A(Inter myInter) {
this.myInter = myInter;
}
public void doSomethingThatUsesInter() {
System.out.println("Doing things with myInter");
this.myInter.doSomething();
}
}
Run Code Online (Sandbox Code Playgroud)
通过这种方法,我们可以改变现在的具体实施Inter中A随意.假设我们写了一个新类BetterB:
package packageB;
import packageA.Inter;
public class BetterB implements Inter {
@Override
public void doSomething() {
System.out.println("BetterB did something.");
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以A用不同的Inter实现来实例化s :
Inter b = new B();
A aWithB = new A(b);
aWithB.doSomethingThatUsesInter();
Inter betterB = new BetterB();
A aWithBetterB = new A(betterB);
aWithBetterB.doSomethingThatUsesInter();
Run Code Online (Sandbox Code Playgroud)
我们没有必要改变任何内容A.代码现在已经解耦Inter,只要符合合同,我们就可以随意更改具体实现Inter.最值得注意的是,我们可以支持代码,这些代码将在未来编写并实现Inter.
Adendum
两年前我写了这个答案.虽然总体上对答案感到满意,但我一直认为缺少了某些东西,我想我终于知道它是什么了.以下内容对于理解答案没有必要,但旨在引起读者的兴趣,并为进一步的自我教育提供一些资源.
在文献中,这种方法被称为界面分离原则,属于SOLID原则.鲍勃叔叔在YouTube上有一个很好的谈话(有趣的是大约15分钟),展示了如何使用多态性和接口让编译时依赖性指向控制流(建议观众自行决定,鲍勃叔叔将会关于Java的轻微咆哮).反过来,这意味着高级实现在通过接口进行segretaget时不需要了解更低级别的实现.因此,如上所示,可以随意交换较低的水平.
想象一下,的功能B是将日志写入某些数据库。该类B取决于该类的功能,DB并提供一些接口以将其记录到其他类。
类A需要的日志记录功能B,但不在乎日志的写入位置。它并不在乎DB,但由于它取决于B,所以它也取决于DB。这不是很理想。
因此,您可以做的是将该类B分为两个类:L描述日志功能的抽象类(不依赖DB)和实现依赖DB。
然后你就可以去耦类A的B,因为现在A只能依靠L。B现在还取决于L,这就是为什么它被称为依赖反转的原因,因为B它提供了中提供的功能L。
由于A现在仅依靠精益L,您可以轻松地将其与其他日志记录机制一起使用,而不必依赖DB。例如,您可以创建一个简单的基于控制台的记录器,实现中定义的接口L。
但由于现在A不取决于B但(在源)只在抽象接口L在运行时它必须被设置为使用的一些具体实施L(B例如)。因此,需要有人告诉运行时A使用B(或其他方式)。这就是所谓的控制反转,因为在A决定使用之前B,但是现在其他人(例如容器)告诉运行时A使用B。
| 归档时间: |
|
| 查看次数: |
7467 次 |
| 最近记录: |