Home java An illustrative example of the difference DTO, POCO (POJO) and Value Object

An illustrative example of the difference DTO, POCO (POJO) and Value Object

Author

Date

Category

Inspired by an article about the differences DTO, POCO and Value Object on Habrahabr:
DTO vs POCO vs Value Object , as well as
question POCO vs DTO .

Nowhere is there concrete examples. Please provide a specific example of a description of a small (or as an example), where and how to use it and why.

UPD

Excellent answers. Thanks to all.

Another small question on the use of POCO. When and how efficiently to push the logic into objects? Here for example, I have a service layer that returns the POCO, which methods I go there I can insert? Let’s say I need to validate kastomer, ok, I did in POCO method Validate , as long as I do not need to climb to validate the database – all good, but as soon as it is needed, the idea does not seem so good. Or am I wrong? Now I have an application, where almost all the action executes the business layer in the models only simple methods such as GetFullName , and in fact I operate DTO-Hami. Now, how to keep track of that fine line “in POCO, that when” or even “all the logic in services operate DTO”?


Answer 1, Authority 100%

provide some online store. This shop has a web interface and an application server that handles the logic. A user wants to make some order. To do this, he needs to perform the following steps: add the desired items to cart and confirm the order

.

To do this, the application server may be a class of Order :

public class Order
{
  private ItemDiscountService _itemDiscountService;
  private UserService _userService;
  public Order (ItemDiscountService itemDiscountService, UserService userService)
  {
    _itemDiscountService = itemDiscountService;
    _userService = userService
  }
  Public int ID {Get; SET; }
  public List & lt; Item & gt; Items {get; SET; }
  public decimal Subtotal {get; set; }
  Public Decimal Discount {Get; SET; }
  public void AddItem (Item item)
  {
    Items.Add (item);
    CalculateSubtotalAndDiscount ();
  }
  public void CalculateSubtotalAndDiscount ()
  {
    decimal subtotal = 0;
    decimal discount = 0;
    foreach (var item in Items)
    {
      var currentCost = item.Cost * _itemDiscountService.GetDiscountFactor (item) * _userService.GetCurrentUserDiscountFactor ();
      subtotal + = currentCost;
      discount + = item.Cost - currentCost;
    }
    Subtotal = subtotal;
    Discount = discount;
  }
}

This class contains the data and the logic of their changes. He does not inherit from any particular class of third-party library or from any third-party class, and is simple enough – Plain Old CLR / Java Object

.


When the user adds something to the cart, this information is transmitted to the application server, which invokes the method AddItem in the class Order , which recalculates the value of goods and discount, changing the most state order. You want to show the user the change, and it needs to pass an updated state back to the client.

But we can not just hand over a copy of our Order , or a copy of it, because it depends on other classes (ItemDiscountService , UserService ), which in turn may depend on other classes, which may be necessary to connect to the database and & nbsp; m & nbsp;. n

.

Of course, they can be duplicated on the client, but then the client will have access to all our logic, the connection string to the database, and & nbsp; r & nbsp;.. N, which we did not want to show. Therefore, to simply pass the updated state, we can do for this special class:

public class OrderDto
{
  Public int ID {Get; SET; }
  public decimal Subtotal {get; SET; } 
Public Decimal Discount {Get; SET; }
  Public Decimal Total {Get; SET; }
}

We will be able to put in it those data that we want to transfer to the client, thereby creating Data Transfer Object . It may contain completely any attributes we need. Including those that are not in the order>Order class, for example, attribute Total .


each order has its own identifier – ID , which we use to distinguish one order from the other. While the application server’s memory may exist with ID = 1, containing 3 items, the same order can be stored in the database, with the same identifier, but containing 5 items. This may occur if we read the order status from the database and changed it in memory without saving changes to the database.

It turns out that despite the fact that some values ​​of the order in the database and order in the application server memory will differ, it will still be the same object, since their identifiers match.

In turn, the value of the cost – 100 , the identifier number – 1 , the current date, the name of the current user – Petrovich will be equal to the same values ​​only when these values ​​are completely coincided, and nothing else.

T. & nbsp; e. 100 can only be 100 , "Petrovich" can only be equal to Petrovich and & nbsp; t. & nbsp ; d. And no matter where these objects will be created. If their values ​​are completely coincided – they will be equal. Such objects are called Value Object .

In addition to the existing Value Object type Decimal or String you can create yours. In our example, we could create a type of OrderPrice and place the fields of the subtotal , Total and Discount .

