简体   繁体   English

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

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

I have the following package and class structure in my project,我的项目中有以下 package 和 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() {
    
}   }

My intention is that the OrderCancellationService should be only called by the DrugOrderManager and none of any other class/service should call it directly.我的意图是 OrderCancellationService 应该只由 DrugOrderManager 调用,任何其他类/服务都不应该直接调用它。 I am trying to make DrugOrderManager as a gateway to all the services.我正在尝试将 DrugOrderManager 作为所有服务的网关。 How do I restrict this visibility?如何限制这种可见性? Please advise请指教

To do what you want, you can simply create OrderCancellationService as private static class inside DrugOrderManager .要做你想做的,你可以简单地在 DrugOrderManager 中创建OrderCancellationService作为私有 static DrugOrderManager

In your case though, I imagine you will have more similiar classes to OrderCancellationService - so putting all those classes in a single package and making only DrugOrderManager public, while making all other services package-private, may be a better approach.不过,在您的情况下,我想您将有更多与OrderCancellationService类似的类 - 因此将所有这些类放在一个 package 中并仅公开DrugOrderManager ,同时将所有其他服务包私有,可能是更好的方法。 You expose only single entrypoint for the consumer, it's manageable and easy to understand the code.您只为消费者公开单个入口点,它易于管理且易于理解代码。

If you can't move the classes then I guess there is no solution in Java.如果您不能移动课程,那么我想 Java 中没有解决方案。

There several obvious and bad ways to do that:有几种明显和不好的方法可以做到这一点:

  • make OrderCancellationService a private classe inside DrugOrderManager使 OrderCancellationService 成为 DrugOrderManager 中的私有类
  • put OrderCancellationService & DrugOrderManager in same package将 OrderCancellationService 和 DrugOrderManager 放在同一个 package

Another solution is to use another class, that will get access to all the instances, and will forward them to the proper implementation.另一种解决方案是使用另一个 class,它将访问所有实例,并将它们转发给正确的实现。 Only that class would get access to everything.只有 class 才能访问所有内容。 The services themselve would only get access to what that common class provide them.服务本身只能访问常见的 class 提供的内容。 This is far from perfect, there still a "god" object, but this is limited to one object and there no more limitation on packages.这远非完美,还有一个“神”object,但这仅限于一个object,并且对封装没有更多限制。

Here is an example where Factory is the object that has all instances and 2 services, ServiceA and ServiceB.这是一个示例,其中 Factory 是 object,它具有所有实例和 2 个服务,ServiceA 和 ServiceB。 ServiceB has access to ServiceA, but ServiceA doesn't have access to ServiceB. ServiceB 有权访问 ServiceA,但 ServiceA 无权访问 ServiceB。

In file Factory.java:在文件 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);
}

}

} }

In File ServiceA.java:在文件服务A.java 中:

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

  private ServiceA() {}

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

In File ServiceB.java:在文件服务 B.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);
  }
}

Other implementations are also likely possible with reflexion API.反射 API 也可能实现其他实现。

Just make the implementation private and let the interface be public.只需将实现设为私有并让接口公开即可。

To me what you are trying to achieve is not worth the effort.对我来说,你想要达到的目标是不值得的。

What is quite easy to do is to at least make ALL implementation fully private and only have the public entry point of the service available through interfaces thanks to Java 9 modules.由于 Java 9 个模块,很容易做到的是至少使所有实现完全私有,并且仅通过接口提供服务的公共入口点。 As any service is typically only a few public method in its facade, this provide 95% of the feature without nasty tricks.由于任何服务通常只是其外观中的几个公共方法,这提供了 95% 的功能而没有讨厌的技巧。 Sure service can see each ither public interface, but they have no way to even access the private implementation.当然服务可以看到每个公共接口,但他们甚至无法访问私有实现。

Before Java 9 to make an implementation really private, you can use maven, make interface & implementation modules for all services, and the implementation module be a runtime dependency to the interface so any ref to impletation would fail at compile time but the implem would be present at runtime.在 Java 9 使实现真正私有之前,您可以使用 maven,为所有服务制作接口和实现模块,并且实现模块是接口的运行时依赖项,因此任何对实现的引用都会在编译时失败,但实现将是在运行时出现。

Service Locator Pattern, Dependency Injection & Spring服务定位器模式、依赖注入和 Spring

You can see my example as very crude implementation of what we often call a Service Locator or the concept of dependency injection.您可以将我的示例视为我们通常称为服务定位器或依赖注入概念的非常粗略的实现。

Spring ( https://spring.io/ ) is the de facto standard for that in the Java world. Spring ( https://spring.io/ ) 是 Java 世界的事实标准。 You should check a few tutos/training on the net to see what it can do.您应该在网上查看一些 tutos/training,看看它可以做什么。

You could try to define OrderCancellationService as a private class inside DrugOrderManager, maybe this will work as your expectation....您可以尝试在 DrugOrderManager 中将 OrderCancellationService 定义为私有 class,也许这会如您所愿......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM