Detailed explanation of VO, DTO, DO, PO in java

concept

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

  • DTO (Data Transfer Object): The concept of data transfer object is derived from the J2EE design pattern. The original purpose is to provide coarse-grained data entities for EJB distributed applications to reduce the number of distributed calls, thereby increasing distributed calls The performance and reduce the network load, but here, I refer to the data transmission object between the display layer and the service layer.

  • DO (Domain Object): A 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 in the data table ( Or several) corresponds to one (or several) attributes of PO.

 

model

The following is a sequence diagram to establish a simple model to describe the position of the above objects in the three-tier architecture application

  • The user makes a request (perhaps to fill in a form), and the data of the form is matched as VO in the presentation layer.

  • The presentation layer converts the VO into the DTO required by the corresponding method of the service layer and transmits it to the service layer.

  • The service layer first constructs (or reconstructs) 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 (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 transmitted in a similar way, omitted.

 

The difference between VO and DTO

You may have a question (in the projects I participated in, many programmers have the same doubts): Since DTO is the object that transmits data between the presentation layer and the service layer, why do you need a VO?

Correct! For most of the application scenarios, the attribute values ​​of DTO and VO are basically the same, and they are usually POJOs, so there is no need to do this, but don’t forget that this is an implementation-level thinking. For the design level, the concept There should still be VO and DTO, because there is an essential difference between the two, DTO represents the data that the service layer needs to receive and the data returned, and VO represents the data that the display layer needs to display.

It may be easier to understand with an example: For example, the service layer has a getUser method to return a system user, one of which is gender (gender). For the service layer, it is only defined semantically: 1-male , 2-female, 0-unspecified, and for the display layer, it may need to use "handsome guy" to represent men, "beauties" to represent women, and "secrets" to represent unspecified. Speaking of this, you may still refute it, isn't it enough to just return "handsome guys and beautiful girls" at the service level?

For most applications, this is not a problem, but imagine that if the requirements allow customers to customize the style, and different styles have different ways of expressing "gender", or the service is used by multiple clients at the same time (different portals ), and different clients have different requirements for the presentation layer, so the problem is coming. Furthermore, returning to the analysis at the design level, from the perspective of the single responsibility principle, the service layer is only responsible for the business and has nothing to do with the specific form of expression. Therefore, the DTO returned by it should not be coupled with the form of expression.

Theory belongs to theory. After all, this is still the thinking of analysis and design. Is it necessary to do this at the realization level? A one-size-fits-all approach is often not worth the gain, and I will immediately 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: at the implementation level):

  • The requirements are very clear and stable, and when the client is clear that there is only one, there is no need to distinguish between VO and DTO. At this time, VO can be retired and only one DTO can be used. Why is VO retired instead of DTO? Back to the design level, the responsibilities of the service layer should still not be coupled with the display layer. Therefore, for the previous example, you can easily understand that DTO still cannot use "handsome guy and beautiful girl" for "gender". This conversion should depend on Page script (such as JavaScript) or other mechanisms (JSTL, EL, CSS)

  • Even if the client can be customized, or there are multiple different clients, if the client can use a certain technology (script or other mechanism) to achieve the conversion, you can also retire VO

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

  • The opposite of the above scene

  • For some technical reasons, for example, when a framework (such as Flex) provides automatic conversion of POJOs to certain 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 decrease of development and maintenance efficiency caused by the design of one more VO.

  • If a "big view" appears on the page, and all the data that composes this big view needs 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 a large view at once. 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 the agreement between the two), and DO is the abstraction of various business roles in the real world, which leads to two The difference in data between users, such as UserInfo and User, for a getUser method, in essence, it should never return the user's password, so UserInfo is at least one less password data than User. In domain-driven design, as the first article in the series 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, there should not be a password attribute definition, but if there is also a createUser method, the passed UserInfo What should I do if I need to include the user's password?

