我正在开发一个SDK,它将用于为批处理创建其他应用程序。有 core-a-api 模块,它保存接口 Client
public interface Client {
void send();
}
和 core-a-impl ,它包含客户端接口的几个实现 - HttpClient 和 TcpClient 。<登记/> 此外,还有一个核心模块 core-b-impl ,它使用 Client 接口的特定实例。
public class SendingTasklet implements Tasklet {
@Autowired
private Client client
public void process() {
client.send();
}
}
应该创建哪个实例( HttpClient 或 SftpClient )应由用户决定,该用户使用SDK创建应用程序。他还需要能够为 Client 创建自己的实现,并在 SendingTasklet 中使用它。来自核心依赖项的用户只能看到来自 -api 模块的接口。对于依赖注入,我使用的是Spring。特定模块的所有bean都在每个模块中单独创建。用户创建的bean是在用户的配置类
@Configuration
public class UsersApplicationConf {
@Bean
public Client client {
return new UsersClient();
}
}
问题是,在某种程度上没有暴露用户应用程序的 -impl 模块细节,他应该能够决定从核心提供的实现中使用哪些客户端实现,或者他应该能够通过它自己的一个。
第一个想法是在注入 SendingTasklet 时使用限定符,但是你需要为 SendingTasklet 中的每个实现创建一个单独的实例变量,这不是很好因为如果有更多 Client 接口的实现,则还需要更改 SendingTasklet 。还有问题,用户应该以某种方式决定使用的实现是否持续存在。
我做了什么,我为客户的应用程序公开了 core-a-impl 。因此,在他的配置中,他可以决定为 Client 接口创建的实例。
@Configuration
public class UsersApplicationConf {
@Bean
public Client client {
return new HttpClient();
}
}
但这也不是很聪明,而且我在想如何解决这个问题?
答案 0 :(得分:1)
您可以使用上面提到的策略或工厂模式here但我个人会使用JSR 330,您可以在代码块下面找到示例here,例如:
package spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static spring.Spring.Platform;
@Configuration
@ComponentScan
public class Spring {
public static void main(String[] args) {
new AnnotationConfigApplicationContext(Spring.class);
}
@Autowired
@Platform(Platform.OperatingSystems.ANDROID)
private MarketPlace android;
@Autowired
@Platform(Platform.OperatingSystems.IOS)
private MarketPlace ios;
@PostConstruct
public void qualifyTheTweets() {
System.out.println("ios:" + this.ios);
System.out.println("android:" + this.android);
}
// the type has to be public!
@Target({ElementType.FIELD,
ElementType.METHOD,
ElementType.TYPE,
ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public static @interface Platform {
OperatingSystems value();
public static enum OperatingSystems {
IOS,
ANDROID
}
}
}
interface MarketPlace {
}
@Component
@Platform(Platform.OperatingSystems.IOS)
class AppleMarketPlace implements MarketPlace {
@Override
public String toString() {
return "apple";
}
}
@Component
@Platform(Platform.OperatingSystems.ANDROID)
class GoogleMarketPlace implements MarketPlace {
@Override
public String toString() {
return "android";
}
}
编辑:我没有测试代码,但我使用了javax.inject.Qualifier 与CDI如果此代码无法正常工作让我知道我会更新 正确的组合和进口