public struct OrderPrice
{
  Public Decimal Subtotal;
  Public Decimal Discount;
  Public Decimal Total;
}

in C # is suitable for This ability to create significant types that are compared by the value and when assigning the entirely copied.


Update
As for the updated question (although it is really a separate big question, as Discord noted):

When we develop the application, we work with any subject area. This subject area can be expressed as a certain model and actions that change the state of this model. All this can be represented as a set of classes. Such classes contain both data (in the form of classes) and actions that are manipulated by these data (in the form of methods).

In principle, there are no restrictions on the placement of data or methods by classes. You can generally shove in one class and it will work perfectly.
The main problem is that such code will be more difficult, which means to support more. Since everything will be intertwined with each other – any changes can bring a bunch of errors, etc. Therefore, to achieve a more “cheap” code, we begin to somehow structure it, break into modules, etc.

We can decompose the data in some classes, and methods in others and this will also work and will be even more modular. But anyway can carry a number of minuses. Looking at a bunch of data may not be obvious that generally with them can occur or who can be needed. The same thing with a bunch of methods. Therefore, so that it is even more convenient to decompose the data on classes somehow grouped into them in a person. The same with the methods. Order data, user, product, etc. Can become separate classes as well as classes with appropriate methods. It will be more modular and clearer. But any approach has its pros and cons.

For example, in our online store there are different products, the logic of calculating the price of which can be quite complicated.
Imagine that there is a certain basic class Item , and many derived classes:

Public Class Item
{
 Public int ID {Get; set;}
 Public String Name {Get; Set;}
 Public Decimal BaseCost {Get; set;}
 Public Decimal Cost {Get; set;}
}
Public Class Boots: Item {...}
Public Class SHIRT: Item {...}
Public Class Pants: Item {...}

Since we have logic in separate classes, imagine that there is a class of ItemCostService , which can count the cost of goods. Then,
Due to the presence of a large number of different conditions, it may look something like this:

public class itemcostservice
{
 Public Decimal CalculateCost (Item Item)
 {
  if (Item Is Boots)
  {
   Item.Cost = ...
  }
  ELSE if (Item IS SHIRT)
  {
   Item.Cost = ...
  }
  ELSE if ....
 }
}

and such places in the program, where, depending on the specific type of product, there must be a lot of behavior.
Of course, it will all work. But as soon as we have a new type of product, or the logic of processing an existing product type will be changed to us
You have to change the code in a large number of places where there are such conditions. It is more difficult than to change everything in one place, longer and is fraught with something to forget something.

In this question, we are talking about languages, the main paradigm of which is the OOP. This means that there is a finished infrastructure that supports the basic principles of the OOP. To follow this paradigm and benefit from the finished infrastructure, we can change our class by adding the logic of calculating the cost in them by changing it as necessary in derived classes:

Public Class Item
{
 ...
 Public Virtual Void CalculateCost () {...}
}
Public Class Boots: Item
{
 Public Override Void CalculateCost () {...}
}

Each derived type itself will be able to determine the logic of its behavior. All she will be in one place, next to the data. And which of the specific methods to call will determine the infrastructure of having delivering us from this headache. In this example, this approach will be more convenient, because We have the need to create a pile of if ‘s throughout the code, which will simplify the program and make changes easier.

Well, again – it all depends on the situation. Silver bullets does not happen in various cases worth using various approaches that will be cheaper in each specific situation. A little more about the OOP and the rest can see in my article here .


Answer 2, Authority 49%

I will give my interpretation of what has been said in the article. True, I disagree that DTO and VO do not intersect.

Poco is a class that does not nail to nails to any library architecture. The programmer itself is free to choose the classes hierarchy (or the absence of it). For example, a library for working with the database will not force the “user” from the “entity” or “active record”. Ideally, the purity of the classes do not even need attributes.

This approach unleashes the hands of the programmers and allows you to build a convenient architecture to them, use already available classes to work with storia libraries, etc. However, it does not cost any problems, for example, using POCO may require magic during execution: generating inherited classes in memory, etc.

Example poco is any class that is not inherited from a certain basic class library, not cluttered with conventions and attributes, but which nonetheless can be fully used this library.

DTO is a class with data, but without logic. It is used to transfer data between application layers and between applications, for serialization and similar purposes.

Example DTO is any class that contains only fields and properties. It should not contain methods for obtaining and changing data.

