繁体   English   中英

值对象模式与数据传输模式的区别

[英]Difference between Value Object pattern and Data Transfer pattern

在哪种情况下我可以在n层架构中使用这些设计模式?

DTO是您可以在系统边界使用的对象。 例如,当您拥有SOAP Web服务并且想要返回响应时,您将使用DTO。 处理比必须通过线路返回的实际XML更容易。 DTO通常由工具生成,例如基于WSDL。 DTO通常根据服务消费者的需求进行定制,并且可能受到性能要求的影响。

另一方面,Value对象存在于系统的核心 它捕获业务逻辑和格式规则。 它使您的代码更安全,更具表现力。 它还解决了“原始的痴迷”反模式。 很好的例子是使用类“SocialSecurityNumber”而不是字符串。 或金钱而不是小数。 这些对象应该是不可变的,这样它们看起来更像基元,并且可以在不同的线程之间轻松共享。

例如,在假设的“客户订单”系统中:

CustomerAndLastFiveOrders是DTO(已优化以避免多个网络呼叫)

客户是实体

MoneySKU是Value对象

将DTO对象与值对象进行比较就像比较橙子和苹果。

他们提供完全不同的情况。 DTO定义了数据在层之间传输的对象/类结构,而值对象在比较值时定义了相等的逻辑。

在此输入图像描述

让我用例子解释一下,让我们先尝试先理解价值对象: -

值对象是一个对象,其相等性基于值而不是标识。

考虑下面的代码,我们创建了两个货币对象,一个是一卢比硬币,另一个是一卢比纸币。

Money OneRupeeCoin = new Money();
OneRupeeCoin.Value = 1;
OneRupeeCoin.CurrencyType = "INR";
OneRupeeNote.Material = "Coin";

Money OneRupeeNote = new Money();
OneRupeeNote.Value = 1;
OneRupeeCoin.CurrencyType = "INR";
OneRupeeNote.Material = "Paper";

现在,当您比较上述对象时,下面的比较应评估为真,因为1卢比纸币在现实世界中等于1卢比硬币。

因此,要么使用“==”运算符,要么使用“等于”方法,比较应评估为true。 默认情况下,“==”或“equals”不会计算为true,因此您需要使用运算符重写和方法重写来获得所需的行为。 您可以看到此链接解释如何实现相同的目标。

if (OneRupeeCoin==OneRupeeNote)
 {
 Console.WriteLine("They should be equal");
 }
if (OneRupeeCoin.Equals(OneRupeeNote))
 {
 Console.WriteLine("They should be equal ");
 }

通常,价值对象是不可变性的良好候选者; 你可以从这里了解更多相关信息。 您可以看到此视频 ,其中描述了如何创建不可变对象。

现在让我们试着了解DTO: -

DTO(数据传输对象)是用于在层之间移动简化数据传输的数据容器。

它们也被称为转移对象。 DTO仅用于传递数据,不包含任何业务逻辑。 他们只有简单的制定者和吸气剂。

例如,考虑下面的调用我们正在进行两次调用以获取客户数据,另一次调用以获取产品数据。

DataAccessLayer dal = new DataAccessLayer();
//Call 1:-  get Customer data
CustomerBO cust = dal.getCustomer(1001);

//Call 2:-  get Products for the customer
ProductsBO prod = dal.getProduct(100);

因此,我们可以将Customer和Product类合并到一个类中,如下所示。

class CustomerProductDTO
{
  // Customer properties
        public string CustomerName { get; set; }
   // Product properties
        public string ProductName { get; set; }
        public double ProductCost { get; set; }
}

现在通过一个电话,我们将能够获得客户和产品数据。 数据传输对象在两个场景中使用,一个用于改进远程调用,另一个用于展平对象层次结构; 您可以阅读本文 ,其中详细介绍了数据传输对象。

//Only one call
CustomerProductDTO cust = dal.getCustomer(1001);

以下是完整的比较表。

在此输入图像描述

这里有几个很好的答案,但我会添加一个来捕捉关键区别:

值对象没有标识。 也就是说,包含的值对象的两个实例之间的任何比较都应表明它们是相等的。 数据传输对象虽然仅用于保存值,但确实具有标识。 比较具有相同值但独立创建的DTO的两个实例不会表明它们是相等的。

例:

DTO dto1 = new DTO(10);
DTO dto2 = new DTO(10);
dto1.equals(dto2); //False (if equals is not overridden)
dto1 == dto2; //False

VO vo1 = VO.getInstance(10);
VO vo2 = VO.getInstance(10);
vo1.equals(vo2); //True
vo1 == vo2; //True

在Java中实现Value Object模式有点困难,因为==运算符总是比较对象标识。 一种方法是实现一个对象缓存,为每个值返回相同的对象。

