OK .. after all the discussion I'm changing my question slightly to better reflect a concrete example that I am dealing with.
I have two classes ModelOne
and ModelTwo
, These classes perform similar type of functionality but are unrelated to each other. However I have a third class CommonFunc
that contains some public functionality that is implemented in both ModelOne
and ModelTwo
and has been factored out as per DRY
. The two models are instantiated within the ModelMain
class (which itself is instantiated at a higher level etc - but I am stopping at this level).
The IoC container that I am using is Microsoft Unity. I don't pretend to be an expert in it, but my understanding of it is that you register a tuple of interface and class with the container and when you want a concrete class you ask the IoC container for whatever object matches a specific interface. This implies that for every object I want to instantiate from Unity, there has to be a matching interface. Because each of my classes performs different (and-non-overlapping) functionality this means that there is a 1:1 ratio between interface and class1. However it does not mean that I am slavishly writing an interface for each and every class I write.
Thus code wise I end up with2:
public interface ICommonFunc
{
}
public interface IModelOne
{
ICommonFunc Common { get; }
..
}
public interface IModelTwo
{
ICommonFunc Common { get; }
..
}
public interface IModelMain
{
IModelOne One { get; }
IModelTwo Two { get; }
..
}
public class CommonFunc : ICommonFunc { .. }
public class ModelOne : IModelOne { .. }
public class ModelTwo : IModelTwo { .. }
public class ModelMain : IModelMain { .. }
The question is about how to organize my solution. Should I keep the class and interface together? Or should I keep classes and interfaces together? EG:
Option 1 - Organized by class name
MySolution
|
|-MyProject
| |
|-Models
| |
|-Common
| |
| |-CommonFunc.cs
| |-ICommonFunc.cs
|
|-Main
| |
| |-IModelMain.cs
| |-ModelMain.cs
|
|-One
| |
| |-IModelOne.cs
| |-ModelOne.cs
|
|-Two
|
|-IModelTwo.cs
|-ModelTwo.cs
|
Option 2 - Organized by functionality (mostly)
MySolution
|
|-MyProject
| |
|-Models
| |
|-Common
| |
| |-CommonFunc.cs
| |-ICommonFunc.cs
|
|-IModelMain.cs
|-IModelOne.cs
|-IModelTwo.cs
|-ModelMain.cs
|-ModelOne.cs
|-ModelTwo.cs
|
Option 3 - Seperating Interface and Implementation
MySolution
|
|-MyProject
|
|-Interfaces
| |
| |-Models
| | |
| |-Common
| | |-ICommonFunc.cs
| |
| |-IModelMain.cs
| |-IModelOne.cs
| |-IModelTwo.cs
|
|-Classes
|
|-Models
| |
|-Common
| |-CommonFunc.cs
|
|-ModelMain.cs
|-ModelOne.cs
|-ModelTwo.cs
|
Option 4 - Taking the functionality example further
MySolution
|
|-MyProject
| |
|-Models
| |
|-Components
| |
| |-Common
| | |
| | |-CommonFunc.cs
| | |-ICommonFunc.cs
| |
| |-IModelOne.cs
| |-IModelTwo.cs
| |-ModelOne.cs
| |-ModelTwo.cs
|
|-IModelMain.cs
|-ModelMain.cs
|
I sort of dislike option 1 because of the class name in the path. But as I am tending to 1:1 ratio because of my IoC choice/usage (and that may be debatable) this has advantages in seeing the relationship between the files.
Option 2 is appealing to me, but now I have muddied the waters between the ModelMain
and the sub-models.
Option 3 works to separate the interface definition from the implementation, but now I have these artificial breaks in the path names.
Option 4. I took Option 2 and tweaked it in order to separate the components from the parent model.
Is there good reason for preferring one over the other? Or any other potential layouts that I have missed?
1. Frank made a comment that having 1:1 ratio harkens back to C++ days of .h and .cpp files. I know where he is coming from. My understanding of Unity seems to put me into this corner, but I am also not sure even how to get out of it if you are also following the adage of Program to an interface
But thats a discussion for another day.
2. I have left out the details of each objects constructor. This is where the IoC container injects objects as required.
interface
for it. Aninterface
is really just an abstract class with all virtual members.