2017-05-28 52 views
0

我有一个简单的复制/ clone方法那就是我的应用程序重要:如何在添加新字段时避免破解克隆/复制方法?

@Override 
    public Operation getCopy() { 
    Operation copy = new Operation(); 
    copy.year = this.year; 
    copy.stage = this.stage; 
    copy.info = this.info; 
    copy.user = this.user.getCopy(); 
    // NOT TO BE COPIED! copy.id = this.id; 
    ... 
    return copy; 
} 

注意,有一些不应该被复制了一些具体领域。还有一些复杂的对象(如用户)有自己的复制方法。

的问题是,由于新代码开发的,有时开发人员创建应该复制一个新的领域,但他忘了将它添加到copy方法:

private String additionalInfo; 

而且即使没有一个编译错误,这是一个业务问题,只有我们的QA团队甚至用户才会发现。

我能做些什么来防止这种情况发生?我已经尝试过使用原始对象和其副本进行比较的JUnit测试,并且它们适用于现有字段,但它们不占用新字段。

回答

2

我用我称之为“环和开关”测试此:

for (Field field : Operation.class.getFields()) { 
    switch (field.getName()) { 
    case "year": 
     // Test that year is copied correctly. 
     // Initialize blah so that year is set. 
     assertEquals(getCopy(blah).year, blah.year); 
     break; 
    case "stage": 
     // Test that stage is copied correctly. 
     // Initialize blah so that stage is set. 
     assertEquals(getCopy(blah).stage, blah.stage); 
     break; 
    case "id": 
     // We don't want to copy id. 
     // Initialize blah so that id is set. 
     assertNull(getCopy(blah).id); 
     break; 

    // etc. 

    default: 
     throw new AssertionError("Unhandled field: " + field.getName()); 
    } 
} 

这不是一个非常有想象力的名字:您遍历所有的类的字段,然后切换直线距离,以便您可以分别明确地处理各个字段。

这样做的好处是,default案件立即发现缺乏对新增字段的处理。在测试中你会得到一个很棒的大耳光,说你需要在测试中处理它 - 并且扩展而言,你也需要在生产代码中处理它。

使用普通的旧Java反射时的缺点是它不会捕获被删除的字段。这可能是一个“不太糟糕”的情况,因为它只是你剩下的未使用的代码,而不是生产代码中未经测试的代码路径。


我开发(或读取某处,我不幸无法回忆)此成语,同时建立协议缓冲区协议缓冲区转换器。 Java的协议缓冲区有generated field numbers,所以实际上你可以打开的场数,而不是名称:

for (FieldDescriptor fieldDesc : proto.getDescriptorForType().getFields()) { 
    switch (fieldDesc.getNumber()) { 
    case FIELD1_FIELD_NUMBER: 
     // ... 
    case FIELD2_FIELD_NUMBER: 
     // ... 
    } 
} 

关于这样做的好处是,你了解删除的情况下也是如此,因为场数将不再生成,这意味着测试开关将不再编译。

+0

面对变化,这种方法极其不稳定。测试'assertEquals(复制,原始,“复制失败”);'通常就足够了。 –

+0

@LewBloch,除了依赖equals检查所有的字段。 –

+0

只有那些需要建立平等的人。如果这个状态是由其他领域决定的,那么他们应该用“等”来解释。 –

0

代码审查如何错过缺少重写?

此外,复制方法不应该太脆弱。如果您有“不应复制的特定字段”,为什么它们对子类可见?

为什么继承层次如此之深?如果每个需要复制的类型都实现一个接口,那么在开发过程中错过重写会更加困难,并且您不需要深层继承层次结构。那些碰巧继承getCopy()的合适的基本实现的类可以通过super.来调用它以开始,那些不简单地实现继承的接口方法的类。

您不能强制程序员通过编译器从具体实现中覆盖方法。代码审查应该会发现这样的错误。如果他们没有对那些错过评论的人说一句话。

抽象方法的实现更容易被捕获,因为如果你不这样做,编译器会发出呻吟声。

相关问题