I have some classes that represent, for the most part, data that’s deserialized from XML. They also have some behavior in them, because I don’t want to suffer from an anemic domain model. These domain objects don’t have any XML specific code in them, but they do have properties that correspond exactly to the tags and attributes in the XML.
Many of these classes’ behaviors rely on resources loaded from disk, like images. For that, some properties / xml attributes are relative file paths to these resources. Now my problems begin. The absolute path to be constructed for these resources is based on a separate dependency – the root of the “project”. Here’s what I’m struggling with:
-
Should my domain objects store the full absolute path to their resources? Or just the relative paths? If they held the absolute path, then the classes that load them – my XML readers – will have to take a dependency on the project root in order to build the full path for them. If not, I’ll have to make yet another layer of classes to handle that. I already have 3 layers, I don’t know if I can handle any more!
-
Should my domain objects store their own paths for where they are on disk? It makes sense for them to know where their dependencies are in relation to them, but to know their own location just feels wrong to me intuitively. This is sort of unrelated to the other part of the question, but I think if I go the wrong way on this it could bite me later.
2
@teresko gave you already a good answer for your question 2, and I try to add an answer for part 1:
Lets say you have a business object Image
with some properties, including a (persistent) property FilePath
(I assume the Image
object not to load that data into memory automatically, just beeing a reference to the data or containing meta data about the image file). Obviously, since you have several images to deal with, each one having its data under the same project root folder (and this folder may change in the future), you don’t want to store the absolute path in each image object, only relative paths. Lets assume further you have a business object Project
with a property RootFolder
. This business object may be a persistent object, too, or it may be created and initialized at run time, whatever fits best to your requirements.
Now you have two options for accessing the image files:
-
either you add a (derived) property
AbsoluteFilePath
to your Image class. To make this property return the concatenation of the relative path and the root folder, your Image objects needs depend on theProject
object. This dependency might be constructed / injected during the construction process of theImage
object, or you have a two-phase construction process where after the deserialization the dependency is injected afterwards, or it may be hardcoded somehow in yourImage
object, but you cannot avoid it -
or, you don’t add such a property to the
Image
class, and let the client code (the code using theImage
object) handle the problem. For this case, it may be helpful to add a helper methodGetAbsolutePath(relativePath)
to theProject
class and reuse this method throughout your code. This has the advantage that you avoid the dependency betweenImage
andProject
above, but the drawback that the client code gets a little bit more lengthy: for example, instead ofReadFile(image.AbsoluteFilePath)
you will have to write
ReadFile(project.GetAbsolutePath(image.FilePath))
You will have to make a decision between those two options, and from the information you gave in your question, it is impossible for me to tell which is the better one in your case – both options are sometimes reasonable. But IMHO none of these two options leaves you with an “additional layer” or an “anemic domain model”.
1
TL;DR
No.
Longer version.
When you are talking about “data models” I assume that you mean domain objects. Because “model” is not an object or class. It is an application layer.
Back to the point.
No. The domain object should not know “where” it is being store or even “if” it is has been store anywhere at all. The responsibility of domain object is to represent the business rules, which apply to a specific part of domain model (as defined in this book).
Since my primary language is PHP, the example will be in it:
$user = new User;
$user->setId(42);
$mapper = new UserMapper($xmlFileHandler);
if ($mapper->fetch($user)) {
$user->setName('Ford Prefect');
$mapper->store($user);
}
The persistence of domain objects should be handled by data mappers. And you can have multiple mappers acting on same domain object.
For example: when you are loading data for “current user” domain object, it can be populated by the information that is in user’s session, data from cache and info from one or more SQL tables.
2
-
I didn’t understand the “dependency on project root” part, but it sounds like you may want to preserve relative paths in java properties / xml attributes and introduce a java property that represents path to the project root and has no corresponding xml attribute. You can initialize this property either in the constructor or via a setter method after deserializing the model.
-
Assuming that path to the project root does not have to be the same as the path to a serialized model, I would rather not store the path to a serialized model in the model itself. This would preclude potentially persisting the model to a database or other storage type, which sounds wrong.
I don’t think you need one more layer of abstraction to solve both of these issues. A path to serialized model and a project root can be provided in some kind of a model manager or a factory.
Finally, I think it is worth having data and methods to process it together unless you’re writing an ORM library. However, it is important to keep only those methods which are directly meant for processing data and factor everything else out to other classes in order to avoid placing multiple responsibilities on your class.