2013-05-05 56 views
0

假设一个Java类名为Car,其对象通过静态工厂初始化:最佳实践TDD - Java对象验证和干净的代码

public class Car { 

    private String name; 

    private Car(String name){//...} 

    public static Car createCar(String name){ 
     //mechanism to validate the car attributes 
     return new Car(name); 
    } 
} 

当然,我想提取验证过程到一个名为专用类CarValidator

有提供这种验证工厂的方式有两种:

不stubbable/mockable验证

public static Car createCar(String name){ 
    new CarValidator(name); // throw exception for instance if invalid cases 
    return new Car(name); 
} 

Stubbable/mockable验证:

public static Car createCar(CarValidator carValidator, String name){ //ideally being an interface instead 
    carValidator.validate(); 
    return new Car(name); 
} 

它在这里看起来很像冗余:CarValidator已经包含name值,因为它存储Car参数作为自己的字段(先验干净的方式),因此,我们可以绕过这样的第二个参数:

public static Car createCar(CarValidator carValidator){ 
    carValidator.validate(); 
    return new Car(carValidator.getName()); 
} 

然而,这看起来不清楚......为什么一个Car发现它的价值从Validator =>没有意义。

所以,我们可以refactorate这样的:

public static Car createCar(CarValidator carValidator, String name){ 
         carValidator.validate(name); // throwing exception for instance if invalid cases 
         return new Car(carValidator.name()); 
} 

听起来很少怪异,但CarValidator失去从创建字段,而不是参数传递给它的每一个必要的私有方法,如受益:

private checkForCarName(String name); 

我应该选择哪种方法?

回答

1

我的建议如下: 我不会混合领域对象的验证与对象本身。

如果域对象假设传递给它的数据是有效的,并且验证应该在其他地方执行(例如在工厂中,但不是必需的),那将更清晰。在该“工厂”中,您将执行数据准备状态(验证,漏洞删除等),然后您将创建一个新对象。

您将能够测试工厂(如果它正确验证),而不是域对象本身。

+0

对不起,但我不同意。验证对象机制应该在领域类别之外进行描述,这一点毫无疑问。但为了始终保持一个对象处于内聚状态,特别是防止有人在事先不使用“外部”工厂的情况下创建它,必须在创建它之前验证它,因此验证应该通过域类来调用。我特别为不可改变的阶级而思考。 – Mik378 2013-05-05 20:43:53

+1

我相信这里的一个好方法是使用Fluent Builder模式。这样,Car类本身可以不可变,Car.Builder类将包含所有必要的验证规则。 – Olaf 2013-05-07 20:46:15

+0

@Olaf是的,但这并不能解决问题。您的解决方案的后果:违反SRP。如果我们想要解决SRP问题,即使有一位漂亮流利的建筑师,我们也会在帖子中回到我的问题。 – Mik378 2013-05-08 13:17:51