At the design level, the DTO passed by the presentation layer to the service layer and the DTO returned by the service layer to the presentation layer are conceptually different, but at the implementation level, we usually rarely do this (define two UserInfo, or even more) , Because this is not necessarily very wise, 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 No matter 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 point to explain: Why not return DO directly in the service layer? This can save the DTO encoding and conversion work, the reasons are as follows:

  • 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, and there may even be a many-to-many relationship between the two.

  • DO has some data that should not be known to the display layer

  • DO has a business method. If you pass DO directly to the presentation layer, the code of the presentation layer can bypass the service layer and directly invoke operations that it should not access. This is a problem for the AOP-based mechanism that intercepts the service layer for access control. It is particularly prominent, and the business method of calling DO in the presentation layer will also make the transaction difficult to control due to transaction problems.

  • For some ORM frameworks (such as Hibernate), "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 cases). Under the circumstances is not a design worthy of respect), if it tries to obtain an unloaded associated object when the Session is closed, a runtime exception (LazyInitiliaztionException for Hibernate) will occur.

  • From a design perspective, 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 kind of cross-layer Dependence can lead to unnecessary coupling.

For DTO, there is one point that must be explained, that is, DTO should be a "flat two-dimensional object". Take an example to illustrate: If User is associated with several other entities (such as Address, Account, Region, etc.), then getUser () Does the returned UserInfo need to return all the DTOs of its associated objects?

If this is the case, it will inevitably lead to a significant increase in the amount of data transmission. For distributed applications, this design is even more unacceptable due to the transmission, serialization, and deserialization of data 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 to "flatten" a "three-dimensional" object tree into a "flat" Two-dimensional objects", the project I’m currently involved 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 it regardless of the number of things. The performance is very slow. .

 

The difference between DO and PO

In most cases, DO and PO have a one-to-one correspondence. PO is a POJO that only contains get/set methods. However, some scenarios can still reflect the essential conceptual difference between the two:

  • DO does not need to be explicitly persisted in certain scenarios. For example, the discount strategy designed by 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. The PO, but this PO has no practical significance in the business field, and it cannot correspond to any DO at all. It should be specifically stated here that not all many-to-many relationships have no business meaning. This is related to specific business scenarios. For example, the relationship between two POs will affect specific businesses, and there are multiple types of such relationships. The many-to-many relationship should also be expressed as a DO, another example: there is a many-to-many relationship between "role" and "resource", and this relationship will obviously be expressed as a DO-"authority".

  • 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 DOs with a one-to-one relationship. However, due to performance considerations (extreme cases, right as an example), in order to reduce database connection query operations, the Customer and Contacts are two The DO data is combined into one data sheet. Conversely, if a book Book has an attribute of cover cover, but this attribute is binary data of a picture, and certain query operations do not want to load the cover together, thereby reducing disk IO overhead, and assuming an ORM framework Lazy loading at the attribute level is not supported, so you need to consider separating the cover into a data table, so as to form a DO to deal with a PO situation.

  • Some attribute values ​​of PO have no meaning for DO. These attribute values ​​may be data that exists to solve certain persistence strategies. For example, in order to achieve "optimistic locking", PO has a version attribute, and this version is for DO It has no business meaning, and it should not exist in DO. In the same way, there may also be attributes in DO that do not need to be persisted.

 

Application of DO and PO

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

  • For attributes that do not need to be persisted in DO, they need to be explicitly declared through ORM. For example, in JPA, you can use the @Transient declaration.

  • For attributes that exist in PO for a certain persistence strategy, such as version, because DO and PO are merged, they must be declared in DO, but because this attribute has no business meaning for DO, the attribute needs to be hidden from the outside. , The most common approach is to privatize the get/set method of the property, or even not provide the get/set method, but for Hibernate, this requires special attention, because Hibernate reads data from the database and converts it to DO. The reflection mechanism first calls DO's empty parameter constructor to construct a DO instance, and then uses the JavaBean specification to reflect the set method to set a value for each attribute. If the set method is not explicitly declared or the set method is set to private, it will cause Hibernate can't initialize DO, resulting in a runtime exception. A feasible approach is to set the set method of the property 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 Hibnate's related information.

So far, I believe everyone has a clearer understanding of the concepts, differences and practical applications of VO, DTO, DO, and PO. Through the above detailed analysis, we can also summarize a principle:

The analysis and design level and the realization level are completely separate levels. Even if the realization level can combine two completely independent concepts into one through some technical means, at the analysis and design level, we still (at least in our minds) need to Conceptually independent things are clearly distinguished. This principle is very important for good analysis and design (the more advanced the tools, the more numb we are).

Guess you like

Origin blog.csdn.net/qq_39809613/article/details/107018927