Transferred from: http://www.uml.org.cn/mxdx/200907132.asp
In the current developer community, there is a widespread prevalence of an architectural pattern known as the anemic domain model by Martin Fowler. The model has been blamed for the criticism of the master. This model has a fatal flaw: it often behaves poorly in dealing with complex areas. There are many indications that when we face complex applications, it is best to turn to a framework based on a rich domain model.
While the rich domain model has obvious benefits, it also poses challenges for practice, both for technical reasons and for design methods. For the construction of technology, such as annotation, aspect and Di and other complex technologies, the use of the final can be clearly mastered, but in the design method, often due to different practices and difficult to achieve consensus.
The purpose of this paper is simply to provide a method for transforming the anemic domain model into a rich domain model, which can be used for peer reference with the same needs.
1. Prerequisites and Limitations
Regardless of which domain model is used, support for some tools is often required, including the IOC container and the O/R mapping tool. Due to the author's experience, when referring to these tools, it only means spring and hibernate in the Java world.
For a description of the anemia domain model, please refer to:
Http://www.martinfowler.com/bliki/AnemicDomainModel.html
For best practices in the anemic domain model, please refer to:
Https://appfuse.dev.java.net
The most authoritative guide to enriching the domain model is available at:
http://www.domaindrivendesign.org
Because of the different contexts, different hierarchical patterns of terminology have different meanings, but the tasks they want to achieve can be separated, and these tasks have not caused extensive semantic confusion at present. To better compare the two architectural patterns mentioned in this article, define the tasks they want to accomplish as follows:
Task |
Describe |
Performance logic |
Receives a request from outside the system, proxies the request to another module, and renders the returned processing result in some way to the requestor. |
Application logic |
is the implementation of the appearance of the use case, which coordinates the actual implementation of the use case to complete an application-related function. |
Domain logic |
Model the most essential content of the problem domain to realize the function of user's core value. |
Persistence logic |
interacts with the external storage of the data. |
Basic services |
More technology-centric, providing basic support for each module of the software system. |
2. Anemia Domain Model Framework
2.1. Layered mode
They also have different styles, even if they are labeled with anemic models. The following is a more typical one:
Layer |
Task |
Object |
Description |
Presentation |
Display logic |
Model objects |
Models. The Entity/value object in the domain layer can also be used as a standalone object. |
View |
View |
Controller |
Controller. A response to a user request is obtained through a mechanism. |
Domain layer |
Mixed application logic in domain logic |
Service |
Service. Process domain logic and application logic at the same time |
Entity |
Entities. Static view of the domain model |
Data source layer |
Persist logic |
DAO object |
is implemented in many ways, such as JDBC, Hibernate, IBATIS, JPA, EJB CMP |
Infrastructure layer |
Basic services |
|
|
2.2. Sample Code
Now suppose there is an online shopping site where we want to browse the product list and then select an item of interest, and we need to see the product details.
1) The page makes a request
The following is a possible JSF code fragment:
<f:param value= "#{product.id}" Name= "ProductID" ></f:param> |
2) Assign to Controller
Suppose the request is dispatched to the controller yourpackage.action.ProductAction:
Package yourpackage.action; ...... public class Productaction extends Baseaction { Through the service of dependency injection Private Productservice Productservice; The Realm object as a model object Private product product; Private Integer ID; Responding to events that view product information Public String edit () { Product = productservice.getproduct (ID); return "Product"; JSF resolves it to a product.xhtml view } } |
3) service at the domain level
Typically there is a service interface Productservice, then the implementation of the interface Productserviceimpl:
Package yourpackage.service; ...... public class Productserviceimpl extends Baseservice implements Productservice { By relying on the injected DAO object Private Productdao Productdao; Domain logical approach to obtaining product information Public Product getproduct (Integer ID) { return productdao.getproduct (ID); } } |
4) Entity of the domain layer
The following is a JPA-style entity that is used to host data only, without domain behavior (which is why anemia is called).
Package Yourpackage.model; ...... @Entity public class Product { @Id @GeneratedValue (Strategy=generationtype.auto) @Column (name= "Id") Public Long getId () { return ID; } @Column (name= "name", Length=30, Nullable=false) Public String GetName () { return name; } } |
5) DAO Object
There is also a need for an interface, which implements the class if it is JPA:
Package Yourpackage.dao; ...... public class PRODUCTDAOJPA extends BASEDAOJPA implements Productdao { Public Product getproduct (Integer ID) { Return (Product) getjpatemplate (). Find (Product.class, id);; } ...... } |
2.3. Analysis
Advantages:
* Get the most basic benefits of layering.
* Easy to understand, fast to master: No more complex techniques are used, and there are a wealth of sample resources.
* With extensive tool support, it is very easy to benefit from the Spring/hibernate type of framework.
* Suitable for the simple model, the CRUD operation is the main field.
Disadvantages:
* The area of the model is lacking in expressive capacity.
* Code responsibility Assignment is unreasonable.
3. Enrich the domain model
3.1 Tiered Mode
The typical DDD style layering pattern is as follows:
Layer |
Task |
Object |
Describe |
Presentation Layer |
Performance logic |
Model objects |
The Entity/value object in the domain layer can also be used as a standalone object. |
View |
|
Controller |
|
Application Layer |
Application logic |
Service |
Modeling the use case |
Domain Layer |
Domain logic |
Service |
Modeling domain Operations |
Entity |
Model domain concepts and can be persisted |
Value Object |
Value Object. Modeling Domain Concepts |
Storage Library |
Repository. Isolation persistence |
Basic facilities |
Persistent logic and basic services |
Data mapping |
Persistent operations are typically encapsulated in DAO mode |
Basic services |
|
In practice, I personally prefer to separate the data mapping from the infrastructure layer, which will have a clearer hierarchy.
Regardless of the domain model, there has been controversy over whether to pass domain objects to the presentation layer as model data. Making the right design decisions requires a balance of flexibility and rigor. There are a number of technical methods that enable domain objects to be protected as DTO objects, as can be found in the following article, "Protecting the domain Model":
Http://api.blogs.com/the_catch_blog/2005/05/protecting_the_.html
These practices have partly compensated for the negative impact of direct-transfer domain objects.
3.2 What's different.
From the table above we can find that the things to do are still those things, but part of the responsibility is reassigned. In relation to the anemic domain model, in the new layering mode:
* Unchanged is the presentation layer;
* The data source layer is merged and is now part of the infrastructure;
* Added is the application layer;
* The domain layer is being re-organized and its responsibilities are assigned to the appropriate objects: Entities, value objects, services, and repositories.
The biggest changes here are three:
1) The application logic is separated from the domain logic to form a new application layer. The interface of the layer is designed according to the use case, so the granularity is large, and the layer reflects the tasks implemented by the system and can reflect the workflow if necessary.
2) The domain layer reflects only the most central part of the domain logic and is therefore the most complex (if the domain is more complex than the technical complexity). The entity not only holds the data, but also has the rich behavior; The service is a field-related operation (this differs from the application-tier service and the service at the infrastructure level), and the connection to the data technology is isolated through the repository.
3) The domain layer can independently access services and resources from other tiers. This is a controversial topic and is technically challenging, as explained in the example code below.
4. Refactoring to a rich domain model architecture
4.1. Technical Solutions
For simplicity, the aliases of A and B are used to represent the "anemic domain Model" and the "Enrich domain Model", respectively, using namespaces to represent layers in the model, such as B:: The application layer represents the application layer of the rich domain model.
With the previous comparison, it is easy to get the following conversion scenario:
1) Keep the performance layer unchanged
2) separate out the application layer. From a:: Domain layer Remove application logic Form B:: Application layer.
3) Refactor a purely domain layer. The domain logical part of a:: Domain layer is decomposed:
# Refactor The conceptual logic to the B:: Domain layer. Entity and B:: Domain layer. Value object;
# Refactor the operational logic to the B:: domain layer. Services;
# The data source access is abstracted as a repository interface, and the implementation of the repository is injected by the IOC container.
4) Reconstruct the data access object so that it implements the repository interface of the domain layer.
5) The infrastructure layer remains the same.
Do not explain more, the following code to explain.
4.2. Sample Code
Or the previous online shopping site, but this time uses a use case that slightly reflects the domain logic: list other products related to the current product.
1) The page makes a request
The following is a possible JSF code snippet:
Then, you need to specify the following in the JVM load parameter:
-javaagent: <path-to-ajlibs>/aspectjweaver.jar</path-to-ajlibs> |
Now it's time to say it's done.
5) DAO Object
The interface that DAO needs to implement now becomes the productrepository of the domain layer:
Package Yourpackage.dao; Import Yourpackage.domain; ...... public class PRODUCTDAOJPA extends BASEDAOJPA implements Productrepository { Public Product getproduct (Integer ID) { Return (Product) getjpatemplate (). Find (Product.class, id);; } Public Product getrelatedproduct (Integer ID) { Here is the specific implementation code } } |
5. Conclusion
To build a purely domain model, it is often necessary to use external services directly in the domain object, such as database access, external resources, or other necessary services. Without the support of strong annotation, AOP and Di technology, these external services or resources are difficult to inject into the domain object, thus creating the design style of the anemia model.
In particular, for spring users, the resolution of the issue has become easier after release of version 2.0. Using spring's integrated ASPECTJ implementations to inject dependency into domain objects enables domain objects to express richer logic and thus transition to rich domain models. After this key problem is solved, the remaining problems will be solved.