public interface I{
void doSomething();
}
@Component("a")
public class A implements I{
public void doSomething(){
//...
}
public void doSomethingElse(){
//...
}
}
@Component("b")
public class B implements I{
public void doSomething(){
//...
}
}
@Component
public class Driver {
@Autowired
@Qualifier("someLogicalName") // under the hood it spring will map it to IImpl1 but you don't know that here
I i;
}
在这种情况下——情况要好得多——您永远不会在代码级别将驱动程序与具体实现耦合。这意味着一般来说,更改限定符以获得另一个实现就足够了。你不能打电话 bar 再也不能编译了。您也不知道将注入什么实现。如果将来实际实现“somelogicalname”逻辑的组件的实现将发生变化(我的意思是您将创建一个新类) IImpl3 ),您在这里感觉不到它-您将把限定符放在新类上,所有使用它的地方都将自动获得该实现。 案例3:
@Configuration
public class MyConfiguration {
@Bean
public Driver driver(@Qualifier("someLogicalName") I i) {
return new Driver(i);
}
}
public class Driver {
private final I i;
public Driver(I i) { // in real life this constructor can be generated by
// lombok or something, put it here for the sake of completeness
this.i = i;
}
}
2条答案
按热度按时间juud5qan1#
这就是面向对象编程(尤其是抽象和多态)的意义所在。
构建独立于具体实现的类并使用接口。
这允许您随时更改所使用的实现。
假设你有:
如果你使用
你可能会想用
doSomethingElse()
方法的实现细节(无论出于什么原因)。但是,如果您使用
这不能发生,因为接口中不存在该方法。
这使您能够随时交换实现。
dba5bblo2#
直接自动连接类而不是接口不是更有意义吗?
这在很大程度上取决于如何准确地使用限定符,但一般来说,答案是“否”,如果您有一个接口,则自动连接类是一件不好的事情-您应该始终按接口工作。
以下是示例:
注意,一个实现
IImpl1
有一个附加方法bar
它不属于接口I
案例1:这里的类驱动是紧紧可以实现的
IImpl1
一般来说,我可以调用bar
从Driver
类,因为我有这个实现,但在这种情况下,如果我必须切换Driver
将来您还必须更改代码:既要更改引用,又要去掉对的调用IImpl1.bar()
这可能没那么容易做到——这是逻辑上的改变。结果,整个多态行为丢失了。到目前为止,这是最糟糕的编程方式。
现在,考虑案例2:
在这种情况下——情况要好得多——您永远不会在代码级别将驱动程序与具体实现耦合。这意味着一般来说,更改限定符以获得另一个实现就足够了。你不能打电话
bar
再也不能编译了。您也不知道将注入什么实现。如果将来实际实现“somelogicalname”逻辑的组件的实现将发生变化(我的意思是您将创建一个新类)IImpl3
),您在这里感觉不到它-您将把限定符放在新类上,所有使用它的地方都将自动获得该实现。案例3:
到目前为止,这是最“干净”的方法——从概念上讲,它与案例2非常相似,但是在本例中,您没有将限定符放在
Driver
上课,其实是上课Driver
甚至在代码/元数据级别上都不知道它与spring有关。当然,案例2的所有“优点”在这里也同样适用。