我是一个刚开始从事大型项目的团队的新手,该项目具有许多组件和依赖项。对于每个组件,都有一个interfaces
包装,用于放置该组件的暴露接口。这是一个好习惯吗?
我通常的做法一直是将接口和实现放在同一个程序包中。
Answers:
放置接口和实现都是司空见惯的事,这似乎不是问题。
以Java API为例,大多数类在同一包中都包含了接口及其实现。
以java.util
包装为例:
它包含的接口,如Set
,Map
,List
,同时还具有实现,如HashSet
,HashMap
和ArrayList
。
此外,Javadocs旨在在这些条件下很好地工作,因为当显示包的内容时,它将文档分为接口和类视图。
除非有大量的接口,否则仅具有用于接口的软件包实际上可能有点多余。但是仅仅为了这样做,将接口分成自己的程序包听起来是一种不好的做法。
如果需要将接口名称与实现区别开来,则可以使用一种命名约定来使接口更易于识别:
在接口名称前添加I
。.NET框架中的接口采用了这种方法。可以很容易地说出这IList
是列表的接口。
使用-able
后缀。这种方法是Java API中经常看到,比如Comparable
,Iterable
和Serializable
仅举几例。
对于任何语言,将它们放在同一程序包中都可以。重要的是暴露给外界的东西,以及它从外部看的样子。没有人会知道或不在乎实现是否在同一程序包中。
让我们看一下这个特定实例。
如果您将所有公共物品放在一个包中,而私人物品放在另一个未公开的包中,则库的客户端将看到一个包。如果您将私有物品与公开暴露的物品一起移到包装中,但不从包装内部暴露它们,则客户会看到完全相同的事物。
因此,这没有规则的味道,它没有充分的理由:它是基于公开可见的内容来做出决定,而该决定不会对公众可见内容产生任何影响。
就是说,如果在任何特定情况下,将接口和实现拆分为单独的包似乎是个好主意,请继续进行。想到这样做的原因是该程序包很大,或者您可能想链接一个替代的实现而不是标准的实现。
friend
(C ++)或internal
(C#)。
在许多框架中,例如OSGi,您几乎都必须这样做。我认为这促进了在包装而非罐子级别的松耦合。
《实用软件工程:案例研究方法》一书提倡将接口放在单独的项目/程序包中。
本书所讨论的PCMEF +体系结构具有以下原则:
原则3和原则7的说明解释了为什么这是一个好主意:
邻居通信原理要求程序包只能与其邻居程序包直接通信。该原理确保系统不会分解为互通对象的不可压缩网络。为了执行该原则,在非相邻对象之间传递的消息使用委托(第9.1.5.1节)。在更复杂的场景中,可以使用相识软件包(第9.1.8.2节)来对接口进行分组,以帮助协作进行远处的软件包。
熟人打包原则是邻居沟通原则的结果。相识包由对象(而不是具体对象)传递给方法调用的参数的接口组成。这些接口可以在任何PCMEF软件包中实现。这有效地允许非相邻包之间的通信,同时将依赖项管理集中到单个相识包。9.1.8.2节解释了对熟人包的需求,接下来将在PCMEF上下文中再次讨论。
是的,这是一个很好的做法,因为它允许您在不发布特定实现的情况下发布接口。就是说,如果您不需要发布外部接口,则将接口定义放在与实现相同的程序包中就没有问题。
我正在做一个项目,由于以下原因,它对我来说效果很好:
与不同类型的Map或Set相比,单独打包的接口和实现用于不同的用例。没有理由只为树提供一个包(java.util.tree.Map,java.util.tree.Set)。它只是一个标准的数据结构,因此将其与其他数据结构放在一起。但是,如果您要处理的益智游戏具有非常简单的调试界面和漂亮的生产界面,则作为其前端的一部分,您可能会拥有com.your.app.skin.debug和com.your.app .skin.pretty。我不会将它们放在同一个程序包中,因为它们会做不同的事情,而且我知道我会诉诸一些SmurfNamingConvention(DebugAttackSurface,DebugDefenceSurface,PrettyAttackSurface等)为两个人创建一些非正式的命名空间(如果它们位于同一程序包中)。
对于查找单独程序包中的相关接口和实现的问题,我的解决方法是为程序包采用命名配置。例如,我可以将所有接口都放在com.your.app.skin.framework中,并且知道与包树相同级别的其他包是实现。缺点是这是非常规惯例。老实说,我将在6个月的时间内看到此约定的效果:)
我没有虔诚地使用这种技术。有些接口仅在特定的实现中有意义。我不会将它们放在框架包中。在某些程序包中,我看起来好像不会创建40个不同的实现类,因此不必理会。
我的应用程序使用guice并具有很多接口。
程序设计的问题通常涉及利弊,没有一个适合所有人的答案。就像为什么您会在小型200行程序中使用此技术?考虑到我的其他架构选择,对于我的特定问题,这对我来说很有意义。:)
有很多充分的理由将接口与实现放在单独的程序包中。例如,您可能想使用支持Dependency Injection的容器在运行时连接必要的实现,在这种情况下,只需在构建时提供接口,并在运行时提供实现即可。或者,您可能希望在运行时提供多个实现(例如,使用模拟实现进行测试)或特定版本的多个版本(例如,用于A / B测试等)。对于此类使用案例,将接口和实现分开打包更为方便。