0

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

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 作为所有服务的网关。如何限制这种可见性?请指教

4

3 回答 3

1

要做你想做的事,你可以简单地OrderCancellationServiceDrugOrderManager.

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

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

于 2020-07-09T15:51:44.330 回答
1

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

  • 使 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);
}

}

}

在文件 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。

只需将实现设为私有并让接口公开即可。

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

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

在 Java 9 使实现真正私有之前,您可以使用 maven,为所有服务制作接口和实现模块,并且实现模块是接口的运行时依赖项,因此任何对实现的引用都会在编译时失败,但实现会是存在于运行时。

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

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

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

于 2020-07-09T16:40:25.883 回答
0

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

于 2020-07-09T15:52:54.413 回答