More formally, a domain model is a blueprint of the relationships between the various entities of the problem domain and sketches out other important details, such as the following:
Objects that belong to the domain
Behaviors that those objects demonstrate in interacting among themselves
The language that the domain speaks
The context within which the model operates
With a modular system, each component is self-contained in functionality and interacts with other components only through explicitly defined contracts. With this arrangement, you can manage complexity better than with a monolithic system.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/** * Lifecycle of a domain object */ traitDomain{
typeE typeH typeP
// Every object (entity or value object) in any model must have a definite lifecycle pattern // thus events will be using repeatedly in various contexts of domain modeling. defcreation: E defbehaviors: H defpersistence: P }
1 2 3 4 5 6 7 8 9 10 11 12
/** * Bank is also an entity, * an entity can contain other entities or value objects */ traitBank{
// attributes of bank defdebit: Unit// 贷款 defissue: Unit// 转账
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/** * In fact, [[Account]] is a aggregate root */ traitAccount{ // Basic contract of an Account aggregate defno: String defname: String defbank: Bank// Reference to another entity defaddress: Address// Address is a value object. defdateOfOpening: Date defdateOfClose: Option[Date] // .. }
// Factory Pattern be used objectAccount{ // define apply method }
In reality, when you design aggregates, you may find that for performance and consistency of operations you have to optimize away many composing entities from the aggregate and have only the root along with the value objects. For example, you may choose to keep a bank ID instead of the entire Bank entity as part of the Account aggregate.
A domain model is a blueprint of the relationships between the various entities of the problem domain and sketches out other important details, such as following:
Objects that belong to the domain
Behaviors that those objects demonstrate in interacting among themselves
/** * Repository doesn't have any knowledge of the nature of the underlying persistent store. */ traitAccountRepository{ defquery(accountNo: String): Option[Account] defquery(criteria: Criteria[Account]): Seq[Account] defwrite(accounts: Seq[Account]): Boolean defdelete(account: Account): Boolean }
supply a bunch of arguments to the factory and get back an aggregate(such as Account).
use the aggregate as your contract through all behaviors that you implement through services.
use the aggregate to persist the entity in the repository
/** * [[AccountServiceImpl]] respect the qualities of understandability * 1. The function body doesn't contain any irrelevant details. It just encapsulates the domain logic * 2. The implementation used terms from the domain of banking, so business domain doesn't know anything about * the underlying implementation platform, it is reference transparent. * 3. The implementation narrates use method composing and monadic and takes care of any exceptions in the sequence of execution. */ traitAccountServiceImplextendsAccountService{