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.
Best Answer
Since an interface is abstractly similar to a base class, use the same logic you would use for a base class. Classes implementing an interface are closely related to the interface.
I doubt you would prefer a directory called "Base Classes"; most developers would not want that, nor a directory called "Interfaces". In c#, directories are also namespaces by default, making it doubly confusing.
The best approach is to think about how you would break up the classes/interfaces if you had to put some into a separate library, and organize the namespaces/directories in a similar manner. The .net framework design guidelines has namespace suggestions that may be helpful.