VO is a class that is identified by value. If you do not resort to overload of comparison operators and other methods, then in C # class will not be VO (for classes by default, equality is a link to the same object, reference equality), and the structure will be (for the default structures, equality is Equality of all fields). In this case, the class is not limited to the availability of logic. Such classes are recommended to do unchangeable, but sometimes life causes to retreat from this rule.

Example VO is any class that implements equality through the equality of data contained in it.


Consider an example:

struct point {
  Public int x;
  Public int Y;
}

This type is POCO, as it is not inherited from non-user types. It is DTO, because it contains only data and can be used to transfer data between processes. And it is VO, because two points with equal coordinates will be equal.

class point {
  Public int x;
  Public int Y;
}

If you replace struct on Class , the status of VO will disappear, as two points with equal coordinates will be unequal. To be full to be called VO again, you will need to implement Equals , operators and comparison interfaces.

class point {
  Public int x;
  Public int Y;
  Void Move (int deltax, int deeltay) {...}
  Void iSwithin (Rect RECT) {...}
}

After adding methods, the DTO status will disappear, since the class is already promoting logic for changes and calculations.

class point: dbentity {
  [Property]
  Public int x;
  [Property]
  Public int y;
  Void Move (int deltax, int deeltay) {...}
  Void iSwithin (Rect RECT) {...}
}

But in this form it is even not POCO, because the class has increased the basic type and attributes from the third-party library.


Answer 3, Authority 16%

These are non-cycle concepts. In principle, they cannot be placed on the same plane (as done in the article on Habré).

Poco / Pojo is an approach to writing classes- entities of business logic . Like entities, Poco contains within itself and data, and logic. PART “PLAIN OLD” just indicates that inheritance from a heavy superclass from the framework is not used to create entity classes (like inheritance from EntityObject in the old Entity Framework). Those. The essence of the approach is “not harsh mega-duper-trendy megaclasses from the framework, but in the old way, stupidly old good ordinary objects.”

Poco is used only inside BL.

dto is a pattern that involves the use of individual classes for data transmission (without status, without logic, just objects with a set of properties). DTO cannot be an essence of business logic – and, accordingly, cannot be POCO.

DTO is used on the border between layers / services. To be at the same time, Poco can not – it is not a full essence. In addition, for DTO, there have never been the problem of the ubiquitous use of “new-fashioned superclasses”, from which it would be possible to return to Plain Old Objects.

Value Objects is a way of representing logically integral objects for which there is no ready standard types. For example, dates, time, money. Value Objects is not independent entities . It is “Bricks” to build entities.

Value Object used where to have. This is auxiliary type, like DateTime. And it cannot be POCO, by definition – because It is not an essence, and again, the cooking use of “new newcomers superclasses” has never been observed for ValueObjects, so it becomes “old good” they simply did not have to.


In addition to the question: now you have what is called Anemic Domain Model . By reference, Fauler describes in detail what it is bad:

This Is One of Those Anti-Patterns That’s Been Around for Quite A Long Time, Yet Seems to Be Having a Particular Spurt at the Moment.

The Fundamental Horror of this Anti-Pattern Is That It’s So Contrary to the Basic Idea of ​​Object-Oriented Design; Which is to Combine Data and Process Together.

With all the horrors painted by the Fowler, this is a completely normal approach for small simple applications – because the logic in them is not enough, and it can be expressed in the form of Transaction Script – what you now call services. Those. Each operation you just paint in the form of a script – download something, then change something, save.

Anemic has its advantages – because In essence, there is no logic – they can be safely transmitted beyond the SERVICE LAYER. Actually, so you do not see the difference between Poco and DTO – because you calmly give your Poco-BE outward, almost without harmful consequences. Those. You do not have a problem that the DTO pattern is designed to solve, and therefore you can not understand why some DTO classes are needed – because in your case they really do not need.

The difference is manifested just when leaving anemic – logic is added in essence (your Validate, for example). And the outward out of BL essence can suddenly get into the database, for example, at the moment of rendering of the view. It is this problem that is solved by the patterns DTO / Localdto – You’re just a trimmed class, without logic that you can safely transfer outside.

The use of BE is automatically limited to BL, and the use of the POCO term (as business logic encoded in conventional objects, and not in the heirs of classes from the framework) – too.


Answer 4, Authority 10%

I want to try to answer, although I don’t know whether I understand enough deeply in the subject. If anything, then correct.

Poco. I have an association that Poco is directly mapping to the database table. Although, judging by the definition, it is not necessary. By definition, just a simple class with simple fields properties and methods of type String, Int … may have logic.

