"DDD" field-driven design practice--application layer Implementation

Source: Internet
Author: User

This article is the second part of the implementation of the DDD framework, mainly introduces the realization of the application layer of DDD, and explains the service and assemble responsibilities and implementation in detail. A github address is attached at the end of this article. Compared to the shipping system example in the original book of domain-driven design, the business scenario for social service systems is more familiar to everyone and is believed to be better understood. This article is one of the "DDD" series of articles, others can be consulted: implementing Business systems using domain-driven design ideas

Application Layer

In the DDD design idea, the application layer is responsible for assembling the various components of the domain layer and the infrastructure layer of the public components, to complete the specific business services. The application layer can be understood to glue the various components together, allowing fragmented components to be combined to provide a complete business service. In a complex business scenario, a business case typically requires multiple domain entities to be involved, so the glue utility of the application comes in handy.

Application layer mainly by: service, assembler composition, the following respectively to explain it.

Serviceservice is a component binder

The service here is different from the domain service of the tier, which is the application services. It is a component binder that combines the various components of the domain layer with the persistence components of the infrastructure layer, the message components, and so on, completing the specific business logic and providing a complete business service.

Through continuous practice, we find that: when the business service is realized through DDD, one of the criteria for verifying the quality of the business model is that there is no if/else in the--service method. If there is a if/else, either the system use case is coupled, or the business model is not friendly, causing some business logic to leak to the service.

In general, a business case will correspond to a service method at the service layer, thus ensuring the independence of this implementation. Take the "POST" module in the community service, we have the following obvious case: Post (posting), delete (deletepost), query the Post details (querypostdetail), these case in the service layer corresponds to a separate business method.

Thinking

For a more complex case: Query the list of posts, you may need to filter posts according to different tags, or query different types of posts, or query hot posts, this time should be implemented with a service method? Or is it multiple?

Consider this problem, mainly from these two aspects: domain consistency, data storage consistency; If two consistency is met, then we can do it in a business method, or we will do it in a separate business method.

For example: query posts and query all posts list based on the Post Operations tab The two case we can implement in a service method, because the previous case only adds a filter on the basis of the latter case, which can be completely handed to the DAO layer's SQL Where conditions are disposed of, besides, domain and repository are exactly the same;

The case of "query hot posts" cannot share a service method with the two case above, because the data source of the hot post list is not in the database, but rather exists in the cache, so there is a big difference in the fetch logic of repository. If a service method is shared, it is not friendly to have a If/else decision on the service layer.

Class diagram

