Analysis of the concepts, differences and uses of VO, DTO, DO, PO and MapStruct - Java bean mapping

Introduction: ** PO: persistent object The most vivid understanding of a persistent object is that a PO is a record in the database. The advantage is that a record can be treated as an object, which can be easily converted to other objects. BO: business object The main function of the business object is to encapsulate the business logic into an object.

PO:
persistent object persistent object

The most vivid understanding is that a PO is a record in the database.
The advantage is that a record can be treated as an object, which can be easily converted to other objects.


BO:
business object business object

The main function is to encapsulate business logic as an object. This object can contain one or more other objects.
For example, a resume, with educational experience, work experience, social relations and so on.
We can map education experience to a PO, work experience to a PO, and social relationship to a PO.
Create a BO object corresponding to the resume to process the resume, and each BO contains these POs .
When dealing with business logic in this way, we can deal with BO.


VO:
value object value object
ViewObject presentation layer object

It mainly corresponds to the data object displayed on the interface . For a WEB page, or an interface of SWT or SWING, use a VO object to correspond to the value of the entire interface.


DTO:
Data Transfer Object data transfer object
is mainly used for remote calls and other places that require a large number of transfer objects.
For example, if we have a table with 100 fields, then the corresponding PO has 100 attributes.
But we only need to display 10 fields on the interface, and
the client uses WEB service to obtain data. It is not necessary to pass the entire PO object to the client.
At this time, we can use DTO with only these 10 attributes to transfer the result to the client. This will not expose the table structure of the server. After reaching the client, if this object is used to display the corresponding interface, then its identity will be changed to VO at this time


POJO:
plain ordinary java object Simple java object
I personally feel that POJO is the most common and most variable object, an intermediate object, and the object we most often deal with.

After a POJO is persisted, PO
directly uses it to transfer, and during the transfer process, DTO is
directly used to correspond to the presentation layer, which is VO

POJO, PO, DTO, and VO are all names in the processing flow, not that PO corresponds to a POJO, DTO corresponds to a POJO, and VO corresponds to a POJO. In some cases,
PO , DTO, and VO refer to the same POJO


DAO:
data access object data access object
This is the most familiar to everyone, and it is the most different from the above O's. There is basically no possibility or necessity of mutual conversion. It is
mainly used to encapsulate access to the database. Through it, POJO can be persisted as PO, and VO and DTO can be assembled with PO

To sum up, I think what an object is depends on the specific environment. In different layers and different application occasions, the identity of the object is different, and the transformation of the identity of the object is also very natural. Just like you are a husband to your wife and a child to your parents. The original intention of designing these concepts is not to bluff people, but to better understand and deal with various logics, so that everyone can better deal with problems in an object-oriented way.

Don't fall into over-design, you don't have to design for the sake of design, you must distinguish each object in the code. In a word, technology serves applications.

Since different projects and developers have different naming habits, here I first give a brief description of the above concepts. The name is just an identifier, and we focus on its concept:

concept:

VO **(View Object****): **View object, used for the display layer, its function is to encapsulate all the data of a specified page (or component).

DTO ** (Data Transfer Object****): **Data Transfer Object, this concept comes from the J2EE design pattern, the original purpose is to provide coarse-grained data entities for EJB distributed applications to reduce distributed calls The number of times, thereby improving the performance of distributed calls and reducing network load, but here, I generally refer to the data transfer objects used between the presentation layer and the service layer.

DO ** (Domain Object****): **Domain Object is a tangible or intangible business entity abstracted from the real world.

PO ** (Persistent Object****): **Persistent object, which forms a one-to-one mapping relationship with the data structure of the persistence layer (usually a relational database). If the persistence layer is a relational database, then, Each field (or several) in the data table corresponds to one (or several) attributes of PO.

  • The user makes a request (maybe filling out a form), and the data in the form is matched as VO at the presentation layer.
  • The display layer converts the VO into the DTO required by the corresponding method of the service layer and sends it to the service layer.
  • The service layer first constructs (or rebuilds) a DO based on the data of the DTO, and calls the business method of the DO to complete the specific business.
  • The service layer converts the DO into the PO corresponding to the persistence layer (the ORM tool can be used or not), calls the persistence method of the persistence layer, passes the PO to it, and completes the persistence operation.
  • For a reverse operation, such as reading data, it is also converted and passed in a similar way, omitted.

The difference between VO and DTO

You may have a question (in the project I participated in, many programmers also have the same doubt): Since DTO is the object for transferring data between the presentation layer and the service layer, why do we need a VO? right! For most application scenarios, the attribute values ​​of DTO and VO are basically the same, and they are usually POJO, so there is no need to do more. But don’t forget that this is the thinking at the implementation level. For the design level, there should still be VO and DTO conceptually, because there is an essential difference between the two. DTO represents the data that the service layer needs to receive and return data, and VO represents the display The data the layer needs to display.