Public Class Person
{
  Public String Email {Get; SET; }
  Public String Name {Get; SET; }
  Public DateTime Birthdate {Get; SET; }
  Public Override String Tostring ()
  {
    Return String.Format ("name: {0}, e-mail: {1}, Birth Date: {2}", name, email, birthdate);
  }
  // Edit! Some Other Logic
  Public Void SeTeMailTolowerCase ()
  {
    Email = email.tolower ();
  }
}

valueobject. Unit of DDD paradigm, which I do not need id, because It is non-emotional, i.e. Does not change along the way. Apparently, it may have a logic that does not prevent it from being non-emotional.

Public Class PersonValueObject
{
  Public String Email {Get; Private SET; }
  Public String Name {Get; Private SET; }
  Public DateTime Birthdate {Get; Private SET; }
  Public PersonValueObject (String Email, String Name, DateTime Birthdate)
  {
    Email = email;
    Name = Name;
    Birthdate = Birthdate;
  }
  Public Override String Tostring ()
  {
    Return String.Format ("name: {0}, e-mail: {1}, Birth Date: {2}", name, email, birthdate);
  }
  // Edit!
  Public Override Bool Equals (Object OBJ)
  {
    VAR Other = OBJ AS PERSONVALUEOBJECT;
    if (Other == NULL) RETURN FALSE;
    ELSE RETURN (
      Email == Other.Email
      & amp; & amp; Name == Other.name.
      & amp; & amp; Birthdate == Other.birthdate.
      );
  }
}

dto. to transfer data between different systems or different layers of one system. Should not have logic. Although, in some cases, why not have logic there. Only not such that the state of the object changes, and such that is to calculate some value based on the state. But for clarity, I will write without logic.

Public Class Persondto
{
  Public String Email {Get; SET; }
  Public String Name {Get; SET; }
  Public DateTime Birthdate {Get; SET; }
}

To the question, what is the difference between Poco and DTO I would answer that dto data transfer only, and Poco – simple data model.


UPD

Another question on the use of POCO. When and how much
rationally stuff logic into objects?

I do not know how in your case it is better. But I know that everything falls into place if you use DDD. I will try to say about the concept of the aggregate. It may be in this case and will not be useful because DDD has a big entry threshold.

An example of an aggregate can here .

  • Aggregate, as far as I understand, this is a logic bunch of essentialities, united in one whole, which has an ID. The unit cannot be broken, there are always correct data in it.
  • the aggregate is well listed validation and other logic. However, I heard that the validation refers to the logic of Persistance, that is, it must be implemented by repositories.
  • Properties in the assembly assembly. Changing data is carried out through the methods of the unit. Data processing is immediately performed, changing the state of the unit or the Exception call.
  • As far as I understand it, the unit sends messages when changing the status. These messages sign other aggregates to react correctly.
  • Aggregate gets from the repository. Also sent to the repository to save data. If we consider that one unit can combine data from several database tables, then the implementation of the repositories is turned out sufficiently affected. (I have not tried, however, do it with Nhibernate)
  • Presentation layer operates only with DTO.
  • Data Recording Operation occurs as follows: As part of one transaction, aggregates from repositories are obtained, the methods of aggregates are caused to change their states and aggregates are saved in the repositories.
  • Turning DTO – & GT; aggrgate and aggregate – & gt; DTO occurs with DToAssembler (and to transform DTO- & GT; AgGregate , the sequence of changing the properties of DTO would be taken into account. (Edit 🙂 Some logic can be used in the domain services caused by this Assumber. (earlier it was said that the domain services can be called by an aggregate, but somehow it is not logical to transmit services to the unit, especially if you withstand IOC)

is the theory, and in practice it is more difficult. In addition, it is only my experience that I do not have so much. There is no such thing that is just not as otherwise. I understood these moments for myself, but took them from a more experienced colleague and from the course of lectures pluralsight “DDD”. I take criticism.


Answer 5

Regarding the Value Object – I recently saw an example: https://folkprog.net/ Value-Object-Yu-Symfony-Formakh /
But there in the context of Symfony Form. As far as I understood, convenience is the storage seems to be one value, but which consists of several simple (scalar?) Values. Something reminds vector. Accordingly, the comparison logic is the same, by values ​​(unlike Entity, where by the identifier) ​​

Programmers, Start Your Engines!

Why spend time searching for the correct question and then entering your answer when you can find it in a second? That's what CompuTicket is all about! Here you'll find thousands of questions and answers from hundreds of computer languages.

Recent questions