在项目不同层次使用不同类型的对象包装类的理解:VO,Entity,DTO,POJO

DDD perspective

Persistence Ignorance

Persistence Ignorance holds that you should separate your domain model from the underlying persistence storage. Classes that you use for modeling your business domain shouldn’t be impacted by how they are stored in the database. Ideally, their design should be as close as possible to the design needed to solve the problem at hand, without taking into consideration persistence concerns.

Value Object

Value Objects explained

Entity

Entity Base Class

Value Object vs. Entity

Entity vs Value Object: the ultimate list of differences

1、相等性比较:
entity 比较唯一标识符字段的值;—— identity equality,同一个对象
value object 比较结构中所有字段的值,没有唯一标识符。—— structural equality,一组相同值的组合
2、历史记录:
entity 因为有唯一标识字段id,所以有该id对象的值变化记录了该entity的历史变化;
value object 没有唯一标识符,所有没有历史记录。
3、独立存在:
entity 指向一个真实的逻辑对象,可以独立存在;
value object 只是一组值的记录,需要作为 entity 的成员对象才有存在意义。
4、不可变性:
entity 可变;
value object 不可变。若value object 值变化,由相等性比较原则,得与变化前的value object 不再是同一个object,所以具有不可变性。
5、数据库表对象:
entity 结构对应于数据库表的表结构;(只要唯一标识符相等就是同一个entity)
value object 不具有实体意义,不能对应于数据库表。(只要值相等就是同一个value object)
6、由于value object 的不可变性,应该总是优先选择value object .

Entity Framework vs. NHibernate

EF Core 2.1 vs NHibernate 5.1: DDD perspective

ORM对EF中在域模型(domain model)中使用值对象(value object)的两个限制:

1、实体中的值对象属性不能为null(entity 中的 value object 不能为null)
2、值对象不能引用实体(value object 不能指向entity,因为缺少entity中的唯一标识字段)

这些限制导致无法构建隔离域模型。NHibernate没有这样的限制

举例说明限制内容:
如下有一个实体类Customer,包含了一个值对象Address

public class Customer // Entity
{

    public int Id { get; set; }

    public string Name { get; set; }

    public Address Address { get; set; }

}

public class Address // Value Object
{

    public string Street { get; set; }

    public string City { get; set; }

}

1、若需要标识地址不存在,按照限制一:address值对象不可以为null,只能通过时address对象的各字段值为null表示

public class Customer
{

    public Customer(int id, string name)
        : this()
    {

        Id = id;

        Name = name;

        Address = null; // Can’t do that.必须要像下面的方法,使address中的各字段值为空
    }

	public Customer(int id, string name)
        : this()
    {

        Id = id;

        Name = name;

        Address = new Address(null, null, null);
    }
}

2、使用如下的定义来表示一个Customer实体是不可以的。因为值对象不能引用实体。

public class Customer // Entity

{
    public int Id { get; set; }

    public string Name { get; set; }

    public Address Address { get; set; }

}

 

public class Address // Value Object
{

    public string Street { get; set; }

    public string City { get; set; }

    public Country Country { get; set; } // Not supported. 值对象中不可引用实体类对象

}


public class Country // Entity
{

    public int Id { get; protected set; }

    public string Name { get; protected set; }

}

detached mode

domain model

DTO vs Value Object vs POCO
Having the domain model separated from the persistence model

分类

1、DTO——Data Transfer Object

没有逻辑概念的数据传输对象,用于在一个应用的不同层次或不同应用之间的数据传输。

2、Value Object

具有逻辑概念的数据对象,不具有唯一标识符,作为域模型的组成元素,常作为域实体的属性成员体,不用于数据传输。

3、POJO——Plain Old Java Object, also known as POCO in .Net(Plain Old CLR Object)

区别于 类似于JavaBean这种重型企业Java对象,POJO用于创建于与执行环境无关的域模型,大大降低了表关系的复杂度(因为JavaBean是与执行环境相关的)。

换句话说,Value Object和DTO不应该继承任何重量级的企业组件,因此它们是POCO。 同时,POCO是一个更广泛的集合:它可以是值对象,实体,DTO或您可能创建的任何其他类,只要它不会继承您域中的意外复杂性。
在这里插入图片描述
在这里插入图片描述

持久层、表现层是否应该公用一个域模型的比较

持久层:persistence layer
表现层:presentation layer、business layer
域模型:domain model
域实体:domain entity
持久模型:persistence model

1、共用一个域模型:

优点:

因为不需要进行“用于接收表现层数据的对象”与“用于持久层的实体类对象”之间的转换,所以效率会高一点。

缺点:

1、冗余包
该类的定义会变复杂,同时包含了两个层次需要用到的包,使用时会显得冗余 ——如果您的实体被“传递”到您的表示层,那么该层需要“了解”您在持久层中使用的特定库/框架。如果你正在做web 的东西,这不是什么大问题,但如果你做rich clients(例如Swing)那么可能你的客户需要随身携带额外包袱)

2、冗余字段
若实体类Entity与传输对象DTO不是一对一的关系,比如表现层/业务层需要一些持久层中用不到的字段(DTO需要比实体类更多的字段),那么对于持久层来说,会有多余字段。

3、数据库对象的立即加载
当尝试获取某个记录的子记录时,根据懒加载原则,会自动查询数据库获取子记录。但若我们只是想要查看前端是否传了子记录进行非空判断,这种表现层与持久层混用域模型的方式,将使这样的判断不可行。

