【问题标题】:Dependency Injection and Java packages依赖注入和Java包
【发布时间】:2011-07-18 06:42:08
【问题描述】:

我正在做一个有几个包的项目。我所有的类都是根据依赖注入理念实现的。

现在,在我的应用程序中,将有一个地方负责实例化所有对象(实际上我为此使用了 IoC 容器,但这不重要)——所谓的组合根。

现在,问题在于,至少在我的理解中,组合根必须知道系统中将使用的所有类。也就是说,所有类都必须标记为公开。

我可以为每个包定义一个包组合根,然后从系统的组合根中调用它们中的每一个,但这似乎不是一个好主意。

例如,在 C# 中,情况并没有那么严重,因为没有包保护的访问修饰符 -- 而是内部的(当前程序集的所有元素都可以访问)。

你们一般是怎么处理的?

【问题讨论】:

    标签: java dependency-injection packages


    【解决方案1】:

    这是一个老问题,但我认为仍然讨论这个问题非常重要。虽然其他人试图说将包类公开以供组合访问没有问题,但我完全不同意。包最重要的功能是使用访问修饰符向其他人隐藏细节。你可以争论细节这个词,并说提供其主要功能的包的主要类不是包的细节。当你使用多态接口将你的包与外界隔离时,我会回答,主类也是细节的一部分。当您希望在编译时借助语言特性来保护您的软件架构不被团队中的其他开发人员侵犯时,限制对该主类的访问非常有用。如果您在 Python 中没有这样的功能,我为您感到抱歉,但这并不意味着在 Java、C# 等中没有必要使用如此出色的功能。

    假设您有一个使用多态接口与外部世界通信的包,并且它的所有内部类型都是访问受限的。那么实现该接口的主类如何在组合阶段初始化,而组合操作发生在所有包之外呢?这是主要问题。

    正如 Devoured 自己也提到的,除了在每个包中定义一个公共 composer 来实例化和合成所有内部类型,并最终返回一个多态接口类型的对象,该对象将这个模块与外部世界隔离开,没有办法。

    【讨论】:

      【解决方案2】:

      在我看来,C# 中的情况也是如此。如果 bean 工厂在包之外,而开发人员在内部创建了一个类,那不就是拒绝访问 bean 工厂吗?

      我把课程公开,不用太担心。

      客户端应该使用的接口根据定义是公共的。由于它们不直接实例化或使用实现,因此不必担心向它们提供公共访问权限。

      另一种方法可能是创建工厂方法并使其可用于 bean 工厂。让它选择使用公共工厂为给定实现提供哪个实现。

      【讨论】:

      • 在 C# 中,类是内部的。来自同一程序集的任何其他类(读取,.dll)都可以使用它们。但是是的,如果您尝试构建一个多组件项目,问题仍然存在。
      • 但是,就像我说的,bean factory 不太可能是同一个程序集的一部分。如果 bean 工厂是包的一部分,Java 就不会遇到这个问题。这是同样的问题。暗示(错误地).NET 执行了一些魔法来保持免疫是不诚实的。
      • 谁说 .NET 有魔力?我说过(并且是正确的)internal 的访问修饰符对于这种情况比 package-protected 更有用。
      • @devoured,我认为你错过了这里的大多数答案都在争论这个拥有公共类的“问题”并不是一个值得担心的真正问题,无论 C# 中的修饰符是否使它容易与否。
      【解决方案3】:

      现在,问题在于,至少在我的理解中,组合根必须知道系统中将使用的所有类。也就是说,所有类都必须标记为公开。
      ...
      大家一般是怎么处理的呢?

      通过将所有类标记为public。在 Java 世界中,这并不是真正的问题。

      【讨论】:

      • +1:只有其他包中的类访问需要公开。除非每个类都可以是一个组件,否则这可能不是必需的。
      • 公开所有课程在我看来并不是最伟大的想法(也就是说,如果它们不是必须的)。您是否将所有方法、所有字段都标记为公开?
      • 不,我公开的唯一方法是那些实现接口的方法,或者是 POJO 中的简单 getter/setter 方法。我不相信拥有public 类是一个问题——我不担心我的项目中的另一个开发人员恶意地将我的代码用于其他目的。除了使用访问修饰符之外,还有其他方法可以强制关注点分离、模块化、分层等。将此与 Python 之类的语言进行对比,其中没有任何访问修饰符 - 只是开发人员记录哪些方法是供公众使用的,哪些不是。
      • 并非所有方法;几乎没有字段。这不是马特 b。说。
      【解决方案4】:

      大多数容器通过使用反射来绕过访问限制。然而,这只是一个技巧,让您觉得自己有一些保护,而实际上反射允许您忽略访问修饰符。

      恕我直言,如果您正在访问另一个包中的类,您应该清楚这一点并给它一个适当的访问修饰符。

      【讨论】:

      • 问题是,如果我不使用 DI,我可以保留所有那些“外围”包保护类...包保护。
      • 如果你使用OSGi,你可以更详细地定义这种东西。模块必须明确导出可用的包。我会质疑你通过更合格的访问修饰符真正获得了什么。
      • 如果您愿意,您可以将它们保留为私有包,甚至私有,并通过反射访问它们。但是,您会发现将组件公开并直接使用它们更简单且不易出错。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-19
      • 1970-01-01
      • 2011-12-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多