【问题标题】:Convert DTO to Domain models and back with lambda将 DTO 转换为域模型并返回 lambda
【发布时间】:2017-11-05 11:45:51
【问题描述】:

我是 Java 新手,所以我想问你是否存在 lambda 的一些漂亮的解决方案,可以将一种类型的对象转换为另一种类型的对象?

我有服务中的功能:

public List<MyObjectDto> findAll() {
    List<MyObject> list = repository.findAll();
    return list.someMagicToConvertToDtoObjectsInList();
}

对此有什么想法吗?

【问题讨论】:

  • 什么类型需要转换成什么类型​​?
  • 没有。没有魔法。写一个转换器。您可以查看 MapStruct 之类的内容 - 但它可能会超出您当前的水平。
  • @Salman 我的带有属性的自定义对象。

标签: java lambda dto


【解决方案1】:

这里没有魔法,但您可以流式传输列表,然后实现 map 函数以从域表示形式转换为 DTO 表示形式。

例如,给定一个带有id, firstName, lastName 的域对象和一个带有id, name 的DTO(其中namefirstNamelastName 的串联),下面的代码...

List<MyObject> domain = new ArrayList<>();
domain.add(new MyObject(1, "John", "Smith"));
domain.add(new MyObject(1, "Bob", "Bailey"));

// using the verbose statement of function (rahter than a lambda) 
// to make it easier to see how the map function works
List<MyDto> asDto = domain.stream().map(new Function<MyObject, MyDto>() {
    @Override
    public MyDto apply(MyObject s) {
        // a simple mapping from domain to dto
        return new MyDto(s.getId(), s.getFirstName() + " " + s.getLastName());
    }
}).collect(Collectors.toList());

System.out.println(asDto);

...打印出来:

[
    MyDto{id=1, name='John Smith'}, 
    MyDto{id=1, name='Bob Bailey'}
]

当然,在使用stream() 时,上面对匿名类的使用看起来有些不合适,所以这里是使用 lambda 表示的相同代码:

List<MyDto> asDto = domain.stream().map(
        s -> new MyDto(s.getId(), s.getFirstName() + " " + s.getLastName())
).collect(Collectors.toList());

【讨论】:

  • 嗨,例如,谢谢,但我正在使用带有属性的自定义对象,我需要地图属性
  • 我提供了一个字符串示例,因为我不熟悉您的“具有属性的自定义对象”,但无论List 是什么类型,上述示例中的方法都是有效的。 lambda 接受域对象的实例并发出 DTO 的实例,lambda 的实现只是简单地适应另一个。我刚刚更新了答案,以更清楚地显示地图功能如何将您的域转换为您的 DTO。
  • 可怕的匿名class 是怎么回事?为什么使用 Java 8 Stream 而不是 lambda?
  • @BoristheSpider 我的原始答案使用了 lambda,OP 的回复让我怀疑这使答案更难理解,所以我编辑添加了带有以下评论的匿名 Function 类来解释我这样做的原因: "// 使用函数的详细语句(比 lambda)更容易看到 map 函数的工作原理"
  • 很公平 - 有点提到它们等效。 lambda 将使用 invokedynamic 并可能显着提高性能。
【解决方案2】:

通过使用流,您可以使用以下内容:

public List<MyObjectDTO> findAll() {
    List<MyObject> list = repository.findAll();
    return list.stream()
            .map(MyObjectDTO::new)
            .collect(Collectors.toCollection(ArrayList::new));
}

为此,您的 DTO 类需要有一个接受您的域模型的构造函数:

public class MyObjectDTO {

    // fields

    public MyObjectDTO(MyObject myObject) {
        // map MyObject fields to MyObjectDTO fields
    }
}

编辑

参数构造函数的替代方法是将转换封装在方法中,例如:

public class Service {    

    public List<MyObjectDto> findAll() {
        List<MyObject> list = repository.findAll();
        return list.stream()
                .map(Service::convert)
                .collect(Collectors.toCollection(ArrayList::new));
    }

    private MyObjectDTO convert(MyObject myObject) {
        // conversion here
    }
}

【讨论】:

  • 是的,这就是我要找的东西,但是如果没有 MyObjectDTO 中的参数构造函数,是否可以这样做?
  • 如果你愿意将转换封装在一个方法中,你可以这样做:
  • 请忽略我上面的评论。如果您愿意将转换封装在一个方法中,您可以实现它。请参阅我编辑的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-03
  • 2017-02-22
  • 2022-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多