在Java中,通常使用数据传输对象(DTO)在应用程序的各个层之间传输数据。然而,在Go中,DTO并不是必要的,甚至可能对应用程序的设计有害。
DTO是Java类,它包含数据但没有行为。它们用于在应用程序的各个层之间传输数据,例如在控制器和服务层之间。
DTO通常用于封装数据并在应用程序的各个层之间提供抽象层。
Java是一种强类型语言,这意味着变量和方法必须声明为特定的数据类型。这可能会使在应用程序的各个层之间传递数据变得困难,因为每个层可能需要不同的数据类型。DTO提供了一种封装数据并在应用程序的各个层之间提供抽象层的方法。
Go是一种静态类型的语言,与Java类似,但有一些关键区别。最重要的区别之一是Go比Java更简洁。
这意味着Go程序往往比Java程序具有更少的层。在Go中,常用结构体表示数据。结构体可以包含数据和行为,并且可以在应用程序的各个层之间传递。这消除了DTO的需要,因为结构体可以提供与DTO相同的数据抽象和封装。
在Go中使用DTO实际上可能对应用程序的设计有害。DTO在应用程序的各个层之间添加了不必要的抽象层,这可能会使代码更难以阅读和维护。DTO还可能使向应用程序添加新功能更加困难,因为对DTO的更改可能会在整个代码库中引起连锁反应。
在Go中,结构体可用于表示数据,并且可以在应用程序的各个层之间传递。结构体还可以包含行为,使它们比DTO更强大。可以这样定义结构体:
type Person struct {
Name string
Age int
}
例如,这是一个将Person
结构体作为参数的函数:
func PrintPerson(p Person) {
fmt.Printf("Name: %s\nAge: %d\n", p.Name, p.Age)
}
可以像这样使用Person
结构体调用此函数:
p := Person{Name: "Alice", Age: 25}
PrintPerson(p)
假设我们有一个电子商务应用程序,其中包含以下层:
- HTTP层:负责处理传入的HTTP请求并返回响应。
- 服务层:负责处理业务逻辑并与数据层通信。
- 数据层:负责处理与数据库的通信。 现在,假设我们想向应用程序添加一个新功能,允许用户为其产品上传图像。为此,我们需要修改我们的HTTP层以接受图像上传,修改我们的服务层以处理图像上传,并修改我们的数据层以将图像存储在数据库中。
如果我们在各个层之间使用DTO传输数据,我们需要修改DTO以包括图像数据,这将导致我们的代码库中的连锁反应。例如:
- 我们需要修改我们的HTTP层以接受图像数据作为HTTP请求的一部分,并将其映射到我们的DTO。
- 我们需要修改我们的服务层以更新我们的DTO以包括图像数据并处理图像上传逻辑。
- 我们需要修改我们的数据层以更新我们的DTO以包括图像数据并将图像存储在数据库中。 正如你所看到的,这可能会很快变得繁琐和容易出错。此外,如果我们不小心,我们可能会得到包含大量不必要数据的DTO,使它们更难以处理并减慢我们的应用程序。
更好的方法是在不需要DTO的情况下直接在应用程序层中使用结构体。这种方法将简化我们的代码,并使向应用程序添加新功能变得更容易,而不会在我们的代码库中引起连锁反应。
在第二个示例中,我们在应用程序层中直接使用了User
结构体,而不是单独的UserDTO
结构体。这消除了额外的抽象层,并简化了我们的代码。
我们在GetUser
函数中直接使用了User
结构体,但在应用程序的其他部分仍然需要使用单独的UserDTO
结构体进行数据传输。这说明了我们如何在应用程序层中直接使用结构体,但仍需要在代码库的其他部分使用DTO。
Go的哲学是保持简单,本文可能对某些用户来说并不明显,但想法是尽可能多地使用具有嵌入和json/db注释的相同结构体来完成不同的任务。
与我们将DAO和DTO层分开的其他做法不同,尽可能简单,只需使用GO结构体。
总之,DTO通常用于在Java应用程序的各个层之间传输数据,但在Go中并非必需。Go的简洁性质和强大的结构体类型使得可以在应用程序的各个层之间传递数据而不必添加不必要的抽象层。如果需要,可以使用Option模式或Builder模式来丰富结构体。使用结构体而不是DTO,可以使你的代码更易于阅读、维护和扩展。因此,在Go中不要再使用DTO,因为它不是Java!
译自:https://dsysd-dev.medium.com/stop-using-dtos-in-go-its-not-java-96ef4794481a
评论(0)