如何限制 class 在不同包中的另一个 class 中的可见性?

How to restrict a class visibility in another class only that are in different packages?

我的项目中有以下包和class结构,

package de.mycompany.jakarta.order;
import de.mycompany.ordermanagement.order.OrderCancellationService;
public class DrugOrderManager {
private static final DrugOrderManager INSTANCE = new DrugOrderManager();

private DrugOrderManager() {
}

public static DrugOrderManager getInstance() {
    return INSTANCE;
}

public void cancelOrder() {
    OrderCancellationService.getInstance().process();
}   }



package de.mycompany.ordermanagement.order;
public class OrderCancellationService {
private static OrderCancellationService INSTANCE = new OrderCancellationService();

private OrderCancellationService() {
}

public static OrderCancellationService getInstance() {
    return INSTANCE;
}

public void process() {
    
}   }

我的意图是 OrderCancellationService 应该只由 DrugOrderManager 调用,任何其他 class/service 的 none 应该直接调用它。我正在尝试将 DrugOrderManager 作为所有服务的网关。我如何限制这种可见性?请指教

要执行您想要的操作,您只需在 DrugOrderManager.

中将 OrderCancellationService 创建为私有静态 class

但在你的情况下,我想你会有更多类似于 OrderCancellationService 的 classes - 所以将所有这些 classes 放在一个包中并且只制作 DrugOrderManager public,同时将所有其他服务打包为私有,可能是更好的方法。您只为消费者公开一个入口点,它易于管理且易于理解代码。

如果你不能移动 classes 那么我想 Java 中没有解决方案。

您可以尝试将 OrderCancellationService 定义为 DrugOrderManager 中的私有 class,也许这会如您所愿....

有几种明显但不好的方法:

  • 在 DrugOrderManager
  • 中将 OrderCancellationService 设为私有 classe
  • 将 OrderCancellationService 和 DrugOrderManager 放在同一个包中

另一种解决方案是使用另一个 class,它将访问所有实例,并将它们转发给正确的实现。只有 class 才能访问所有内容。服务本身只能访问公共 class 提供的内容。这远非完美,还有一个“神”对象,但仅限于一个对象,没有更多的包限制。

这是一个示例,其中 Factory 是具有所有实例和 2 个服务(ServiceA 和 ServiceB)的对象。 ServiceB 可以访问 ServiceA,但 ServiceA 不能访问 ServiceB。

在文件 Factory.java 中:

class Factory {
  private static Map<Class, Object> INSTANCES = new HashMap<>();
  private ServiceA serviceA;
  private ServiceB serviceB;

  public static void register(Class clazz, Object instance) {
    instances.put(clazz, instance);
  }



static {
  Class.forName("ServiceA");
  Class.forName("ServiceB");


  serviceA = (ServiceA)(INSTANCES.get(ServiceA.class));
  serviceB = (ServiceB)(INSTANCES.get(ServiceB.class));
  
  serviceB.setServiceA(serviceA);
}

}

}

在文件 ServiceA.java 中:

class ServiceA {
  private ServiceA INSTANCE = new ServiceA();

  private ServiceA() {}

  static {
    Factory.register(ServiceA.class, INSTANCE);
  }
}

在文件 ServiceB.java 中:

class ServiceB {
  
  private ServiceB INSTANCE = new ServiceB();
  private ServiceA serviceA;

  private ServiceB() {}
  
 
  public setServiceA(ServiceA serviceA) {
    this.serviceA = serviceA;
  }
  static {
    Factory.register(ServiceB.class, INSTANCE);
  }
}

反射也可能实现其他实现 API。

只需将实现设为私有,让接口设为public。

对我来说,你想要达到的目标是不值得的。

很容易做到的是至少使所有实现完全私有,并且由于 Java 9 个模块,只有 public 服务的入口点可通过接口访问。由于任何服务在其外观中通常只有几个 public 方法,因此它提供了 95% 的功能,而没有令人讨厌的技巧。当然服务可以看到每个 ither public 接口,但他们甚至无法访问私有实现。

在 Java9 之前,要使实现真正私有化,您可以使用 maven,为所有服务创建接口和实现模块,并且实现模块是接口的运行时依赖项,因此对实现的任何引用都会在编译时失败,但在运行时会出现 implem。

服务定位器模式,依赖注入 & Spring

您可以将我的示例视为我们通常所说的服务定位器或依赖项注入概念的非常粗略的实现。

Spring (https://spring.io/) 是 Java 世界的事实标准。你应该在网上检查一些 tutos/training 看看它能做什么。