public class VO {
  Map<Integer, WeakReference<VO>> cache = new LinkedHashMap<Integer, WeakReference<VO>>(); 
  public static VO getInstance(int value) {
     VO cached = cache.get(value);
     if(cached == null) {
        cached = new VO(value);
        cache.put(value, new WeakReference<VO>(cached));
     }
     return cached.get();
  }

  private int value;
  private VO(int value) {
    this.value = value;
  }
}

我会建议反对数据传输对象。 在我看来,这是一个EJB 1.0反模式,由坚持层纯度的人赋予价值。

值对象很有用。 它通常是一个不可变的对象,比如Money。 它们应该是线程安全的。

值对象是封装为对象有用的东西,但它没有标识。 将它与实体进行比较,实体具有身份。 因此,在订单处理系统中,客户或订单或LineItem是指向特定人员或事物或事件的概念,因此它们是实体,其中值对象类似于货币金额,没有独立存在自己。 例如,对于部分应用程序涉及计算如何在不同帐户之间划分支付的系统,我创建了一个不可变的Money对象,该对象具有divide方法,该方法返回Money对象数组,均匀地将原始对象的数量分割为它们,方式分配金额的代码在一个方便的地方,编写jsp的人可以使用它,并且他们不必使用非表示相关的代码搞乱jsp。

数据传输对象是一个包装器,用于将各个事物捆绑在一起,以便跨应用程序层或层进行发送。 我们的想法是,您希望通过设计发送大量信息的方法来最小化网络来回流量。

数据传输对象用于设置来自数据访问层(DAO)中的数据库的属性值,而使用VO模式,我们可以在MVC的控制器层中设置已在DAO层中设置的值。 客户端可以访问VO对象而不是他/她可以在jsp页面中迭代的DTO。 你可以说这两个层都存在分离关系。

DTO是一个代表一些没有逻辑的数据的类。 DTO通常用于在单个应用程序中的不同应用程序或不同层之间传输数据。 您可以将它们视为愚蠢的信息袋,其唯一目的是将此信息提供给收件人。

另一方面, Value Object是域模型的完整成员。 它符合与实体相同的规则。 Value Object和Entity之间的唯一区别是Value Object没有自己的标识。 这意味着具有相同属性集的两个值对象应该被视为相同,而两个实体即使它们的属性匹配也不同。

值对象确实包含逻辑,通常它们不用于在应用程序边界之间传输数据。 在这里阅读更多

值对象和数据传输对象是设计模式。

  • 值对象 :在需要根据对象的值测量对象的相等性时使用。

真实世界的例子是java.time.LocalDate

public class HeroStat {

   // Stats for a hero

   private final int strength;
   private final int intelligence;
   private final int luck;

   // All constructors must be private.
   private HeroStat(int strength, int intelligence, int luck) {
    this.strength = strength;
    this.intelligence = intelligence;
    this.luck = luck;
   }

  // Static factory method to create new instances.
  public static HeroStat valueOf(int strength, int intelligence, int luck) {
    return new HeroStat(strength, intelligence, luck);
  }

  public int getStrength() {
     return strength;
  }

  public int getIntelligence() {
     return intelligence;
  }

  public int getLuck() {
     return luck;
  }

  /*
   * Recommended to provide a static factory method capable of creating an instance 
       from the formal
   * string representation declared like this. public static HeroStat parse(String 
     string) {}
   */

  // toString, hashCode, equals

  @Override
  public String toString() {
      return "HeroStat [strength=" + strength + ", intelligence=" + intelligence
    + ", luck=" + luck + "]";
  }

  @Override
  public int hashCode() {
     final int prime = 31;
     int result = 1;
     result = prime * result + intelligence;
     result = prime * result + luck;
     result = prime * result + strength;
     return result;
  }

  @Override
  public boolean equals(Object obj) {
       if (this == obj) {
          return true;
        }
       if (obj == null) {
          return false;
       }
       if (getClass() != obj.getClass()) {
          return false;
       }
       HeroStat other = (HeroStat) obj;
       if (intelligence != other.intelligence) {
          return false;
       }
       if (luck != other.luck) {
          return false;
       }
       if (strength != other.strength) {
          return false;
       }
          return true;
    }
    // The clone() method should not be public. Just don't override it.
  }

- 数据传输对象 :从客户端到服务器一次性传递具有多个属性的数据,以避免多次调用远程服务器。

  public class CustomerDto {
       private final String id;
       private final String firstName;
       private final String lastName;

       /**
        * @param id        customer id
        * @param firstName customer first name
        * @param lastName  customer last name
        */
        public CustomerDto(String id, String firstName, String lastName) {
           this.id = id;
           this.firstName = firstName;
           this.lastName = lastName;
        }

        public String getId() {
           return id;
        }

        public String getFirstName() {
           return firstName;
        }

        public String getLastName() {
           return lastName;
        }
     }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM