创建 java 库时如何组织 类

How to organize classes when creating a java library

我正在创建一个科学图书馆,其中包含许多科学和数学分支的方法,包括微积分、统计学、物理学等。现在我有以下设置:

maths 中,Calculus.javaEvaluation.java 是唯一 类 我想要的 public,其中我将有我的 public在项目中随处可访问的静态方法。

我应该有更多包裹吗?更多目录?添加更多会使事情变得更多 complicated/unusable? 我尝试创建更多包,但它迫使我制作 类 例如 BinaryOperation.java public,我这样做了不需要,因为这个库的用户不需要处理二元运算符。

我希望用户可用的方法(public static):

将外部需要的方法标记为 public 并将其余方法标记为私有,仍然将 class 修饰符标记为 public 以便在以下情况下可以将其扩展需要。只要合乎逻辑,更多的包无论如何都不会受到伤害。

您可以通过删除 public 修饰符将其他 类 的可见性从 math 更改为包私有。例如。来自

public class BinaryOperation

class BinaryOperation

您图书馆的用户将无法访问那些 类 或其成员。当然,除非他们创建了一个同名的包。你无法阻止真正尝试的人。 ;)

在 "real" 世界中,答案是:视情况而定

没有 "one" 可以轻易推导出的结构。如何将您的应用程序分割成 "components"、"modules"、"libraries" 包在很大程度上取决于您的要求。当您是唯一一个使用此源代码的人时,请选择一些 "simple" 可以帮助 编写代码的东西。在更大的 "real" 项目中,您会考虑许多其他方面。

仅举一个例子:Conway's law 表示

organizations which design systems ... are constrained to produce designs which are copies of the communication structures of these organizations.

换句话说:当您有两个不同的团队处理同一件事时,让他们处理不同的 包可能是明智的。甚至在构成您的 application/product.

的不同 "components" 上

我给你的直接提示:

  • 如果您打算让其他人使用您的代码,请创建一个 包含 "public" 元素的特定包。将您的 "internal" 物品分开存放
  • 你的class名字似乎表明你项目的一部分是关于解析表达式的;以后与他们合作。然后 parsing 这样的责任肯定会进入它自己的包。
  • 因此,应该指导您的一个范例是 Single Responsibility Principle

但最重要的是:这些事情可能会发生变化 - 现在任何体面的 IDE 都支持在包之间移动 classes。因此,关键要理解的是:不要浪费太多时间来决定完美的目录结构预先

相反:观察您的设计决策的影响。当您意识到:"this approach isn't working for me" - 然后花时间 改变 事情。并且:让其他人审查你的工作。 50% 的学习是自己编程 - 150% 是倾听有经验的人对您的输出提供反馈。

最后:如果您真的有兴趣学习,我建议您查看C# 中的敏捷原则、模式和实践 罗伯特·马丁。那本书描述了构建真实世界应用程序的所有 个方面;包括 "how do I package my product".

等问题

有几个自由度。从技术角度来看,它们在 "clean" 或 "puristic" 的程度、可持续性和可维护性以及特定结构的执行力度方面各不相同。

实用的答案很简单:当用户应该看到 class 或界面时,就将其设为 public。否则:不要 做到public

这非常干净而且非常强大:没有人可以使用他不应该使用的 class。 JavaDoc 将默认生成 public classes 的文档,这正是您想要的。

重要的是要认识到,一旦 某些东西已经 public,您就不能再简单地移动、删除、重命名或结构性地改变它。这些更改中的每一个都会破坏客户的代码。


但是,当applications/libraries变大时,您经常提到的一点是:有一组class应该在所有包之间共享library,但仍然对外界不可见 - 如您的情况,maths.eval.BinaryOperation class。

我在这里看到的一些选项是:

  1. 将所有使用 BinaryOperation class的class放在一个包中。这可能 不是 一个合理的选择,因为它们在其他方面是不相关的,并且只有 BinaryOperation 作为(非常低级的)横切关注点。 (不过,就是上面所说的"clean"和"strong")

  2. BinaryOperation 标记为客户不应使用的内容。例如,您可以将它放入一个名为 ...common.internal.implementation 的包中,并在 JavaDoc 中明确声明 "...这个 class 不应该被使用客户。这既不干净也不坚固。但它给您带来的努力最少,因此可能是一个合理的权衡。

  3. BinaryOperation 拉出到自己的库中。 (可能与 UnaryOperation 和其他几个 classes 一起)。然后可以将该库打包为 common-operations.jar 之类的东西。您的 math... 图书馆的用户将 依赖于主图书馆。主库依赖于 "operations" 库这一事实在主库本身 中是不可见的。 Maven 等工具可帮助您为库的用户透明地解决这些依赖关系。这里的严重缺点:它给您带来了维护这个 (public) "operations"-库的负担。

  4. 只是为了完整性:对于 "large scale" 软件开发,还有其他解决方案。例如,在 OSGi 上下文中,您可以定义 access rules for packages

一个意见:我会选择选项 2. 或 3.


旁注:

不要调用你的根包 maths! 每个人都可以创建这样的包(但没有人 应该 创建它).如果您打算创建一个仅 public 可用的库,请查看 Package naming conventions:您的包名称应该是 "reversed domain name"。因此,例如,注册域 "defoification.com",并将您的包命名为 com.defoification.maths。其他一切都会导致长期运行出现问题。

所有这些都与 API 设计和一般 OOP 的某些原则密切相关。例如,有些人提倡非常严格的设计,从某种意义上说,只有接口应该是 public,实际数据模型不应该是 public classes全部。此外,class 设计的细节可能有某些注意事项。例如,方法修饰符的选择(如果你有 public classes)。方法应该很少是 public,而是 public finalprotected finalprotected abstract,这取决于应该允许谁调用或覆盖它。有关此内容(以及许多相关主题)的更多信息,请参阅 http://wiki.apidesign.org/wiki/Main_Page 以及 NetBeans 主要作者之一 Jaroslav Tulach 所著的相应 "Practical API Design" 书籍。