【问题标题】:is it bad programming practice to place abstract classes inside the same package containing their derived classes?将抽象类放在包含其派生类的同一个包中是不好的编程习惯吗?
【发布时间】:2013-01-23 08:34:30
【问题描述】:

假设A、B、C派生自AbstractBaseClass并且它们都是同一个java项目的一部分,是形式的包结构......

 package com.whatever.###
 AbstractBaseClass.java

 package com.whatever.###.###
 A.java
 B.java
 C.java

...通常比以下形式的包结构更受欢迎...

 package com.whatever.###.###
 AbstractBaseClass.java
 A.java
 B.java
 C.java

?

...还是很少有人会关心?

【问题讨论】:

  • 我的预期正好相反:将抽象骨架类包私有与实现保持在同一个包中是一种很好的做法。

标签: java package abstract-class derived-class


【解决方案1】:

我使用第一个示例编写了一个相当复杂的应用程序应用程序,这就是我证明设计合理性的方式。在我的案例中,有一个与承保案例定价相关的通用界面,但有几个供应商可以提供不同的 Web 服务来填充实际数据。这是包结构

com.example.pricing
 \IPricingProvider.java
 \AbstractPriceProvider.java
com.example.pricing.vendorA
   \PricingEngine.java
com.example.pricing.vendorB
   \PricingEngine.java
com.example.pricing.vendorC
   \PricingEngine.java

然后在我的代码中,我使用import 连接我想要的引擎。像这样:

import com.example.pricing.*;
import com.example.pricing.vendorB.*;

IPricingProvider provider = Engine.create();

对我来说,优势是能够为每个供应商提供复杂而混乱的实现(两个是基于 rest 的,一个是使用 wsimport 的 Web 服务,因此生成了很多 Java 文件),并且不会让 Eclipse 自动完成看起来就像一场噩梦。此外,它还可以更轻松地将单个供应商移交给不同的开发人员。

【讨论】:

  • 我不同意你的回答,因为对我来说,在不同的包中使用相同的类名是一场噩梦。我更喜欢相同的包和不同的类名。我只是将不同的实现打包到不同的 jar 中(如果可能的话),并且只包括实际使用的供应商 jar。但我认为这就像喜欢巧克力而不是香草。
  • 我想这归结为你想用什么机制来管理不同的实现。使用编写良好的 Ant Build 文件或 Maven 之类的东西,您的方法可能不会变得更繁琐,实际上会导致运行时间更短,部署更容易。也许是时候让我放弃香草并尝试巧克力了(+1 表示观点)
【解决方案2】:

这实际上是一种很好的做法。太多的包会很快变得混乱。将实现类保存在同一个包中可以避免额外的导入语句,并且可以在应用程序代码库增长时轻松找到抽象类。例外情况是您有更多的实现类,这些实现类都是从抽象类扩展而来的。因此,例如,如果您有一个 MySQL 实现和一个 Mongo 实现的多个抽象类,您可能希望将它们放在单独的子包中。类似的东西

com.foo.data  <--- abstract classes
com.foo.data.mysql  <-- impl
com.foo.data.mongo  <-- impl

【讨论】:

    【解决方案3】:

    包结构有两个有时是不一致的目的。

    1. 让学习您的 API 和代码的人可以轻松找到满足他们需求的类。在这种情况下,您希望将类似的东西组合在一起,并使用包名称,让浏览 Javadoc 的人可以清楚地看到在哪里查找。这主张使用对 API 客户端有意义的具有广泛划分的少量软件包。
    2. 允许类访问彼此的包私有 API。这适用于许多紧密耦合类的小组。

    像包这样的大规模组织不应该依赖于当前的实现细节,所以我更喜欢 (1) 而不是 (2)。

    深层次结构很难学习,因此如果添加名称元素不会使学习 API 变得更容易,也无法帮助人们过滤掉与其当前任务无关的部分,那么就将其排除在外。

    【讨论】:

      【解决方案4】:

      我认为这取决于哪个部分对客户更重要:超类还是子类?

      当您首先考虑子类时,通常会出现后者,并且只是将一些公共部分重构为超类。那么这个超类应该在同一个包中,并且不公开可见,就像路易斯在他的评论中所说的那样。如果客户需要查看子类的类型,那么您倾向于使用这种模式。

      但是,当您从实现中抽象出来时,客户端通常只与 Jason 的回答中的超类一起使用,那么您应该遵循将每个子类放入其自己的包中的策略。通常这些子类需要更多与外部代码无关的类,因此为它们提供一个自己的包是一件好事。

      【讨论】:

        【解决方案5】:

        令人惊讶的答案是。视情况而定。

        如果您要创建两个兄弟后代,那么每个(如三个)一个文件是有意义的。如果它们很小并且/或者您几乎总是同时使用它们(例如目录和文件),那么无论如何都要将它们全部合二为一,这是一个务实的论据。

        如果您正在构建一些深层继承层次结构,其中只有最终后代具有可用功能(一个类越抽象,它做的越少),那么将它放在单独的文件中是没有意义的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-09-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-07-15
          • 2017-10-17
          相关资源
          最近更新 更多