2009-07-16 58 views
11

我只是在阅读敏感原理,模式和实践在C#由R.马丁和M.马丁,他们建议在他们的书,保持所有的接口在一个单独的项目,例如。 接口组织接口

举个例子,如果我有一个项目,包含我所有的自定义GUI类,我将保持其接口在接口项目。具体来说,我有一个在 CustomButton类,我会保持在接口 ICustomButton接口。

的优点是,这需要一个ICustomButton任何类并不需要,但只对重量轻得多接口项目本身的参考。

此外,应在项目变更一类,从而导致它被重建,只有项目直接参照的CustomButton需要重新编译,而那些指ICustomButton可能会保持不变。

我理解的概念,但看问题:

可以说我有这个接口:

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

正如你所看到的,它是指AnimatorStrategy,这是一个具体的类,因此将坐在不同的项目,让我们打电话动画。 现在界面工程需要参考动画。另一方面,如果动画使用在接口中定义的接口,则需要参考它。

循环依赖 - “我们来了”。

对于这个问题,我看到的唯一解决方案是,接口中定义的所有方法都接受本身为接口的输入。试图实现这一点,很可能会产生多米诺骨牌效应,并且很快需要一个接口来实现即使是最基本的类。

我不知道我是否愿意在开发中处理这种开销。

有什么建议吗?

回答

16

小心永远,永远,永远 - 特别是在所有的附近,没有,或每一个。

如果您总是你们接口的所有在单独的程序?不 - 不一定。

您是否应该将希望实现代码的外部使用者的接口放在可能的位置?如果您希望项目中的多个程序集依赖它们,我会将接口放到外部程序集中 - 这可以帮助中断耦合依赖关系。我也使用这种做法来解决循环引用问题,其中程序集需要知道另一个接口。

我不把接口只在一个项目中在一个单独的程序集中使用。当我的项目相对较小时,我也不会将接口提升到它们自己的组装中,或者如果没有依赖它们的组件,则不打算使用这些接口。

至于你提出的例子 - 我建议你考虑不从接口引用系统中的类。只要有可能,我尝试让接口只引用其他接口 - 这会使事情相对解耦。你不能总是实现这一点 - 所以当你有这些类型的接口时 - 你必须让它们保持它们所依赖的程序集。

如果您决定将接口放入单独的部件中 - 则不必将它们全部放入单个部件中。您可能希望按照其预期用法将其分解出来 - 这样消费者就可以仅仅引入与特定功能域相关的接口。

3

简单的答案是AnimatorStrategy也应该是一个接口。 AnimatorStrategy的实现位于Animation项目中,但接口将位于AnimationInterfaces或Interfaces(根据需要)项目中。

我不一定有一个接口项目,但每个功能分组。 Animation的客户端会引用AnimationInterfaces,Gui的客户端会引用GuiInterfaces。

这样你就可以保留你的合同,而不用混淆任何实现。

为了什么值得我更喜欢用命名约定来换个角度。将接口放入Animation中,并将实现放入AnimationImpl(或类似的)中。这样你就引用了功能名称。

-2

如何定义一个接口与采用泛型类型的方法?例如。

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

如果您需要在T variable一些限制,你可以这样做:

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

IOtherInterface也是在你的界面项目中定义。然后,只要您的特定类继承IThingIOtherInterface,就可以使用DoMyThing方法并传入特定类的实例,而不会产生循环依赖。您的代码可能变为:

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

该接口没有提及具体类AnimatorStrategy

+1

这有什么关系? O_o – 2009-07-16 13:49:57

+1

这是一个好主意,但看起来更像是对我的破解。接口在那里拼出契约。 T如何阐明期望的策略?如果我有可以注册,我不需要T. – 2009-07-16 14:39:48

1

我认为循环依赖可能是不可避免的,即使你将所有声明为接口也是不可避免的,因为在程序集Foo中可能有一个方法需要一个参数IBar和一个带有参数IFoo的程序集Bar中的方法。

我想说这里没有通用的配方,但是你应该使用“常识”来根据需要划分组件中的接口。