Which Java objects exist? When do they exist? Is it enough that objects are instantiated and have memory allocation? What about lazy initialization? How can temporary objects be non-existing, since they exist in my code and program? What about soft-deleted entity objects? How about objects which are waiting for the GC? There are two aspects to consider. First, from technical point of view, objects exist after they have been created, i.e. they have been allocated memory space and instantiated. Second, objects at higher (abstraction) level might not exist even after they have been created: here is the realm of domain objects (DOs). For example, if an object represents a real-world object and certain state of it, we should define its existence. Think that only when the object has been created and its state has been loaded the object is considered to be “real” (which means that it exists too). This post discusses the existence of higher level objects.
Domain objects should consist of simple JPA entities – not generally speaking of course, but assuming JPA is used. The idea is a bit like using DAOs but different. The entities should be anemic and separate domain objects would be the base of a proper domain model! For a long time I used repository pattern with CRUD methods, but then I started to think that what is the point of having source code lines like: “myCar.update()”. I moved to thinking that at least CRUD-operations should be hidden, i.e. protected. Why? IMO, any operation that changes the state of itself should be encapsulated – remember objects? But I still didn’t get the idea of the repository pattern anymore: shouldn’t all updates to any object be automatically stored to persistence storage e.g. at the end of service method call? The answer to this problem did come after a long thinking.
Then it hit me. If I use domain objects (and a proper domain model) together with anemic data entities (a proper data model) I could discard the repository pattern with my Renovator Pattern. But first it needs a bit tweaking. The Image 1 shows the improved version.
I have introduced Actions (PBRD): Plan, Build, Renovate, and Destroy. Additionally, I introduce the corresponding states (EPBRD): Empty, Planned, Built, Renovated, and Destroyed. Note that existing, i.e. real objects are in states “Built” and “Renovated”: built objects have not ever been stored to persistence storage. The actions are similar to the operations in a repository (CRUD): i.e. Create, Read, Update and Delete. And corresponding entity states are described in JPA Entity Life Cycle model. But there is crucial difference: real objects are mapped to domain objects and domain objects are real objects: real objects either exist or don’t. This makes life easier to programmers – please read on.
DEFINITION: only Objects which can be read after a system failure are considered to be Existing, otherwise they are Non-existing. When the system fails the existing objects must maintain their states! This implies that write operations are “more powerful” than read operations, because only writing can change state.
Both domain objects and data entities must have a default objects which has always the same identifier, for example Long id = 0L, because database IDs typically start from one. A default object is in “Planned” state which makes it non-existing and therefore you can not invoke any business logic method calls from them. To summarize: I argue that domain objects should consist of data entities and only existing domain objects should be used at runtime!
// Outcome is an existing object (Car.class) CarEntityBuilder.build(); // Outcome is a non-existing object Long registrationID = 2343L; CarEntityBuilder().renovate(registrationID).destroy();
Life-cycle of a Car domain object.
// Non-existing (note: "new" operation is allowed only within DO) Car c = CarEntityBuilder().setRegistrationNumber(CarRegistrationNumber.Default()).plan(); // Build it to make it existing by definition! CarRegistrationNumber nb = RegistrationCenter.requestNewCarRegistrationNumber(); c = c.setRegistrationNumber(nb).build(); // Copies are must be allowed Car copy = CarEntityBuilder().renovate(c.setRegistrationNumber()); // Finally destroy it c = c.destroy(); // Can not destroy car two times => "destroy if exists" cf. "create if not exists" copy.destroy();
But what about objects that do not need persistence but should be existing? Objects like beans which are for instance application scoped or singleton and can always be read and instantiated if they do not have dependencies to other objects which require persistence. The implication is that such objects have no state, or the immutable state is coded into the source code. The recommendation is NOT to put these objects into database! For example, if you use domain model, the domain objects can exist without the persistence layer if they are in accordance with the DEFINITION. However, note that they have identifiers still, because these higher level objects have different semantics for them – and are stateless too.
You must be logged in to post a comment.