3

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:

  1. 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!

  2. 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.

  • 3
    Which is the better choice... - your "tl;dr" is a loaded question and basically presents a false alternative. Just because a domain object can't write itself to a database or wherever doesn't mean it is "anemic". It should embody business rules - that's the behavior. – Konrad Morawski May 6 '14 at 10:01
  • @Konrad It wouldn't be anemic because it lacks knowledge about it's storage. It would be anemic because if I ripped out the stuff about absolute paths, I would have to also rip out the behavior that depends on those absolute paths, and they would be reduced to data bags. – Tesserex May 6 '14 at 12:28
3

@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 the Project object. This dependency might be constructed / injected during the construction process of the Image 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 your Image 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 the Image object) handle the problem. For this case, it may be helpful to add a helper method GetAbsolutePath(relativePath) to the Project class and reuse this method throughout your code. This has the advantage that you avoid the dependency between Image and Project above, but the drawback that the client code gets a little bit more lengthy: for example, instead of

      ReadFile(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".

  • I know I explained something right if you were able to infer my domain structure so well. I don't know why I didn't think of adding a helper to the Project class. I had been assuming that putting the work on the client side would be some huge hassle. – Tesserex May 6 '14 at 12:36
2

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.

  • Actually, this answers only part 2 of the question. – Doc Brown May 6 '14 at 10:40
  • And which was the 1st part then? Because I only noticed the 'which type of path should "models" store?' and 'should my "models" store path?' parts in the question. Since I actually bothered to read the long part, I ignored the "tl;dr" bit, which contained two invalid and confusing "solutions". – mefisto May 6 '14 at 11:06
1
  1. 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.

  2. 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.