In my system I have two different projects, one defining its interfaces and another defining its domain objects. So far I managed to have the interface definitions independent of the domain objects but I am feeling now the need to include certain domain objects either as parameters of the methods defined i开发者_JAVA技巧n the interfaces or as return values of such.
Should I resist and try to keep interfaces independent of the domain objects or is this a unfounded concern?
EDIT - after posting the question I thought about defining an interface for each domain object, this way they can kept separate - don't know if it is overkill or if it is the price to pay so they remain independent.
EDIT # 2 - I was asked to give an example so I'll try to keep it simple. I have a process that handles image transformation and one of my domain objects is a class that holds information such as resolution, list of pages, hash, etc. Let it be called DocumentInfo. I have a class that uses DocumentInfo to perform actions such as GeneratePdfFromTiff; I had defined GeneratePdfFromTiff first as an interface method of IImageHandler, which is then implemented by ImageHandler.
The problem is - one of the parameters to GeneratePdfFromTiff is DocumentInfo. Here I have the method defined at the interface level having to be aware of DocumentInfo which was defined at the domain level. This is the kind of dependency I am concerned about.
This is a tough one, I'll give a try. +1 for the question.
Domain Models should know how to interact with each other's inner workings if they do it in the real world I think. That, of course, depends heavily on your exact domain model, because different models of the same thing would come up with very different representations.
The issue with the interfaces for each domain model class is that your domain model itself is already a specific view on reality, just like the interfaces. An interface is only valid within that specific domain. You can't use the same ICar
for transportation planning, household-income calculators and car aerodynamics optimization.
Therefore, I doubt it is very useful to isolate their dependencies too far.
From what I know, interfaces are mostly (always?) public, which gives rise to access issues. The interface should not expose details about the implementation, but the domain model classes contain the actual implementation. Thus, instead of 'just accessing some value', you'd have to create another abstraction mechanism for each and every detail. You can't, for example, access any ID, User, etc. in the system. You'd need an abstract ID type, an ID Provider, etc. I believe this could be extremely cumbersome in a large real-world model.
Certain 'natural domain borders' should still be isolated, of course. If you build a social text editor, all domain classes that would also occur in a traditional text editor should be completely isolated from the social-network related items. Thus, the text-editor should only know an IUser
. But I guess I'm not telling you anything new...
This is not too satisfying I'm afraid, but it seems it is essentially a thin line to walk.
I would keep in mind the interests of the software engineers using the interface. Trying to decouple can make the code more abstract, and usually more difficult to consume. That means that more code will need to get written to "get stuff done", and that code will require more effort to write.
Pardoxally, due to the extra complexity, it will also get harder to change things, because more lines of code depend on your domain's visible interface. This is kind of the opposite of what you probably want to achieve, because the decoupling should help to make the system easier to understand and maintain (among other things).
But it really really depends a lot on what types you intend to expose, and to whom. Could you give some examples?
You may actually need to. If your Domain Model references the interface library, you can't reference the Domain Model from the interface library, as that would create a circular reference.
Even if this isn't the case, referencing the Domain Model from the services creates a hard coupling between the interfaces and the Domain Model. This means that anyone implementing or referencing the interfaces also reference the Domain Model. You may not want that.
I would definetely recommend that you extract interfaces from those domain objects you would like to use together with your interfaces.
If you already have a class called Foo
, then extract and interface IFoo
from it, and use it in your other interfaces:
public interface IMyService
{
public IBar DoStuff(IFoo foo);
}
Once you start using domain objects as interfaces, you will discover that there may be more places where you can replace the concrete class with the interface. Every time you do that, your code becomes more loosely coupled, and that's a good thing. It makes your code more maintainable, and more adaptable to change.
When you extract an interface, remember that you must perform a deep extraction.
If Foo
looks like this
public class Foo
{
public Baz Baz { get; }
}
the interface should look like this:
public interface IFoo
{
IBaz Baz { get; }
}
public interface IBaz {}
(apologies for the C# code if you write in a different language...)
I'd recommend defining interfaces for domain classes that have behavior, but not for simple container classes or value types.
If GeneratePdfFromTiff
just treats DocumentInfo
like a parameter object and the document information class doesn't have any logic, it should just be a publicly-accessible type.
If the document information class performs calculations or does anything else interesting, it's definitely worth extracting an interface. (For all the excellent reasons Mark mentions in his answer.)
精彩评论