在DDD中,DTO(数据传输对象)->BO(业务对象)、BO(业务对象)->PO(持久化对象,有的叫DO,即和数据表映射的实体)等等情况要做转换,这里提供以下转换方式
1、from或者try_from trait实现对象转换
需要转换对象满足接收对象的所有字段
客户定义
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Customer {
// uuid
pub user_id: String,
// 用户名
pub username: String,
// 邮件
pub email: String,
// 密码
pub password: String,
// 头像
pub avatar: Option<String>,
// 验证码
pub verify_code: Option<String>,
// 收货地址
pub receive_address: Vec<ReceiveAddress>,
}
通过实现from trait,可以从Model转换为Customer
impl From<Model> for Customer {
fn from(user: Model) -> Self {
Customer {
user_id: user.user_id,
username: user.username,
email: user.email,
password: user.password,
avatar: user.avatar,
verify_code: user.verify_code,
receive_address: user.receive_address,
}
}
}
实现了From trait默认自动实现Into trait,你可以通过以下两种方式实现对象转换,Try from trait用法一样,只是在转换失败时可以返回错误
// 使用from方法将Model实例转换为Customer实例
let customer_instance = Customer::from(model_instance);
// 或者使用更简洁的into方法,它会自动调用对应的from方法
let another_customer_instance = model_instance.into();
但是这样不够优雅,很多时候DTO并不能满足领域对象的所有字段,数据对象也不能满足领域对象的所有字段,例如以上例子的验证码和收货地址,最初没有数据时需要设置默认值
// 转Bo
impl From<Model> for Customer {
fn from(user: Model) -> Self {
Customer {
user_id: user.user_id,
username: user.username,
email: user.email,
password: user.password,
avatar: user.avatar,
verify_code: None,
receive_address: vec![],
}
}
}
当下一次从数据库中查到数据需要给收货地址赋值的情况下,这种方案就不适用了,可以使用以下建造者模式
2、链式调用
此时所有字段都是private的,通过builder去赋值
// 注意使用了Default,没有builder的值有默认值
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct Customer {
// uuid
pub user_id: String,
// 用户名
pub username: String,
// 邮件
pub email: String,
// 密码
pub password: String,
// 头像
pub avatar: Option<String>,
// 验证码
pub verify_code: Option<String>,
// 收货地址
pub receive_address: Vec<ReceiveAddress>,
}
impl Customer {
// new默认值
pub fn new() -> Self {
Self {
user_id: String::new(),
username: String::new(),
email: String::new(),
password: String::new(),
avatar: None,
verify_code: None,
receive_address: Vec::new(),
}
}
pub fn user_id(mut self, user_id: String) -> Self {
self.user_id = user_id;
self
}
pub fn username(mut self, username: String) -> Self {
self.username = username;
self
}
pub fn email(mut self, email: String) -> Self {
self.email = email;
self
}
pub fn password(mut self, password: String) -> Self {
self.password = password;
self
}
pub fn avatar(mut self, avatar: Option<String>) -> Self {
self.avatar = avatar;
self
}
pub fn verify_code(mut self, verify_code: Option<String>) -> Self {
self.verify_code = verify_code;
self
}
pub fn receive_address(mut self, receive_address: Vec<ReceiveAddress>) -> Self {
self.receive_address = receive_address;
self
}
}
使用
let customer = Customer::new()
.user_id("123".to_string())
.username("张三".to_string())
.email("<EMAIL>".to_string());
let customer = customer.avatar(Some("https://www.baidu.com".to_string()));
print!("{:?}\n", customer);
//Customer { user_id: "123", username: "张三", email: "<EMAIL>", password: "", avatar: Some("https://www.baidu.com"), verify_code: None, receive_address: [] }
// 修改原有对象
let customer = customer.email("123@qq.com".to_string());
println!("{:?}", customer);
//Customer { user_id: "123", username: "张三", email: "123@qq.com", password: "", avatar: Some("https://www.baidu.com"), verify_code: None, receive_address: [] }
这种方式容易造成意外修改的传播,不推荐
3、建造者模式实现对象转换
在Java中很简单,加上@Builder注解即可
@Builder
public class User {
private UserLastname lastname;
private UserFirstname firstname;
private UserEmail email;
private UserPublicId userPublicId;
private UserImageUrl imageUrl;
private Instant lastModifiedDate;
private Instant createdDate;
private Set<Authority> authorities;
private Long dbId;
private UserAddress userAddress;
private Instant lastSeen;
public User(UserLastname lastname, UserFirstname firstname, UserEmail email, UserPublicId userPublicId, UserImageUrl imageUrl, Instant lastModifiedDate, Instant createdDate, Set<Authority> authorities, Long dbId, UserAddress userAddress, Instant lastSeen) {
this.lastname = lastname;
this.firstname = firstname;
this.email = email;
this.userPublicId = userPublicId;
this.imageUrl = imageUrl;
this.lastModifiedDate = lastModifiedDate;
this.createdDate = createdDate;
this.authorities = authorities;
this.dbId = dbId;
this.userAddress = userAddress;
this.lastSeen = lastSeen;
}
}
通过builder()使用,通过结尾的build()返回新对象
UserBuilder
.email(user.getEmail().value())
.firstName(user.getFirstname().value())
.lastName(user.getLastname().value())
.publicId(user.getUserPublicId().value())
.authorities(RestAuthority.fromSet(user.getAuthorities()))
.build()
Rust实现(值传递)建造者模式
和直接链式调用相比,添加了一个build函数返回新对象
// 注意使用了Default,没有builder的值有默认值
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct Customer {
// uuid
user_id: String,
// 用户名
username: String,
// 邮件
email: String,
// 密码
password: String,
// 头像
avatar: Option<String>,
// 验证码
verify_code: Option<String>,
// 收货地址
receive_address: Vec<ReceiveAddress>,
}
// 建造(者结构体,包含一个需要构建的对象
#[derive(Default, Clone, Debug)]
pub struct CustomerBuilder {
customer: Customer,
}
impl CustomerBuilder {
pub fn new() -> Self {
// 初始化默认值
CustomerBuilder::default()
}
pub fn user_id(mut self, user_id: String) -> Self {
self.customer.user_id = user_id;
self
}
pub fn username(mut self, username: String) -> Self {
self.customer.username = username;
self
}
pub fn email(mut self, email: String) -> Self {
self.customer.email = email;
self
}
pub fn password(mut self, password: String) -> Self {
self.customer.password = password;
self
}
pub fn avatar(mut self, avatar: Option<String>) -> Self {
self.customer.avatar = avatar;
self
}
pub fn verify_code(mut self, verify_code: Option<String>) -> Self {
self.customer.verify_code = verify_code;
self
}
pub fn receive_address(mut self, receive_address: Vec<ReceiveAddress>) -> Self {
self.customer.receive_address = receive_address;
self
}
pub fn build(self) -> Customer {
Customer {
user_id: self.customer.user_id,
username: self.customer.username,
email: self.customer.email,
password: self.customer.password,
avatar: self.customer.avatar,
verify_code: self.customer.verify_code,
receive_address: self.customer.receive_address,
}
}
}
使用,没有建造的字段由于Default宏的存在会初始化默认值,这种用法和第二种链式调用方式相比每次创建新对象,对象无法修改,只能创建新对象,使用对象会消耗对象,适合创建值对象、响应DTO、Event(因为这些对象用完就会被Drop,创建后就不可变)
let customer_builder = CustomerBuilder::new();
let customer = customer_builder
.clone()
.user_id("123".to_string())
.username("张三".to_string())
.email("<EMAIL>".to_string());
let customer = customer.clone().avatar(Some("https://www.baidu.com".to_string()));
let customer = customer.clone().build();
print!("{:?}\n", customer);
// Customer { user_id: "123", username: "张三", email: "<EMAIL>", password: "", avatar: Some("https://www.baidu.com"), verify_code: None, receive_address: [] }
// 创建新对象
let customer = customer_builder.clone().email("123@qq.com".to_string()).build();
println!("{:?}", customer);
// Customer { user_id: "", username: "", email: "123@qq.com", password: "", avatar: None, verify_code: None, receive_address: [] }
Rust实现(引用修改)建造者模式
如果不想消耗对象,可以将其字段都设置为&mut,使用clone()是为了返回的新对象是完全独立的副本
// 注意使用了Default,没有builder的值有默认值
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct Customer {
// uuid
user_id: String,
// 用户名
username: String,
// 邮件
email: String,
// 密码
password: String,
// 头像
avatar: Option<String>,
// 验证码
verify_code: Option<String>,
// 收货地址
receive_address: Vec<ReceiveAddress>,
}
// 建造(者结构体,包含一个需要构建的对象
#[derive(Default, Clone, Debug)]
pub struct CustomerBuilder {
customer: Customer,
}
impl CustomerBuilder {
pub fn new() -> Self {
CustomerBuilder::default()
}
pub fn user_id(&mut self, user_id: String) -> &mut Self {
self.customer.user_id = user_id;
self
}
pub fn username(&mut self, username: String) -> &mut Self {
self.customer.username = username;
self
}
pub fn email(&mut self, email: String) -> &mut Self {
self.customer.email = email;
self
}
pub fn password(&mut self, password: String) -> &mut Self {
self.customer.password = password;
self
}
pub fn avatar(&mut self, avatar: Option<String>) -> &mut Self {
self.customer.avatar = avatar;
self
}
pub fn verify_code(&mut self, verify_code: Option<String>) -> &mut Self {
self.customer.verify_code = verify_code;
self
}
pub fn receive_address(&mut self, receive_address: Vec<ReceiveAddress>) -> &mut Self {
self.customer.receive_address = receive_address;
self
}
pub fn build(&self) -> Customer {
Customer {
user_id: self.customer.user_id.clone(),
username: self.customer.username.clone(),
email: self.customer.email.clone(),
password: self.customer.password.clone(),
avatar: self.customer.avatar.clone(),
verify_code: self.customer.verify_code.clone(),
receive_address: self.customer.receive_address.clone(),
}
}
}
使用,这里对象创建后不会消耗对象,可以通过.build()修改并返回新对象,适合创建领域模型如聚合对象
let mut binding = CustomerBuilder::new().clone();
let customer = binding
.user_id("123".to_string())
.username("张三".to_string())
.email("<EMAIL>".to_string());
let customer = customer.avatar(Some("https://www.baidu.com".to_string()));
let customer = customer.build();
print!("{:?}\n", customer);
//Customer { user_id: "123", username: "张三", email: "<EMAIL>", password: "", avatar: Some("https://www.baidu.com"), verify_code: None, receive_address: [] }
// 修改原有对象
let customer = binding.email("123@qq.com".to_string()).build();
println!("{:?}", customer);
//Customer { user_id: "123", username: "张三", email: "123@qq.com", password: "", avatar: Some("https://www.baidu.com"), verify_code: None, receive_address: [] }