Java 如何处理依赖注入策略
我必须创建一个具有本地和外部存储的订单系统。本地存储应始终首先用完,如果仍然缺少任何内容,其余内容应由外部存储订购 基本上我有4种可能的情况: 1从本地存储订购所有项目Java 如何处理依赖注入策略,java,dependency-injection,guice,strategy-pattern,Java,Dependency Injection,Guice,Strategy Pattern,我必须创建一个具有本地和外部存储的订单系统。本地存储应始终首先用完,如果仍然缺少任何内容,其余内容应由外部存储订购 基本上我有4种可能的情况: 1从本地存储订购所有项目 从本地存储和外部存储混合的2个订单项目 3从外部存储器订购所有项目 4.无法订购 现在,我决定为3种有效情况创建一个接口。该接口非常简单: public interface Reservator{ boolean reserveItem(Article article, amount); } 现在,我使用以下界面选择哪种策
从本地存储和外部存储混合的2个订单项目
3从外部存储器订购所有项目
4.无法订购 现在,我决定为3种有效情况创建一个接口。该接口非常简单:
public interface Reservator{
boolean reserveItem(Article article, amount);
}
现在,我使用以下界面选择哪种策略:
public interface ReservationContext{
boolean setAmount(int amount);
boolean reserveItem(Article article);
}
其实现大致如下所示:
@Singleton
public ReservationHandler implements ReservationContext{
private int reservationAmount=0;
private Reservator reservator;
private LocalStorage local;
private ExternalStorage external;
@Inject
public ReservationHandler(LocalStorage local, ExternalStorage external){
this.local = local;
this.external = external;
}
@Override
public boolean setAmount(int amount){
if(amount == 0){
return false;
}
if(local.getStorage > amount){
reservator = new LocalReservator(//all dependencies);
}
else if(local.getStorage ==0 && external.getStorage > amount){
reservator = new ExternalReservator(//all dependencies);
}
else if((local.getStorage + external.getStorage) > amount){
reservator = new MixedReservator(//all dependencies);
}
else{
return false;
}
reservationAmount = amount;
return true;
}
@Override
public boolean reserveItem(Article article){
return reservator.reserveItem(article, amount);
}
}
现在我想知道如何通过依赖注入而不是实例来处理三种保留策略(LocalReservator、ExternalReservator和MixedReservator),以便更容易地进行测试
我知道我可以绑定ReservatorInterace的所有实现,并在注入时获得一个列表。然而,我并不完全清楚我如何能轻易地选择正确的一个。在我的案例中,什么是最佳实践
此外,如果正确策略的选择能够得到更好的处理,我愿意接受建议。谢谢你的时间 您的ReservationHandler目前负责至少三件事:创建Reservator实例、计算要使用的Reservator以及充当ReservationContext。虽然这个代码并不是太坏,但我们可以很容易地让Guice处理创建保留实例——毕竟,它的工作是封装依赖性创建——并考虑提取出正确的保留器的创建。如果Reservators的数量增加,或者如果ReservationContext的作用域变得更清晰,那么这也将隔离您。(现在它看起来就像一个包装器接口。) 您需要的不是列表,而是一组提供者:
private final Provider<LocalReservator> localReservatorProvider;
private final Provider<ExternalReservator> externalReservatorProvider;
private final Provider<MixedReservator> mixedReservatorProvider;
你应该这样做吗?现在,您还没有向我们展示您的Reservator实例的依赖关系,或者它们是否可能更改。如果没有,或者列表很短,您可能会坚持使用new
;如果列表很长或者可能会更改,那么注入提供者是非常有意义的。如果您的实例很难在测试中使用,那么注入提供程序也是有意义的,因为您可以使用一个mock来用一个简单的确定性测试双精度替换一个真正的LocalReservator(其余的以此类推)
如果您想在此基础上进行构建,还可以涉及(这允许您以分布式方式在Guice中创建一个集合或映射,一次一个绑定)或(这将允许您在创建Reservator期间传递构造函数参数,使用您定义的工厂而不是Guice的提供程序)。两者都不适用,但都值得学习
从这里开始,如果您的setAmount
逻辑足够复杂,无法提取,您还可以将其提取到一个方法类ReservatorFactory,该类选择返回哪个Reservator。这样,您的ReservationHandler就可以由它自己负责,并且可以在不使用特定保留逻辑的情况下进行测试。(当然,如果这是您希望ReservationHandler做的唯一事情,那么请务必将该实现留在原处。否则,您可以将ReservationHandler重构为一个空壳!)
p、 s.Jack的评论是正确的,他说,在为个人预订保留状态的同时,将此标记为
@Singleton
,可能非常危险。您可以删除@Singleton
注释,Guice每次都会创建一个新实例;这是Guice的默认行为。您的ReservationHandler当前负责至少三件事:创建Reservator实例、计算要使用的Reservator以及充当ReservationContext。虽然这个代码并不是太坏,但我们可以很容易地让Guice处理创建保留实例——毕竟,它的工作是封装依赖性创建——并考虑提取出正确的保留器的创建。如果Reservators的数量增加,或者如果ReservationContext的作用域变得更清晰,那么这也将隔离您。(现在它看起来就像一个包装器接口。)
您需要的不是列表,而是一组提供者:
private final Provider<LocalReservator> localReservatorProvider;
private final Provider<ExternalReservator> externalReservatorProvider;
private final Provider<MixedReservator> mixedReservatorProvider;
你应该这样做吗?现在,您还没有向我们展示您的Reservator实例的依赖关系,或者它们是否可能更改。如果没有,或者列表很短,您可能会坚持使用new
;如果列表很长或者可能会更改,那么注入提供者是非常有意义的。如果您的实例很难在测试中使用,那么注入提供程序也是有意义的,因为您可以使用一个mock来用一个简单的确定性测试双精度替换一个真正的LocalReservator(其余的以此类推)
如果您想在此基础上进行构建,还可以涉及(这允许您以分布式方式在Guice中创建一个集合或映射,一次一个绑定)或(这将允许您在创建Reservator期间传递构造函数参数,使用您定义的工厂而不是Guice的提供程序)。两者都不适用,但都值得学习
从这里开始,如果您的setAmount
逻辑足够复杂,无法提取,您还可以将其提取到一个方法类ReservatorFactory,该类选择返回哪个Reservator。这样,您的ReservationHandler就可以由它自己负责,并且可以在不使用特定保留逻辑的情况下进行测试。(当然,如果这是您希望ReservationHandler做的唯一事情,那么请务必将该实现留在原处。否则,您可以将ReservationHandler重构为一个空壳!)
p、 s.Jack的评论是正确的,他说,在为个人预订保留状态的同时,将此标记为@Singleton
,可能非常危险。你可以