Java 在运行时解析实现 //在Coffee.jar中定义的接口。 界面咖啡{ void brew(); 作废作废(); } //BlackCoffee.jar中定义的实现 类黑咖啡{ @凌驾 公共空间{ System.out.println(“Brew BalckCoffee”); } @凌驾 公共作废作废(){ System.out.println(“丢弃黑咖啡”); } } //filterOffee.jar中定义的实现 类FilterOffee实现了Coffee{ @凌驾 公共空间{ System.out.println(“Brew过滤器报价”); } @凌驾 公共作废作废(){ System.out.println(“丢弃过滤器报价”); } } //Coffee.jar中的运行时类 布雷科菲级{ 公共静态void main(字符串[]args){ 咖啡=//这里有些东西; 咖啡; 咖啡。丢弃(); } }
然后,想法是在不知道实现的情况下在运行时解析实现。Java 在运行时解析实现 //在Coffee.jar中定义的接口。 界面咖啡{ void brew(); 作废作废(); } //BlackCoffee.jar中定义的实现 类黑咖啡{ @凌驾 公共空间{ System.out.println(“Brew BalckCoffee”); } @凌驾 公共作废作废(){ System.out.println(“丢弃黑咖啡”); } } //filterOffee.jar中定义的实现 类FilterOffee实现了Coffee{ @凌驾 公共空间{ System.out.println(“Brew过滤器报价”); } @凌驾 公共作废作废(){ System.out.println(“丢弃过滤器报价”); } } //Coffee.jar中的运行时类 布雷科菲级{ 公共静态void main(字符串[]args){ 咖啡=//这里有些东西; 咖啡; 咖啡。丢弃(); } },java,Java,然后,想法是在不知道实现的情况下在运行时解析实现。 该应用程序将具有Coffee.jar的依赖项,以及BlackCoffee.jar或FilterCoffee.jar的依赖项。这是依赖项注入框架(如Spring)的优点之一 您对接口编写代码,而您的客户机类不知道在运行时实例化了哪个实现 你可以根据条件来选择 e、 g.在Spring中,您可以使用@Conditional属性 @ConditionalOnProperty("coffee.black") class BlackCoffee impl
该应用程序将具有Coffee.jar的依赖项,以及BlackCoffee.jar或FilterCoffee.jar的依赖项。这是依赖项注入框架(如Spring)的优点之一 您对接口编写代码,而您的客户机类不知道在运行时实例化了哪个实现 你可以根据条件来选择 e、 g.在Spring中,您可以使用@Conditional属性
@ConditionalOnProperty("coffee.black")
class BlackCoffee implements Coffee
@ConditionalOnProperty("coffee.filter")
class BlackCoffee implements Coffee
然后有
@Component
class ClassUsingCoffee {
private Coffee coffee;
@Inject
public ClassUsingCoffee(Coffee coffee) {
this.coffee = coffee;
}
//use coffee as normal
}
然后在Spring的属性中,您可以定义属性“black”或“filter”来激活两个具体类实现中的一个。如果您同时定义了这两个属性,您会得到一个异常,说明存在两个Coffee实例,并且它不知道使用Coffee将哪个(依赖项注入)注入ClassUsingCoffee
类
如果不深入了解Spring的细节,很难解释。但是您也可以使用ApplicationContext
(将其视为包含Spring知道的所有类的“东西”)
在这两个示例中,您都将类耦合到
Coffee
接口,而不是特定的实现。e、 g.如果您做了Coffee Coffee=new BlackCoffee()
,那么您的代码将耦合到Coffee的特定实现(在本例中为BlackCoffee
),任何需要的更改都需要代码更改(与配置/属性更改相反)这是依赖项注入框架(如Spring)的优点之一
您对接口编写代码,而您的客户机类不知道在运行时实例化了哪个实现
你可以根据条件来选择
e、 g.在Spring中,您可以使用@Conditional属性
@ConditionalOnProperty("coffee.black")
class BlackCoffee implements Coffee
@ConditionalOnProperty("coffee.filter")
class BlackCoffee implements Coffee
然后有
@Component
class ClassUsingCoffee {
private Coffee coffee;
@Inject
public ClassUsingCoffee(Coffee coffee) {
this.coffee = coffee;
}
//use coffee as normal
}
然后在Spring的属性中,您可以定义属性“black”或“filter”来激活两个具体类实现中的一个。如果您同时定义了这两个属性,您会得到一个异常,说明存在两个Coffee实例,并且它不知道使用Coffee将哪个(依赖项注入)注入ClassUsingCoffee
类
如果不深入了解Spring的细节,很难解释。但是您也可以使用ApplicationContext
(将其视为包含Spring知道的所有类的“东西”)
在这两个示例中,您都将类耦合到
Coffee
接口,而不是特定的实现。e、 g.如果您确实执行了Coffee Coffee=new BlackCoffee()
,那么您的代码将与Coffee的特定实现相耦合(在本例中为BlackCoffee
),并且所需的任何更改都需要代码更改(与配置/属性更改相反)如果您希望选择接口的实现,因为类路径上存在实现的jar文件,那么您应该使用服务加载程序框架
有关更多信息,请参阅
在您的情况下,从组织代码开始,即将类放入包中:
package com.example.api;
public interface Coffee {
...
}
然后像这样包装:
- 将
放入文件com/example/api/Coffee.class
Coffee.jar
- 将
与文件com/example/black/BlackCoffee.class
和内容META-INF/services/com.example.api.Coffee
com.example.black.BlackCoffee
- 将
与文件com/example/filter/FilterCoffee.class
和内容META-INF/services/com.example.api.Coffee
com.example.filter.FilterCoffee
- 将
放入文件com/example/BrewCoffee.class
brew.jar
java-cp brew.jar;咖啡罐;black.jar.com.example.BrewCoffee
java-cp brew.jar;咖啡罐;filter.jar.com.example.BrewCoffee
java-cp brew.jar;咖啡罐;black.jar;filter.jar.com.example.BrewCoffee
注意:在Linux上,替换代码>与:
由于main
方法在所有实现中循环,如果您希望选择接口的实现,因为类路径上存在实现的jar文件,则第三个命令将与BlackCoffee
和FilterCoffee
一起运行,然后您应该使用服务加载器框架
有关更多信息,请参阅
在您的情况下,从组织代码开始,即将类放入包中:
package com.example.api;
public interface Coffee {
...
}
然后像这样包装:
- 将
com/example/api/Coffee.class
放入文件Coffee.jar
- 将
com/example/black/BlackCoffee.class
与文件META-INF/services/com.example.api.Coffee
和内容com.example.black.BlackCoffee
- 将
com/example/filter/FilterCoffee.class
与包含内容com的文件META-INF/services/com.example.api.Coffee
放在文件filter.jar
中。
package com.example;
import com.example.api.Coffee;
public class BrewCoffee {
public static void main(String[] args) {
for (Coffee coffee : ServiceLoader.load(Coffee.class)) {
coffee.brew();
coffee.discard();
}
}
}