views:

229

answers:

4

I am just reading Agile Principles, Patterns and Practices in C# by R. Martin and M. Martin and they suggest in their book, to keep all your interfaces in a separate project, eg. Interfaces.

As an example, if I have a Gui project, that contains all my custom Gui classes, I will keep their interfaces in the Interfaces project. Specifically I had a CustomButton class in Gui, I would keep the ICustomButton interface in Interfaces.

The advantage is, that any class that needs an ICustomButton does not need a reference to Gui itself, but only to the much lighter weight Interfaces project.

Also, should a class in the Gui project change and thus cause it to be rebuilt, only the projects directly referring to the CustomButton would need recompilation, whereas the ones referring to the ICustomButton may remain untouched.

I understand that concept, but see a problem:

Lets say I have this interface:

public interface ICustomButton
{
    void Animate(AnimatorStrategy strategy);
}

As you can see, it refers to AnimatorStrategy, which is a concrete class and therefore would sit in a different project, lets call it Animation. Now the interface project needs to refer to Animation. On the other hand, if Animation uses an interface defined in Interfaces, it needs to refer to it.

Cyclic dependency - "Here we come".

The only solution for this problem, that I see, is, that all methods defined in the interfaces take inputs that are themselves interfaces. Trying to implement this, will most likely have a domino effect though and quickly require an interface to be implemented even for the most basic classes.

I don't know if I would like to deal with this overhead in development.

Any suggestions?

+1  A: 

The simple answer is AnimatorStrategy should also be an interface. The implementation for AnimatorStrategy is in the Animation project, but the interface would be in an AnimationInterfaces or Interfaces (as needed) project.

I wouldn't necessarily have a single interfaces project, but one for each functional grouping. Clients of Animation would reference AnimationInterfaces and clients of Gui would reference GuiInterfaces.

This way you preserve your contracts, without mixing in any implementation.

For what it's worth I prefer to go the other way round with naming conventions. Put the interfaces in Animation, and the implementations in AnimationImpl (or similar). That way you are referencing the functional name.

Rich Seller
A: 

What about defining an interface with methods that take generic types? E.g.

public interface IThing
{
    int DoMyThing<T>(T variable);
}

If you need some restrictions on T variable, you could do:

int DoMyThing<T>(T variable) where T : IOtherInterface;

Where IOtherInterface is also defined in your Interfaces project. Then, so long as your particular class inherits from both IThing and IOtherInterface, you can use the DoMyThing method and pass in an instance of your particular class without having a circular dependency. Your code might become:

public interface ICustomButton
{
    void Animate<T>(T strategy) where T : IAnimateable;
}

The interface has no reference to concrete class AnimatorStrategy.

Sarah Vessels
How is this relevant? O_o
Vilx-
This is a good idea, but looks more like a hack to me. Interfaces are there to spell out contracts. How does T spell out what kind of strategy to expect? If I had IAnimateable I would not need T.
Thorsten Lorenz
+7  A: 

Beware of always, ever, and never - especially near all, none, or every.

Should you always put all of you interfaces in a separate assembly? No - not necessarily.

Should you put interfaces that you expect external consumers of your code to implement - possibly. I would put interfaces into an external assembly if you expect multiple assemblies in your project to rely on them - this can help break coupling dependencies. I've also used this practice to solve circular referencing issues, where assemblies need to be aware of interfaces in one another.

I don't put interfaces that are only used internally in a project in a separate assembly. I also don't promote interfaces into their own assembly when my projects are relatively small - or the interfaces are not intended to be used without the assembly that depends on them.

As for the example you presented - I would suggest that you consider NOT referencing classes in your system from interfaces. Whenever possible, I try to have interfaces only reference other interfaces - this keeps things relatively decoupled. You can't always achieve this - and so when you have these types of interfaces - you have to keep them with the assembly they depend on.

If you do decide to put interfaces into a separate assembly - you shouldn't necessarily put them all into a single assembly. You may want to break them out by their intended usage - this way consumers can pull in just the interfaces that are relevant to a particular domain of functionality.

LBushkin
Thanks for your answer. I was trying to get my head around the DIP (dependency inversion principle).While it looks nice in theory (lower level classes depending on higher level classes and not the other way around), it is hard to implement and maintian in practice.It is so much easier to just keep interfaces together with the classes that implement them.I guess in this case, I agree with your suggestion to only "complicate" the design in this way, if it becomes necessary.
Thorsten Lorenz
A: 

I think that cyclic dependancies might be unavoidable even if you declare everything as interfaces, because there might be a method in assembly Foo that takes a parameter IBar, and a method in assembly Bar, that takes a parameter IFoo.

I'd say that there is no universal recipe for this, but you should instead use "common sense" to divide the interfaces in assemblies as needed.

Vilx-