In which scenario can I use those design patterns in n-tier archi开发者_JS百科tecture?
DTO is the object that you can use at the boundaries of the system. When you have a SOAP web service for example and you want to return response you would use DTO. It easier to deal with than actual XML that has to be returned over the wire. DTOs are often generated by tools, based on WSDL for example. DTO are often tailored to the needs of service consumer and can be affected by performance requirements.
Value objects on the other hand live in the core of the system. It captures pieces of business logic and maybe formatting rules. It makes your code more type safe and expressive. It also tackles "Primitive obsession" anti pattern. Good example is using class "SocialSecurityNumber" instead of string. Or Money instead of decimal. These objects should be immutable so that they look more like primitives and can be easily shared among different threads.
For example in hypothetical 'customer-order' system:
CustomerAndLastFiveOrders is DTO (optimized to avoid multiple network calls)
Customer is Entity
Money and SKU are Value objects
Comparing DTO objects with value objects is like comparing oranges and apples.
They serve completely different situations. DTO defines the object / class structure of how data will be transferred between layers while value objects defines the logic for equality when values are compared.
Let me explain you with examples, let us first try to understand value objects first :-
Value object is an object whose equality is based on the value rather than identity.
Consider the below code we have created two objects of money one is one rupee coin and the other is a one rupee paper currency.
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";
Now when you compare the above objects the below comparison should evaluate to true because 1 rupee note is equal to 1 rupee coin in real world.
So either you are using “==” operator or you are using the “Equals” method the comparison should evaluate to true. By default “==” or “equals” will not evaluate to true so you need to use operator overriding and method overriding to get the desired behavior. You can see this link which explains how to achieve the same.
if (OneRupeeCoin==OneRupeeNote)
{
Console.WriteLine("They should be equal");
}
if (OneRupeeCoin.Equals(OneRupeeNote))
{
Console.WriteLine("They should be equal ");
}
Normally value objects are good candidates for immutability; you can read more about it from here. You can see this video which describes how immutable objects can be created.
Now let’s try to understand DTO:-
DTO (Data Transfer objects) is a data container for moving simplifying data transfer between layers.
They are also termed as transfer objects. DTO is only used to pass data and does not contain any business logic. They only have simple setters and getters.
For example consider the below call we are making two calls one to get customer data and the other to get product data.
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);
So we can combine the Customer and Product class in to one class as shown below.
class CustomerProductDTO
{
// Customer properties
public string CustomerName { get; set; }
// Product properties
public string ProductName { get; set; }
public double ProductCost { get; set; }
}
Now with one call we will be able to get both customer and product data. Data transfer objects are used in two scenarios one to improve remote calls and second to flatten object hierarchy; you can read this article which explains more about data transfer objects.
//Only one call
CustomerProductDTO cust = dal.getCustomer(1001);
Below is the complete comparison sheet.
There are several good answers here, but I'll add one to capture a key difference:
Value objects do not have an identity. That is, any comparison between two instances of a value object that contain the same values should indicate that they are equal. Data Transfer Objects, while only being used to hold values, do have an identity. Comparing two instances of a DTO that have the same values, but were created independently, will not indicate that they are equal.
Example:
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
It's slightly difficult to implement the Value Object pattern in Java, since the == operator always compares object identity. One way to do so would be to implement an object cache that returns the same object for each value.
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;
}
}
A value object is something that is useful to encapsulate as an object, but it has no identity. Compare it to an entity, which is something that does have identity. So in an order-processing system a Customer or an Order or a LineItem are concepts that point back to specific people or things or events, so they are entities, where a value object is something like a monetary amount, that doesn't have an independent existence of its own. For instance, for a system where part of the application involved calculating how to divide a payment between different accounts, I created an immutable Money object that had a divide method that returned an array of Money objects evenly splitting the original object's amount across them, that way the code for dividing amounts was in a place that was handy where the person writing the jsp could use it, and they didn't have to mess up the jsp with non-presentation-related code.
A Data Transfer Object is a wrapper for bundling things together for sending across application tiers or layers. The idea is that you want to minimize the amount of network back-and-forth traffic by designing methods that send large bundles of information.
I would advise against the data transfer object. It's an EJB 1.0 anti-pattern, in my opinion, given value by those who insist in layer purity.
A value object is useful. It's usually an immutable object, like Money. They should be thread-safe.
DTO is a class representing some data with no logic in it. DTO’s are usually used for transferring data between different applications or different layers within a single application. You can look at them as dumb bags of information the sole purpose of which is to just get this information to a recipient.
On the other hand, Value Object is a full member of your domain model. It conforms to the same rules as an Entity. The only difference between Value Object and Entity is that Value Object doesn’t have its own identity. It means that two Value Objects with the same property set should be considered the same whereas two Entities differ even if their properties match.
Value Objects do contain logic and, typically, they are not used for transferring data between application boundaries. Read more here
Data Transfer Object is used to set property values which is coming from database in Data Access Layer (DAO), whereas using VO pattern we can set values in controller layer of MVC that are already set in DAO Layer. Client can have access to VO objects rather than DTO's which he/she can iterate in jsp page. You can say there is a separation of concern for both layers.
Value Object and Data Transfer Object are design pattern.
- Value Object : Use when need to measure the objects' equality based on the objects' value.
Real world example is 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.
}
- Data Transfer Object : Pass data with multiple attributes in one shot from client to server, to avoid multiple calls to remote server.
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;
}
}
精彩评论