到目前为止,您可能在想:“他在说什么?Decodable
和Encodable
协议非常有用!”
我也同意你的看法。在Decodable
和Encodable
协议确实很有用。例如,Swift提供了一种本地方法来解析JSON元素或从 User Defaults 存储和检索对象,这是很棒的。没有什么问题。
但是,我认为我们在模型对象中使用这些协议会犯错。我将尝试解释原因。
领域模型和数据模型
领域模型(Domain Model) 是一种面向对象的模型,该模型合并了行为和数据。它代表了我们试图建模的业务规则。
数据模型(Data Model) 是持久性存储中的数据结构。它没有任何行为。
持久性存储的一些例子是 User Defaults ,Core Data ,文件,数据库,甚至是外部API。这些存储中的每个存储中的数据模型都可能不同。
领域模型和数据模型都包含数据,但是领域模型也包含业务规则。
领域模型中的对象应该不知道使用哪个持久性存储或数据模型。
这是因为领域模型和数据模型有不同的原因而改变。仅当执行业务规则或获得更多关于解决问题的见解时,领域模型才应更改。
另一方面,数据模型可能由于不同的原因而改变。例如,持久性存储需要从本地存储更改为远程API。领域模型不应受此基础结构更改的影响。
Decodable和Encodable
Decodable
协议用于对来自某些外部表示的对象进行 转化 。例如,它用于将JSON对象解析为结构体或类。
Decodable:一种可以从外部表示形式进行解码的类型。
另一方面,该 Encodable
协议用于将对象存储到某个外部表示中。例如,它可用于获取对象的JSON表示形式。
Encodable:可以将自身编码为外部表示形式的类型。
但是,为什么我们不可以使用Decodable
或Encodable
在我们的领域模型对象?
让我们用一个例子来回答这个问题。假设我们具有以下用户的JSON表示形式:
{
“ first_name”:“ dick”,
“ last_name”:“ richardson”,
“ mail”:“ drichardson@enclave.com”,
“ day_of_birth”:7026198103
}
我们使用一个名为User
的Decodable
结构体解析JSON,并在我们的领域模型中表示一个User
:
struct User: Decodable {
let firstName: String
let lastName: String
let email: String
let dayOfBirth: Int
}
但是,如果JSON发生变化会怎样?假设现在first
和last
名称位于一个name
字段中:
{
“ name”:{
“ first”:“ dick”,
“ last”:“ richardson”
},
“ email”:“ drichardson@enclave.com”,
“ day_of_birth”:7026198103
}
由于此较小的更改,以前的User
结构现在无法解析JSON数据。我们被迫更改领域模型以解析新的数据模型:
struct User: Decodable {
let name: Name
let email: String
let dayOfBirth: Int
struct Name: Decodable {
let first