Java 工厂模式:在创建bean时验证输入(Guice/Guava)

Java 工厂模式:在创建bean时验证输入(Guice/Guava),java,validation,guice,factory,Java,Validation,Guice,Factory,我正在编写一个新的应用程序,使用Guice进行依赖项注入,使用Guava的前提条件进行属性验证 我正在使用工厂模式基于外部输入创建bean。问题是,验证输入的首选方法是什么?(在可维护性、清晰度等方面) 让我们假设这些类: Bean.java public interface Bean { public Object getFoo(); } public class BeanImpl implements Bean { private final Object foo;

我正在编写一个新的应用程序,使用Guice进行依赖项注入,使用Guava的前提条件进行属性验证

我正在使用工厂模式基于外部输入创建bean。问题是,验证输入的首选方法是什么?(在可维护性、清晰度等方面)

让我们假设这些类:

Bean.java

public interface Bean {

    public Object getFoo();

}
public class BeanImpl implements Bean {

    private final Object foo;

    public BeanImpl(Object param) {
        foo = param;
    }

    @Override
    public String getFoo() {
        return foo;
    }

}
BeanImpl.java

public interface Bean {

    public Object getFoo();

}
public class BeanImpl implements Bean {

    private final Object foo;

    public BeanImpl(Object param) {
        foo = param;
    }

    @Override
    public String getFoo() {
        return foo;
    }

}
我想检查“param”是否包含“foo”的有效值:

我应该在哪里做,为什么?

  • 在BeanImpl的构造函数中?(我不确定为什么,但在构造函数中添加检查感觉不是个好主意。)
  • 在调用BeanFactory.create(param)之前?(听起来像是可怕的代码复制。)
  • 通过某种我不知道的Guice机制

如果使用特定的
foo
值构造
BeanImpl
是无效的,那么在构造函数中抛出一个
IllegalArgumentException
,详细说明错误所在

public class BeanImpl {
  ...
  public BeanImpl(Object param) {
    if (param == null) {
      throw new IllegalArgumentException("Param cannot be null");
    }
    foo = param;
  }
  ...
}
从早期的“状态和行为相结合”的对象定义来看,这强制要求您不要用无效状态污染对象

对于工厂来说,在构建对象之前检查值是一种方便,但工厂的真正责任并不延伸到对象的责任中。工厂模式有助于确保一个对象以有意义的方式与其他对象相对应,但它不应该确保对象的内部状态正确

让一个对象(工厂)确保另一个对象的状态正确是错误的行为。您将行为(验证状态)放在工厂中,但状态在对象中。因此,您现在拥有了应该是紧密耦合的分散连接代码。这意味着现在你必须有一个工厂来制造一个对象,而不是在有意义的时候有一个工厂来制造一个对象,而在没有意义的时候直接制造这个对象

这通常出现在单元测试中。如果您没有将验证码放入工厂,您可以单独对对象进行单元测试;测试不良参数。但是,如果将验证代码放在工厂中,那么在没有工厂的情况下将无法构造“有效”对象,这是您将得到的第一个提示,即您有两个不应该紧密耦合在一起的非自然耦合对象


当然,也有例外;但是,当人们期望数据是正确的时候,它们就会出现,但是收集数据的方式并没有提供验证。例如,从网络套接字收集的结构化记录实际上可能包含概念上不一致的数据;但是,由于处理的性质,会处理、记录和丢弃无效输入。

请查看Netflix的Guvernator框架:

它是建立在GoogleGuice上的,并通过一些很酷的功能进行扩展,比如

  • 生命周期(施工、有效期、预热、销毁)
  • 验证
  • 配置

在您的项目中有更多的锅炉板包括guvernator,但肯定值得一试。

+1。我还要补充一个假设,即验证是轻量级的,并且可以同步完成;如果有任何外部服务调用(包括网络或磁盘调用)来确认对象是否有效,这可能是例外情况之一。(OP,你的直觉是正确的,构造器不应该做任何“繁重的工作”,特别是在Guice中。直接的验证对我来说并不重要。)感谢你给出了详细的回答。回到什么是对象、耦合在哪里以及每个模式真正意义的基础上,就是解决方案。我将在构造函数中添加我的验证代码。(谢谢@JeffBowman关于外部服务呼叫的精确性,不用说,但其他读者可能会发现它是一个救命稻草;)@SilverQuettier谢谢你的评论。我很高兴你为你的问题找到了正确的解决方案。这并不能真正回答问题