It may be easier to understand with an example: For example, the service layer has a getUser method that returns a system user, and one of the attributes is gender (gender). For the service layer, it is only semantically defined: 1-Male , 2-female, 0-unspecified, and for the presentation layer, it may need to use "handsome" for male, "beautiful" for female, and "secret" for unspecified. Speaking of which, you may still refute, wouldn't it be enough to just return "handsome guys and beautiful women" at the service layer? For most applications, this is not a problem, but imagine if the requirements allow customers to customize the style, and different styles have different expressions for "gender", or this service is used by multiple clients at the same time (different portals ), and different clients have different requirements for the presentation layer, then the problem arises. Furthermore, back to the analysis at the design level, from the perspective of the principle of single responsibility, the service layer is only responsible for the business and has nothing to do with the specific form of expression. Therefore, the DTO it returns should not be coupled with the form of expression.

Theory belongs to the theory. After all, this is still thinking at the analysis and design level. Is it necessary to do this at the implementation level? A one-size-fits-all approach is often not worth the candle. Next, I will analyze how to make the right choice in the application.

Application of VO and DTO

The above is just a simple example to illustrate the conceptual difference between VO and DTO, this section will tell you how to make the right choice in the application.

In the following scenarios, we can consider combining VO and DTO into one (note: it is the implementation level):

  • When the requirements are very clear and stable, and there is only one client, there is no need to distinguish VO from DTO. At this time, VO can be retired, and only one DTO can be used. Why is VO retired instead of DTO? Going back to the design level, the responsibilities of the service layer should still not be coupled with the presentation layer. Therefore, for the previous example, you can easily understand that DTO still cannot use "handsome men and beautiful women" for "gender". This conversion should depend on Scripting (such as JavaScript) or other mechanisms (JSTL, EL, CSS) of the page.
  • Even if the client can be customized, or there are multiple different clients, if the client can use some technology (script or other mechanism) to realize the conversion, the VO can also be retired.

The following scenarios need to give priority to the coexistence of VO and DTO:

  • The opposite of the above scenario
  • For some technical reasons, for example, when a framework (such as Flex) provides automatic conversion of POJOs to some fields in the UI, you can consider defining VO at the implementation level. This trade-off depends entirely on the automatic conversion capabilities of the framework. The comparison between the improvement of development and maintenance efficiency and the reduction of development and maintenance efficiency brought about by the design of one more VO.
  • If there is a "big view" on the page, and all the data that makes up this big view need to call multiple services and return multiple DTOs to assemble (of course, this can also be replaced by the service layer providing a DTO that returns one big view at a time. But whether it is appropriate to provide such a method at the service layer needs to be weighed at the design level).

The difference between DTO and DO

The first is the conceptual difference, DTO is the data transmission object between the presentation layer and the service layer (it can be considered as an agreement between the two), and DO is the abstraction of various business roles in the real world, which leads to two or the difference in data, such as UserInfo and User (for the naming rules of DTO and DO, please refer to a previous blog post by the author ), for a getUser method, it should never return the user's password in essence, so UserInfo At least one password less than User data. In domain-driven design, as the first series of articles said, DO is not a simple POJO, it has domain business logic.

Application of DTO and DO

From the example in the previous section, careful readers may find the problem: since the UserInfo returned by the getUser method should not contain password, then there should be no attribute definition of password, but if there is a createUser method at the same time, the incoming UserInfo Need to include the user's password, what should I do? At the design level, the DTO passed from the presentation layer to the service layer is conceptually different from the DTO returned from the service layer to the presentation layer, but at the implementation level, we usually rarely do this (define two UserInfo, or even more) , because it is not very wise to do so, we can design a fully compatible DTO, when the service layer receives data, the attributes that should not be set by the display layer (such as the total price of the order should be determined by its unit price, quantity, discount etc.), regardless of whether the display layer is set or not, the service layer will ignore it, and when the service layer returns data, the corresponding attributes will not be set for data that should not be returned (such as user passwords).

For DO, there is one more thing to explain: why not return DO directly in the service layer? This saves the work of coding and converting the DTOs for the following reasons:

  • The essential difference between the two may lead to a one-to-one correspondence with each other, a DTO may correspond to multiple DOs, and vice versa, or even a many-to-many relationship between the two.
  • DO has some data that should not be known to the presentation layer
  • DO has business methods. If DO is directly passed to the presentation layer, the code of the presentation layer can bypass the service layer and directly call operations that it should not access. For the access control mechanism based on AOP interception service layer, this problem Especially prominent, and the business method of calling DO in the presentation layer will also make the transaction difficult to control due to the problem of the transaction.
  • For some ORM frameworks (such as Hibernate), the "lazy loading" technology is usually used. If DO is directly exposed to the presentation layer, in most cases, the presentation layer is not within the scope of the transaction (Open session in view is in most case is not a worthy design), if it tries to get an unloaded associated object while the Session is closed, a runtime exception will occur (for Hibernate, it is LazyInitiliaztionException).
  • From the design level, the presentation layer depends on the service layer, and the service layer depends on the domain layer. If DO is exposed, the presentation layer will directly depend on the domain layer. Although this is still a one-way dependency, this cross-layer Dependencies lead to unnecessary coupling.