code example
1 @Service2  Public classPostserviceimplImplementsPostservice {3     4 @Autowired5     Privateipostrepository postrepository;6     7 @Autowired8     PrivatePostassembler Postassembler;9     Ten  One  A      PublicPostingrespbody Posting (requestdto<postingreqbody> requestdto)throwsbusinessexception { -Postingreqbody Postingreqbody =requestdto.getbody (); -         /** the *note: The request parameter check is given to validation, there is no need to verify that the UserID and PostID are empty -          */ -String userId =Postingreqbody.getuserid (); -String title =postingreqbody.gettitle (); +String sourcecontent =postingreqbody.getsourcecontent (); -          +         LongUseridinlong =long.valueof (userId); A          at         /** - * Assemble domain model entity - * Note: The postauthor here does not need to be overloaded from the repository because: the deletepost scene requires the user to log in before the operation, - * Before entering the service, the user identity authentication has been completed at the controller layer, so the UserID arriving here must be a legitimate user -          */ -Postauthor Postauthor =NewPostauthor (useridinlong); inPost post =postauthor.posting (title, sourcecontent); -          to         /** + * Note: Use repository to write model entity to storage -          */ the Postrepository.save (POST); *          $         /**Panax Notoginseng * Note: Use Postassembler to assemble the post model into a DTO return.  -          */ the         returnpostassembler.assemblepostingrespbody (POST); +     } A      the  +      PublicDeletepostrespbody Delete (requestdto<deletepostreqbody> requestdto)throwsbusinessexception { -Deletepostreqbody Deletepostreqbody =requestdto.getbody (); $          $         /** - *note: The request parameter check is given to validation, there is no need to verify that the UserID and PostID are empty -          */ theString userId =Deletepostreqbody.getuserid (); -String PostID =Deletepostreqbody.getpostid ();Wuyi          the         LongUseridinlong =long.valueof (userId); -         LongPostidinlong =long.valueof (PostID); Wu          -         /** About * Assemble domain model entity $ * Note: The postauthor here does not need to be overloaded from the repository because: the deletepost scene requires the user to log in before the operation, - * Before entering the service, the user identity authentication has been completed at the controller layer, so the UserID arriving here must be a legitimate user -          */ -Postauthor Postauthor =NewPostauthor (useridinlong); A         /** + * Overloaded domain model entity from Repository the * To determine if the PostID really has a post -          */ $Post post =postrepository.query (postidinlong); the          the postauthor.deletepost (POST); the          the Postrepository.delete (POST);  -          in         return NULL; the     } the  About  the @Override the      PublicQuerypostdetailrespbody Querypostdetail (requestdto<querypostdetailreqbody>requestdto) the             throwsbusinessexception { +Querypostdetailreqbody Querypostdetailreqbody =requestdto.getbody (); -          theString Readerid =Querypostdetailreqbody.getreaderid ();BayiString PostID =Querypostdetailreqbody.getpostid (); the          the         LongReaderidinlong =long.valueof (Readerid); -         LongPostidinlong =long.valueof (PostID); -          the         //TODO may have some permission checks, such as determining whether the reader has permission to view author posts, and so on. There is no discussion here for the moment.  thePostreader Postreader =NewPostreader (readeridinlong); the          thePost post =postrepository.query (postidinlong); -          the         /** the * Note: Use Postassembler to assemble the model of the domain layer into a DTO, assembly process: the * 1, the completion of type conversion, data format;94 * 2. Combine multiple model into a DTO and return it.  the          */ the         returnpostassembler.assemblequerypostdetailrespbody (POST); the     }    98  About}
AssemblerAssembler is the assembler

Assembler is the assembler, responsible for completing the domain model object to the DTO conversion, the assembly responsibilities include:

    1. Complete type conversion, data formatting, such as log formatting, State enum to the front-end to recognize the string;
    2. Assemble multiple domain domain objects into a desired DTO object, such as querying a list of posts, getting the details of a post from a post (post) domain object, and getting the user's social Information (nickname, profile, Avatar, etc.) from the users domain object;
    3. Crop and assemble domain domain object properties as DTOs; In some scenarios, you may not need properties for all domain domain objects, such as the password property of the user domain object, which is a privacy-related property, and is not required to be returned in the query user information case, and needs to be cropped out.
Sample code
1 /**2 * The assembler of the Post module, complete the domain model object to the DTO conversion, assembly responsibilities include:3 * 1, the completion of type conversion, data formatting, such as the log format, state enum to the front-end to recognize the string;4 * 2. Combine multiple model into a DTO and return it. 5 * TODO: Not very good place each assemble method needs to determine whether the argument object is empty first. 6  * @authorDaoqidelv7 * @createdate September 24, 20178  */9 @ComponentTen  Public classPostassembler { One      A     Private Final StaticString Posting_time_string_date_format = "Yyyy-mm-dd hh:mm:ss"; -      - @Autowired the     PrivateApplicationutil Applicationutil; -      -      Publicpostingrespbody Assemblepostingrespbody (post post) { -         if(Post = =NULL) { +             return NULL; -         } +Postingrespbody Postingrespbody =Newpostingrespbody (); A Postingrespbody.setpostid (string.valueof (Post.getid ())); at         returnPostingrespbody; -     } -      -      Publicquerypostdetailrespbody Assemblequerypostdetailrespbody (post post) { -         /** - * Note: Determines if the entry post is null in          */ -         if(Post = =NULL) { to             return NULL; +         } -Querypostdetailrespbody Querypostdetailrespbody =Newquerypostdetailrespbody (); theQuerypostdetailrespbody.setauthorid (String.valueof (Post.getauthorid ()));//Completing type Conversions *Querypostdetailrespbody.setpostid (String.valueof (Post.getid ()));//Completing type Conversions $ Querypostdetailrespbody.setpostingtime (Panax NotoginsengApplicationutil.converttimestamptostring (Post.getpostingtime (), Posting_time_string_date_format));//Finish date Formatting - querypostdetailrespbody.setsourcecontent (Post.getsourcecontent ()); the Querypostdetailrespbody.settitle (Post.gettitle ()); +         returnQuerypostdetailrespbody; A     } the  +}

Thinking

In the above code implementation, each Assemble method needs to check whether the parameter object is empty, in practice, it is easy to omit this key point, did not think of a good solution.

Class diagram

Demo

This demo code has been uploaded to GitHub and is welcome to download and discuss it, but refuses to be used for any commercial purpose.

GitHub Address: Https://github.com/daoqidelv/community-ddd-demo/tree/master

Branch:master

"DDD" field-driven design practice--application layer Implementation

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.