首页 > 解决方案 > 如何在 DTO 中返回枚举?

问题描述

我有一个订单实体:

public class Order {
  private String name;
  private Status status;//enum
  //other fields, getters,setters
 }

状态是具有很多值的枚举(假设有 30 个状态)。我创建了OrderDtoOrderMapper. 我想将我的订单转换为OrderDto. 我应该如何处理Status枚举?

我应该创建StatusDto枚举和Status converter/mapper或使用域中的枚举还是作为字符串Order返回?Status.FOO.name()

   public class OrderDto {
      private String name;
      private ??? status;//enum or String or another(dto) enum?
    }

标签: javaenumsdtoclean-architecture

解决方案


如果你在你的Status枚举中使用OrderDto它,你将它与你的实体结合起来。因此,如果您更改实体层,您可以轻松地将 API 更改为客户端。

假设OrderDto使用 java 对象序列化将其序列化以将其发送到客户端。如果客户端反序列化它,它需要实体层的类。这通常不是你想要的。

如果OrderDto通过 JSON 序列化,则通常使用枚举的名称。这意味着如果您Status对实体层中的枚举进行更改。它会立即更改发送到客户端的 JSON。

我会将它与另一个StatusDto枚举解耦,并使用Map. 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;
     }
 }

这种映射很容易测试。当使用 switch 而不是 aMap时,很难测试默认情况。

编辑

与简单的 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 中),因为开关使用枚举的序数值。您可以在字节码中看到这一点。 Status.ordinal() 用于 switch 语句

使用 Map 方法,我可以通过null. 由于地图没有映射,因此返回 null ,因此覆盖了“默认”。当然,这与通过未知枚举并不完全相同,但对我来说,这是测试它的最佳折衷方案。


推荐阅读