For DTO, there is also a point that must be explained, that is, DTO should be a "flat two-dimensional object". Let me give an example to illustrate: if User will be associated with several other entities (such as Address, Account, Region, etc.), then getUser Does the UserInfo returned by () need to return all the DTOs of its associated objects? If this is the case, it will inevitably lead to a large increase in the amount of data transmission. For distributed applications, this design is even more unacceptable because it involves data transmission, serialization and deserialization on the network. If getUser needs to return an AccountId, AccountName, RegionId, and RegionName in addition to the basic information of the User, then please define these attributes in UserInfo and "flatten" a "three-dimensional" object tree into a "flat" 2D object". The project that the author is currently participating in is a distributed system. The system converts all associated objects of an object into a DTO object tree of the same structure and returns them regardless of the situation, resulting in very slow performance.

The difference between DO and PO

DO and PO are in one-to-one correspondence in most cases. PO is a POJO with only get/set methods, but some scenarios can still reflect the essential difference in concept between the two:

  • DO does not need to be explicitly persisted in some scenarios. For example, the product discount strategy designed using the strategy pattern will derive the interface of the discount strategy and different discount strategy implementation classes. These discount strategy implementation classes can be regarded as DO, but they It only resides in static memory and does not need to be persisted to the persistence layer. Therefore, there is no corresponding PO for this type of DO.
  • In the same way, in some scenarios, PO does not have a corresponding DO. For example, there is a many-to-many relationship between Teacher and Student. In a relational database, this relationship needs to be represented as an intermediate table, which corresponds to a TeacherAndStudentPO PO, but this PO has no practical significance in the business field, and it cannot correspond to any DO at all. It is specially stated here that not all many-to-many relationships have no business meaning, which is related to specific business scenarios, for example: the relationship between two POs will affect specific businesses, and there are many types of such relationships, then this The many-to-many relationship should also be expressed as a DO, another example: there is a many-to-many relationship between "roles" and "resources", and this relationship will obviously be expressed as a DO-"permission".
  • In some cases, for a certain persistence strategy or performance considerations, one PO may correspond to multiple DOs, and vice versa. For example, the customer Customer has its contact information Contacts, here are two one-to-one relationship DOs, but it may be for performance considerations (extreme cases, right as an example), in order to reduce the connection query operation of the database, the Customer and Contacts two DO data is merged into one data table. Conversely, if a Book has an attribute that is the cover cover, but this attribute is the binary data of a picture, and some query operations do not want to load the cover together, so as to reduce the disk IO overhead, and assume the ORM framework If lazy loading at the attribute level is not supported, then it is necessary to consider separating the cover into a data table, so that a DO corresponds to multiple POs.
  • Some attribute values ​​of PO have no meaning for DO. These attribute values ​​may be data that exist to solve certain persistence strategies. For example, in order to implement "optimistic locking", PO has a version attribute, which is for DO There is no business sense, it should not exist in DO. Similarly, there may also be attributes in DO that do not need to be persisted.

Application of DO and PO

Since the ORM framework is very powerful and popular, and JavaEE has also introduced the JPA specification, the current business application development basically does not need to distinguish between DO and PO. PO can be hidden in DO through JPA and Hibernate Annotations/hbm. Even so, there are some issues we must also pay attention to:

  • For properties that do not need to be persisted in DO, they need to be explicitly declared through ORM. For example, in JPA, @Transient declaration can be used.
  • For attributes that exist in PO for a certain persistence strategy, such as version, since DO and PO are merged, they must be declared in DO, but since this attribute has no business significance for DO, it is necessary to hide this attribute from the outside , the most common way is to privatize the get/set method of the attribute, or even not provide a get/set method. But for Hibernate, this requires special attention, because when Hibernate reads data from the database and converts it into DO, it uses the reflection mechanism to first call the empty parameter constructor of DO to construct the DO instance, and then uses the JavaBean specification to reflect the set method. To set a value for each attribute, if you do not explicitly declare the set method, or set the set method to private, Hibernate will not be able to initialize DO, resulting in a runtime exception. The feasible way is to set the attribute's set method to protected.
  • For scenarios where one DO corresponds to multiple POs, or one PO corresponds to multiple DOs, and attribute-level lazy loading, Hibernate provides good support. Please refer to the relevant information of Hibnate.

So far, I believe that everyone has a clear understanding of the concepts, differences and practical applications of VO, DTO, DO, and PO. Through the above detailed analysis, we can also conclude a principle: the analysis design level and the implementation level are completely independent levels, even if the implementation level can combine two completely independent concepts into one through some technical means, in the At the level of analysis and design, we still (at least in our minds) need to clearly distinguish conceptually independent things. This principle is very important for good analysis and design (the more advanced the tools, the more numb we tend to be).

Guess you like

Origin blog.csdn.net/qq_36538368/article/details/128216524