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

Java 如何仅在不同包中的另一个类中限制类的可见性?,java,package,java-6,java-package,Java,Package,Java 6,Java Package,我的项目中有以下包和类结构 package de.mycompany.jakarta.order; import de.mycompany.ordermanagement.order.OrderCancellationService; public class DrugOrderManager { private static final DrugOrderManager INSTANCE = new DrugOrderManager(); private DrugOrderManager()

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

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调用,任何其他类/服务都不应该直接调用它。我试图使DrugOrderManager成为所有服务的网关。如何限制此可见性?请建议

若要执行所需操作,只需在
DrugOrderManager
中创建
OrderCancellationService
作为私有静态类即可

不过,在您的情况下,我想您将有更多类似于
OrderCancellationService
的类-因此,将所有这些类放在一个包中,只将
DrugOrderManager
公开,而将所有其他服务包私有,可能是更好的方法。您只为消费者公开一个入口点,它易于管理并且易于理解代码


如果您不能移动类,那么我想Java中没有解决方案。

要想做您想做的事情,您只需在
DrugOrderManager
中创建
OrderCancellationService
作为私有静态类

不过,在您的情况下,我想您将有更多类似于
OrderCancellationService
的类-因此,将所有这些类放在一个包中,只将
DrugOrderManager
公开,而将所有其他服务包私有,可能是更好的方法。您只为消费者公开一个入口点,它易于管理并且易于理解代码


如果您不能移动类,那么我猜Java中没有解决方案。

您可以尝试在DrugOrderManager中将OrderCancellationService定义为私有类,也许这会如您所期望的那样起作用….

您可以尝试在DrugOrderManager中将OrderCancellationService定义为私有类,也许这会像你期望的那样起作用……

有几种明显而糟糕的方法可以做到这一点:

  • 使OrderCancellationService成为DrugOrderManager中的私有类
  • 将OrderCancellationService和DrugOrderManager放在同一个包中
另一个解决方案是使用另一个类,该类将访问所有实例,并将它们转发给适当的实现。只有那个类才能访问所有内容。服务本身只能访问该公共类所提供的内容。这远不是完美的,仍然有一个“上帝”对象,但这仅限于一个对象,并且对包没有更多的限制

下面是一个示例,其中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);
}

}
在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也可能实现其他实现

只需将实现私有化,并将接口公开即可。

对我来说,你想要达到的目标不值得付出努力

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

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

服务定位器模式、依赖注入和Spring

您可以将我的示例视为我们通常称之为服务定位器或依赖注入概念的非常粗糙的实现


Spring()实际上是Java世界中的标准。你应该在网上查看一些全套短裙/训练,看看它能做些什么。

有几种明显和不好的方法可以做到这一点:

  • 使OrderCancellationService成为DrugOrderManager中的私有类
  • 将OrderCancellationService和DrugOrderManager放在同一个包中
另一个解决方案是使用另一个类,该类将访问所有实例,并将它们转发给适当的实现。只有那个类才能访问所有内容。服务本身只能访问该公共类所提供的内容。这远不是完美的,仍然有一个“上帝”对象,但这仅限于一个对象,并且对包没有更多的限制

下面是一个示例,其中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);
}

}
在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也可能实现其他实现

只需将实现私有化,并将接口公开即可。

对我来说,你想要达到的目标不值得付出努力

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

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