zoukankan      html  css  js  c++  java
  • 实体与值对象的区别

    在面向对象的软件设计中,万物皆为对象。甚至在Java中,为了保证万物皆为对象,还为基本类型设置了包装类。但即使这样,这些对象也需要我们进一步地进行区分。

    假设存在下面的对象

    public class User {
        private Integer id;
        private String name;
        private String address;
        private String email;
    }

    显然User是我们定义的一个对象,而内部则是该对象的属性。

    我们继续分析这几个属性:

    name属性:按照国人的习惯,最好是姓氏、名字单独存放,以便于在必要时展现“李先生”、“刘女士”等这样的称呼。使用一个简单的String存储显然无法实现。我们可以将name属性拆分为firstName和lastName两个属性,但这样一来,姓氏与名字的拼接工作必须由User对象负责。但是,总感觉不合适,因为所有人的姓氏和名字的拼接规则都一样,似乎不应该有独立的User完成拼接。

    adress属性:地址是一个长长的字符串,包含省、市、县等信息,更关键的,还有非必填的邮编等信息。如果我们把他们都放在一个String里面,显然过于混乱,也面临不好拆分的问题。于是,我们可以考虑将其作为一个地址对象存储,让地址对象包含各个子信息。但这时又让人感觉怪怪的,因为这个对象似乎难以复用。即使用户A和用户B填写了相同的地址也不好复用这一地址,因为不能让一方的修改影响另一方。

    email属性:电子邮件地址有着固定的规则,在存入前需要校验。如果使用String存放电子邮件地址,则校验规则要放在别处,这破坏了内聚性。最好是让email属性自身完成。

    再进一步分析,我们发现id属性也是如此。id不一定是数字,可能是一个字符串。而且,id可能包含了一套生成和校验规则,例如我们的身份证号就包含了所属人的籍贯、生日、性别等信息。

    分析完以上几个属性后,我们发现这些属性不是基本类型,但是又和User这种对象不同。例如我们可以分别定义Name、Address、Email类,他们介于User这类对象和基本类型之间。

    这些对象具有以下的特点:

    1. 没有编号,不能进行相等与否的比较。除非对象内存地址相同,否则他们就是不等的。
    2. 不能更新,很像是一个基本值。如果我们要修改它,则直接生成一个新的它即可,而不是更新它。这意味着我们可以放心地多处引用同一个它,而不用担心一处修改了它影响别处。这点和String的不可更新特性一样。
    3. 他们具有业务意义,仅从名字就能看出他们的作用。这一点是十分友好的。
    4. 他们可以集成相关功能。因为他们本身就是对象,内部可以实现相关的验证逻辑等各类逻辑。因此是一个包含属性和行为的整体。

    以上这种对象,我们称之为值对象。值对象用来表示属性的不变值和属性的行为。

    在面向对象的编程中引入值对象能够提升代码的可读性,提升内聚性。

    而像User这样的对象则称为实体。实体和值对象是不同的,实体存在唯一性标志,而实体是否相等的判断依据就是唯一性标志。

    例如,两个User对象,他们的地址可能并不相同,但是只要两者的id一样,则这样两个对象就是相等的。假设User01存放在内存中,将其序列化再反序列化后得到User02,则User01和User02的地址并不相同,但因为两者id一样,实际为一个对象。

    另外再说一点,实体和值对象的界限不是绝对的。

    例如在一个外卖系统中,地址是一个值对象,从属于人;在社区管理系统中,地址则是一个实体,与人存在多对多的关系。具体的划分要根据业务场景来确定。

  • 相关阅读:
    CentOS 用命令访问网页
    ngalian(一)2:安装npm环境
    数仓建设原则探讨
    C#中获取系统时间 LZU
    判断是否是数字类 LZU
    Extjs中ComboBoxTree的实现 LZU
    SQL之学生选课数据库 LZU
    如何看书 LZU
    面向对象思想 LZU
    C#控件命名规范 LZU
  • 原文地址:https://www.cnblogs.com/yt954437595/p/15581201.html
Copyright © 2011-2022 走看看