Implementation
This section describes the implementation of the project. It will focus on particular aspects of the project.
Package Structure
The project is divided into multiple modules, the following figure shows the package structure and the code dependencies between the modules.
DDD Abstractions
The project is based on the principles of Domain-Driven Design (DDD). We have defined the following abstractions to model the tactical patterns of DDD:
Entity Id
open class EntityId<Id>(open val value: Id) {
override fun equals(other: Any?): Boolean {}
override fun hashCode(): Int {}
}
It is a generic class that represents the identity of an entity.
Entity
open class Entity<Id : EntityId<*>>(open val id: Id) {
override fun equals(other: Any?): Boolean {}
override fun hashCode(): Int {}
}
It is a generic class that represents an entity. It is generic on the type of the identity of the entity and it has a reference to the identity. The equality of entities is based on the identity.
Value Object
interface ValueObject
It is an interface that represents a value object. It's of course empty, but it's useful to mark the value objects in the code.
Aggregate Root
open class AggregateRoot<Id : EntityId<*>>(id: Id) : Entity<Id>(id)
It is a generic class that represents an aggregate root. It is generic on the type of the identity of the aggregate root and it extends the entity class.
Repository
interface Repository<Id : EntityId<*>, E : AggregateRoot<Id>> {
fun findById(id: Id): E?
fun save(entity: E)
fun deleteById(id: Id): E?
fun update(entity: E)
fun deleteAll()
}
It's the simplest abstraction that represents a repository. It should only work with aggregate roots and have the basic CRUD operations. Only find methods should be added when generating a new repository.
Factory
interface Factory<E : Entity<*>>
Like the Value Object interface, it's an empty interface, but it's useful to mark the factories in the code.
Events Abstractions
Domain Event
interface DomainEvent : ValueObject
It is an interface that represents a domain event.
Event Listener
interface EventListener<E : DomainEvent> {
fun handle(event: E)
operator fun invoke(event: E) = runCatching { handle(event) }
}
It is an interface that represents an event listener. It has a handle method that should be implemented to handle the event.
Event Publisher
interface EventPublisher<E : DomainEvent> {
fun publish(event: E)
}
It is an interface that represents an event publisher. It has a publish method that should be implemented to publish the event.