Adding interfaces that won't be actually used
I current开发者_运维技巧ly have two interfaces(that I'll name here IA
and IB
):
interface IA {
int Width;
int Height;
...
}
interface IB {
int Width;
int Height;
...
}
that share the same two properties: they both have a Width
and a Height
property.
I was thinking if there is any point in defining an IMatrix
interface containing a Width
and Height
properties:
interface IMatrix {
int Width;
int Height;
}
The thing is that although they share both the same properties, I won't make use of polymorphism with IMatrix
in any of my coding: i.e., there won't by any situation where I'll want to use an IMatrix
, I'll just want to use IA
and IB
. Adding an IMatrix
seems more like over-engineering than other thing, but I'd like to ask you guys what your opinion is on the matter.
Thanks
If you will not be using it specifically, then I would say there is no need for you to be adding it.
It only makes sense to abstract a relationship if there is a real relationship that you're using or might reasonably want to use in the future. If the relationship is very loose (they just happen to have two properties that mean something similar, but in completely different contexts), then there's no reason to provide the abstraction.
I think the YAGNI principle applies. If you're not going to use IMatrix
in your code then you don't need it. You can always add it and make IA
and IB
implement it later. None of your other code (concrete classes that implement those two interfaces) should have to change.
If you find yourself in the situation that you write two methods with the same implementation for IA
and IB
, then a common interface is a good idea. Otherwise, a common interface not necessary.
If your not in the situation now, you have to assess how likely it is to happen in the future and if it's worth to introduce the common interface now.
It depends upon the intent, how IMatrix might evolve and what the focus of the code is.
For example, if the code really only cares about the dimensions, then it can use IA/IB. But if the calling code is focused on matrix operations, then it may make sense to create this subinterface and use that. If you later add a matrix-specific property or operation, e.g. GetCellValue or similar, which is needed by code specifically dealing with matrixes, then using IMatrix from the start will make adding this easier. If you use IA/IB in code that is really about matrices, then you will have to refactor that code to change IA/IB to IMatrix (possibly involving many method signature changes), or put in a downcast from IA/IB in the code that needs IMatrix.
There can be many reasons for a common interface, IA and IB might have different properties and methods on other areas but if both of them somewhat defines a Matrix, a common interface would be great.
As a great programmer once said:
if possible Simplify everything to an interface
I put together a solution which provides an example on what it might look like in the end
class Program
{
static void Main(string[] args)
{
// D derives from C which implements interface IA and IB which
// are both derived from IMatrix
var matrix = new D {Height = 100, Width = 200};
// Method takes IMatrix
X(matrix);
// Method takes IA
Y(matrix);
// Method takes IB
Z(matrix);
// Method takes D
LastTest(matrix);
//
// Prints heights and widths 4 times
//
}
static void X(IMatrix x)
{
Console.WriteLine(string.Format("Height: {0}\r\nWidth: {1}\r\n\r\n",
x.Height, x.Width));
}
static void Y(IA x)
{
Console.WriteLine(string.Format("Height: {0}\r\nWidth: {1}\r\n\r\n",
x.Height, x.Width));
}
static void Z(IB x)
{
Console.WriteLine(string.Format("Height: {0}\r\nWidth: {1}\r\n\r\n",
x.Height, x.Width));
}
static void LastTest(D x)
{
Console.WriteLine(string.Format("Height: {0}\r\nWidth: {1}\r\n\r\n",
x.Height, x.Width));
}
}
internal interface IMatrix
{
int Width { get; set; }
int Height { get; set; }
}
internal interface IA : IMatrix
{}
internal interface IB : IMatrix
{}
internal class C : IA
{
public int Width { get; set; }
public int Height { get; set; }
}
internal class D : IA, IB
{
public int Width { get; set; }
public int Height { get; set; }
}
In some occations you might just need the width and height, in other scenarios you might need the full set of IA or IB or even the implementation ( but that should be simplified to an interface aswell ).
However, don't over-engineer your software, think about the domain and try to extract common parts.
One might ask why you would have things that you Do not use, IMatrix might be a "bad name" but then you have another problem. Not used code = dead code and thus should be removed.
The other principle in play is Don't Repeat Yourself (DRY), and the interface would be "used" in that IA and IB would extend it, even if no method actually takes an IMatrix (or whatever name you decide on).
However, the repetition is small in this case, so unless more commonality (either in interface methods, or utilities functions that could operate on IMatrix) arises it probably wouldn't be "carrying it's own weight" conceptually.
In your situation, don't make the IMatrix
interface. There's no purpose to an interface if there is no contract relationship to justify it. It would be like building a bridge first, then deciding which river to put it over.
精彩评论