4、发生非预期sql操作
编者工作中发现,在使用hibernate持久层框架时,调用实体类的 setter 方法会引起框架自动调用update语句同步setter操作到数据库(更新某个记录的某个字段、对标注了OneToMany等关系字段的关联表进行级联更新或删除)—— 但这不是我们想要的。

@Entity
@Table(name = "app_user")
public class User implements Serializable
{
	@Id
	@SequenceGenerator(name = "id_app_user_seq", sequenceName = "id_app_user_seq")
	@GeneratedValue(generator = "id_app_user_seq", strategy = GenerationType.AUTO)
	@Column(name = "id")
	private Long id;

	/**
	 * 密码
	 */
	@Column(name = "password")
	private String password;
	
	/**
	 * 拥有的角色列表
	 */
	@ManyToMany(targetEntity = Role.class, fetch = FetchType.LAZY)
	@JoinTable(name = "app_user_role_relation", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
	private Set<Role> roles;

	//省略 setter、getter...
}

//存储了一条数据库记录的实体类对象:entity
...
entity.setPassword(null);
entity.setRoles(null);
HttpServletUtils.updateUserInSession(session, entity);//持久化对象到session内存中
return entity;
//本方法结束后,会自动执行update user表置空本记录的password字段值,且执行delete app_user_role_relation删除本记录在映射关系表中对应记录。
//然后本方法的本意是避免用户敏感信息存储到session中,所以这些连带sql 是不可接受的

2、若在不同的层次使用不同的域模型

结构独立,使用更加灵活;易于扩展;对于需要对接不同客户端的服务,可以使用不同的表现层实现业务包装。

3、若混用域模型

可以根据业务的复杂程度,对不同模块使用不同的域模型

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: DTO (Data Transfer Object) 是一种软件设计模式,用于在多个系统之间传递数据。它是一个简单的Java对象,用于封装数据,可以将数据从一个系统传递到另一个系统。 Entity是一个业务对象,表示数据库中的一张表,是数据库持久化对象,也是一种软件设计模式,用于表示业务对象POJO (Plain Old Java Object) 是指普通的Java对象,没有继承任何特殊类或实现任何特殊接口。它可能是一个EntityDTO。 总的来说,DTO是用于在系统之间传递数据的对象Entity是持久化对象POJO是普通的Java对象。 ### 回答2: DTOVOEntityPOJO(Plain Old Java Object)是开发中常见的四种对象,它们各有不同的作用和用途。 1. DTO(Data Transfer Object)数据传输对象 DTO是用于不同层之间数据传输的一种对象。通常在业务逻辑层和表示层之间传输,作为中转站,可以减少对数据库重复操作和网络传输次数,提高效率。 2. VO(Value Object)值对象 VO是一个类,它封装了某个方法调用的返回值或者给用户端展示的属性列表。它使用在业务逻辑层和表现层之间传递简单数据类型VO属于供客户端使用,是用来展示数据的一种业务对象。 3. Entity Entity是实体类,它是用来与数据库相映射的一种对象。实体类一般与数据表的结构对应,每个实体都是一个持久化对象,实体中包含了要操作的数据和对数据的操作。它用于ORM(Object-Relational Mapping)关系映射,ORM技术将数据库表结构映射为面向对象的实体,对数据操作进行简化。 4. POJO(Plain Old Java Object)普通Java对象 POJO是一种普通的Java对象,它没有实现任何框架或者接口,不依赖任何第三方库,通用性比较强。POJO对象只有属性的get和set方法,用来简单地封装数据。它是用来承载业务数据或数据VO对象的一种对象。 总结: 在实际开发中,我们可能会用到DTOVOEntityPOJO这几种对象DTO用于不同层之间数据传输,VO用于业务层和表现层之间传输,Entity用于与数据库相映射,POJO用于承载业务数据或数据VO对象。我们需要根据实际开发需要,针对每种类型对象,进行合理使用。 ### 回答3: DTOVOEntityPOJO是Java编程中常见的概念,它们分别代表不同的数据模型。 DTO(Data Transfer Object)是一种数据传输对象,它主要用于不同层之间数据的传输,可以理解为数据的载体或者数据的容器。DTO通常包含多个属性,但不包含任何业务逻辑,DTO中的属性通常可以是各种类型的JavaBean、字符串或者Java基本数据类型VO(Value Object)是一种值对象,通常将数据从一个或多个Java Bean中提取出来,并将这些值组合成一个全新的对象。与DTO不同的是,VO在传输过程中不仅带有数据,还包含了一些描述这些数据的特征和属性的信息,通常是直接在Java Bean中提取出来的属性和方法。 Entity是一种实体对象,通常代表数据库中的一张表或者多张表的关联信息。Entity包含了所有的业务逻辑、数据库交互和持久化逻辑,并且通过ORM框架实现数据的 CRUD 操作。在项目中,Entity通常是Java对象和数据库表之间的桥梁。 POJO(Plain Old Java Object)是普通的Java对象,它是一种简单的Java类,没有任何限制,不继承或实现任何Java类或接口,也不需要遵循任何可重载构造函数的规则。POJO可以用来表示Java中的任何一种数据类型,通常不包含业务逻辑或任何框架相关的代码。 总的来说,DTOVO是用于数据传输的,而EntityPOJO则是用于数据持久化和业务逻辑的。DTOVO在传输过程中的区别比较难理解,需要在实际项目中进行实践和对比,而EntityPOJO是用来处理数据库操作的,需要符合设计模式和项目的实际需要。因此,在实际开发中,需要结合项目的实际情况选择使用不同的数据模型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值