0

Currently, I have classes in my module represented by the class diagram below. RestaurantService is a façade interface that is composed of other services like ReservationService and KitchenService. Scope for ReservationService class and KitchenService class is default to hide their visibility from client. From encapsulation perspective this works fine, clients are only aware of RestaurantService and have no knowledge of the internal services. enter image description here

Package Structure

enter image description here

public class RestaurantServiceImpl implements RestaurantService {

   private KitchenService kitchenService;
   private ReservationService reservationService;

   @Override
   public void bookTable(){
      this.reservationService.bookTable();
   }

   @Override
   public OrderDto placeOrder() {
      boolean orderAccepted = this.kitchenService.acceptOrder();
      
      .........
   }

   .........
}

class KitchenService {

   public boolean acceptOrder(){
      .........
   }
}

class ReservationService {

   public void bookTable(){
      .........
   }
}

Now, I want to replace internal service classes with interfaces something like below. enter image description here

With this new design the internal services become public since I can't use protected with Java Interfaces. Therefore, by design there is nothing stopping the client from directly accessing the internal services. Which would lead to two obvious problems:

  1. How will the client know whether it should call bookTable() from RestaurantService or ReservationService.
  2. Leading to fragile code when individual developers decide to call internal service directly rather than using the façade.

So, my question is how to use Java Interfaces for internal services without losing on encapsulation.

I also think this is not a subjective question but more of a design problem for which I am sure there must a design pattern. Therefore, want to learn how you guys handle this in your projects.

Thanks. Looking forward to your inputs.

Meena Chaudhary
  • 9,909
  • 16
  • 60
  • 94
  • @Sweeper scope for internal classes is `default` not protected(corrected it). I have added code and package structure to add more context to my problem. – Meena Chaudhary May 30 '23 at 12:53
  • Interfaces can be `default` (package-private) too? What's the problem with making the interfaces package private? Just don't put an access modifier before `interface`, and make the implementation classes package-private too. – Sweeper May 30 '23 at 13:11
  • @Sweeper with `default` access modifier interface will not be available outside the package for implementation. That means interfaces and implementations have to be in the same package. I think it would go against common design principles. – Meena Chaudhary May 30 '23 at 13:18
  • I see. Have a look at the module system then. You can put everything except the client in the same module, and only export the facade to the client. Look up how to write a module-info.java – Sweeper May 30 '23 at 13:20
  • @Sweeper This can be one of the possible approaches considering we are using Java 9 or later. However, I will be interested to know if there is a general design solutions for such use case without depending on language specific feature. – Meena Chaudhary May 30 '23 at 13:36
  • Umm... what is a "general design solution"? Every solution has to be dependent on language features. Otherwise you can just do all the designing in your head. Before Java 9, this is indeed very difficult to do (I'm not sure how) - package-private is tbh [a rather broken feature](https://stackoverflow.com/a/6470746/5133585), *and that's why Java 9 exists*. And come on, Java 9 was released in 2017, 5 years ago, you should be using it by now. – Sweeper May 30 '23 at 13:42
  • @Sweeper Thanks for sharing the other post gave me a bone to chew for now. – Meena Chaudhary May 30 '23 at 16:21

0 Answers0