【问题标题】:How to work around that there's no subpackage visibility in Java如何解决 Java 中没有子包可见性的问题
【发布时间】:2019-07-25 17:23:18
【问题描述】:

当我使用 DDD 编写一个新组件时,我尝试在一个包中包含一个单独的 public 类,我的组件的所有协作者 package protected

这通常效果很好,因为只有一个入口点,我的组件的客户端可以使用。所有(内部)协作者都将被隐藏。

考虑一个示例,客户可以驾驶我专门构建的 Java 汽车四处行驶。我不希望客户看到车辆的所有内部部件,所以只有Car 类公开:

org.automobile
|- Car           <-- only Car is public
|- Engine        <-- all collaborators have default (package-protected) visibility
\- Battery

现在,随着领域的发展,事情通常会变得更加复杂,所以我想将具有他们的协作者的类移动到子包中,以保持我的结构整洁:

org.automobile
|- Car
|- drive.Engine           <-- how to make this only available to Car
|- drive.Spark
|- drive.Belt
|- electric.Battery       <-- and this
\- electric.BatteryCell

我现在想让EngineBatteryCar 可见,因为我的组件的客户端仍然不能直接使用这些类。

我知道 Java 中没有“子包”可见性,但是除了使用 Java 9 模块之外,还有其他轻量级模式可以实现我想要的吗?

【问题讨论】:

  • 很好的问题,写得很好,我时不时会想到它。我偶尔尝试过一些解决方法,但由于缺乏子包可见性,因此需要进行一些权衡。对这个问题感兴趣吗?
  • 是的,当然。告诉我你有什么:D

标签: java package visibility


【解决方案1】:

我会说有 2 个选项。任何人都可以随意参与,因为这个问题很有趣。

对 java 代码使用单个文件而不是包

这个想法是,您可以使用单个 java 文件来声明 Car.java(引擎和电池)可用的类和 API。声明对 Car 隐藏的概念的类(Spark、Belt、BatteryCell)应该是私有的和静态的,这样它们就不会与声明的类有隐式链接。

这种方法可以扩展,但需要更多的工作。这在一定程度上也是有帮助的,它不适合大型代码库,也不适合将来规模庞大的代码库。

 org.automobile
|- Car
|- Engine.java           <-- how to make this only available to Car
|- Engine.java-Spark     <--private static class in File Engine.java
|- Engine.java-Belt      <--private static class in File Engine.java
|- Battery.java               <-- package private class
\- Battery.java - BatteryCell <--private static class in File Battery.java

将 abstract 和 protected 修饰符与子包结合使用

这个想法是您创建公共抽象类,其功能由受保护的方法公开。例如 AbstractBattery 和 AbstractEngine。 然后,您可以创建一些充当“代理”的类,使用 Car 包中的包私有实现扩展抽象类,并覆盖您想要提供的方法。例如发动机和电池。 Car 将有权访问抽象类的重写方法。另一个副作用是您的 AbstractClasses 中不能有最终的 API 方法。

这种方法更适合大型代码库,旨在隐藏功能和抽象以防止意外使用。但是,它需要更多的工作。 当然,其他人仍然可以扩展 AbstractBattery 和 AbstractEngine 并使用它们。

org.automobile
|- Car
|- Engine      <-- extends AbstractEngine, is package private, overrides methods that Car needs to  access
|- Battery     <-- extends AbstractBattery,is package private, overrides methods that Car needs to access
|- drive.AbstractEngine <-- Public abstract class with no public methods, methods that are needed by Engine and Car are protected.
|- drive.Spark <-package private
|- drive.Belt <-package private
|- electric.AbstractBattery <--Public abstract class with no public methods, methods that are needed by Battery and Car are protected.
\- electric.BatteryCell <-package private

这是一个示例:

org.automobile.engine.AbstractEngine

package org.automobile.engine;

public abstract class AbstractEngine {

    protected void startEngine(){
        System.out.println("Zoom Zooomm Zoommm");
    }
}

org.automobile.Engine

package org.automobile;

import org.automobile.engine.AbstractEngine;

final  class Engine extends AbstractEngine {

    @Override
    protected void startEngine(){
        super.startEngine();
    }
}

【讨论】:

  • 有趣的第二种方法是使用abstract 类在包之间建立契约。不过,我肯定会以不同的方式命名这些类。基本包中的 EngineClient 和子包中的 Engine 之类的东西。我会调查一下,这是什么感觉。
  • 我同意第一种方法不能很好地扩展。
  • 我也同意命名,实际上我习惯将它们命名为*Proxy,如EngineProxy和Engine。我将命名方案与 Abstract 一起使用,以使其易于演示。附言如果您使用它,请随时添加任何可以提供帮助的评论或想法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-30
  • 2022-01-05
  • 1970-01-01
  • 2021-12-21
  • 2016-08-08
相关资源
最近更新 更多