如果您在 OrderDto 中使用 Status 枚举,则将其与您的实体耦合。因此,如果您更改实体层,您可以轻松地将 API 更改为客户端。
假设OrderDto 是使用java 对象序列化序列化的,以将其发送到客户端。如果客户端反序列化它,它需要实体层的类。这通常不是您想要的。
如果您通过 JSON 序列化 OrderDto,则通常使用枚举的名称。这意味着如果您更改实体层中的Status 枚举。它会立即更改发送到客户端的 JSON。
我会将它与另一个 StatusDto 枚举解耦,并使用 Map 将其映射到传输层(DTO 所在的位置)。如果实体Status 比StatusDto 更细粒度,这也是有意义的,例如
public class StatusMapper {
private Map<Status, StatusDto> toDto = new HashMap<>();
public StatusMapper(){
toDto.put(Status.PLACED, StatusDto.IN_PROCESS);
toDto.put(Status.CONFIRMED, StatusDto.IN_PROCESS);
toDto.put(Status.SHIPPED, StatusDto.IN_DELIVERY);
}
public StatusDto map(Status status){
StatusDto dto = toDto.get(status)
if(dto == null){
// default status or exception ?
}
return dto;
}
}
这个映射很容易测试。当使用开关而不是Map 时,很难测试默认情况。
编辑
与简单的 switch 语句相比,这是很多开销。为什么默认值很难测试?
首先我想说,下面的例子是基于Java的。也许有些语言没有这个问题。
假设您定义了以下枚举:
public enum Status {
S1, S2, S3;
}
通常,当您实现映射时,源值和目标值之间存在一对一的关系。因此,使用开关的映射如下所示:
public String map(Status status) {
switch(status) {
case S1: return "State1";
case S2: return "State2";
case S3: return "State3";
default: throw new IllegalArgumentException("Unknown status");
}
}
现在尝试编写一个涵盖默认情况的测试。
-
您不能传递将执行默认情况的Status 枚举,因为所有枚举值都被它们的情况所覆盖。默认情况的本质是仅在添加新枚举时才执行。但是您不能仅出于测试目的添加新枚举。不允许子类化。枚举是最终的。添加默认情况通常是为了提示开发人员记住,如果添加了新的枚举,还有一些工作要做。
-
您不能传递null,因为它会导致NullPointerException(在Java 中),因为开关使用枚举的序数值。您可以在字节码中看到这一点。
使用 Map 方法,我可以通过 null。由于地图没有映射,因此返回 null ,因此覆盖了“默认”。当然,这与通过未知枚举不完全相同,但对我来说,这是测试它的最佳折衷方案。