这是一个概念性的问题。
我通常以逻辑方式将代码组织在软件包中。
例如:数学运算进入my.package.math或业务逻辑进入my.package.business,依此类推。

在这几天里,我怀疑我是否想对Java中的程序包可见性施加的约束感到惊讶。

让我显示一些代码来更好地解释我的情况:
我有以下包结构:

+-- org.example
    +-- greetings
    |   +-- RandomGreetings
    +-- GreetingsService
    |
    +-- Main


和以下代码:

GreetingsService.java

package org.example;

import org.example.greetings.RandomGreetings;

public class GreetingsService {
    public String greetingsToTheWorld(){
        RandomGreetings greetings = new RandomGreetings();
        return greetings.say() + " World";
    }
}


RandomGreetings.java

package org.example.greetings;

import java.util.Random;

class RandomGreetings {
    public String say() {
        Random rand = new Random();
        int value = rand.nextInt(2);
        return value==0 ? "Hello" : "Hi";
    }
}



Main.java

package org.example;

public class Main {

    public static void main(String[] args) {
        GreetingsService sayHelloService = new GreetingsService();
        System.out.println(sayHelloService.greetingsToTheWorld());
    }
}



正如我向您展示的,此代码无法编译,因为类RandomGreetings是包可见的,这意味着GreetingsService无法实例化它。
可以在类RandomGreetings中公开解决此问题:

public class GreetingsService {
...
}


但是对我来说,RandomGreetings是一种我想保持封装且不公开可见的实现。
在这种情况下,世界(任何导入我可能产生的jar工件的人)都可以看到并调用该类,而这并不是我想要的。

另一个可能的解决方案是将GreetingsService移动到相同的RandomGreetings级别,如下所示:

+-- org.example
    +-- greetings
    |   +-- RandomGreetings
    |   |
    |   +-- GreetingsService
    |
    +-- Main


在这种情况下,代码可以成功编译并且将RandomGreetings封装起来,但是最后我遇到了另一个问题。
我不能再按照逻辑顺序在包中组织该类。
在这种情况下,有几个班级,因此情况仍然可以控制,但是如果班级数量增加,我认为只会有一个独特的大包装。

我知道在Java中没有subpackage visibility,那么如何处理这种情况?
您将如何解决上述代码的问题?

最佳答案

当您要使用软件包时,它必须具有一些入口点,该入口点必须为public。否则,您将无法使用该包装,将其丢弃。这意味着您的org.example.greetings软件包必须包含某些东西,即public,并且可以从“外部”使用/调用它。不必是您的RandomGreetings类。

您可以定义一个接口(在org.example包中),在您的RandomGreetings类中实现该接口,并使用另一个public方法创建并返回“可见的包” RandomGreetings类。代码可能看起来像这样:

package org.example;

public interface Greeting {
    public String say();
}


这由RandomGreetings类实现:

package org.example.greetings;

import org.example.Greeting;

class RandomGreetings implements Greeting {
    // ...
}


然后,定义一个public助手类,以从RandomGreetings包中返回一个org.example.greetings对象:

package org.example.greetings;

import org.example.Greeting;

public GeneratorHelper {
    public static Greeting buildIt() {
         return new RandomGreetings();
    }
}


使用GeneratorHelper.buildIt()方法时,您将获得一些实现Greeting接口的对象。但是您不能访问RandomGreetings类本身,因为它仍然是“包可见的”。

09-26 18:08