Java switch on enumeration that implements the same interface

I have a group project in which we are forced to use interfaces and enumerations.

Imagine the situation as shown below:

// marker interface interface Request<T extends Response>{} // marker interface interface Response{} enum TypeAction implements Request<SomeEnumClassThatImplementsResponse>{ TYPE1, TYPE2, TYPE3 } enum OtherTypeAction implements Request<SomeOtherEnumClassThatImplementsResponse>{ OTHERTYPE1, OTHERTYPE2 } 

In another class, I have a list of queries like: List<Request> req = new LinkedList<Request>() I want to do the following: create a switch, as shown below:

 switch(a_request){ CASE TYPE1: .... CASE TYPE2: .... CASE TYPE3: .... CASE TYPE2: .... CASE OTHERTYPE1: .... CASE OTHERTYPE2: .... } 

How can I do it?

IMPORTANT NOTE: I cannot add methods to interfaces or enumerations, but I can create new enumerations that implement the interfaces that you can see above. I would prefer not to have two enumerations that do the same, if possible.

EDIT:. This differs from a possible duplicate answer in that I cannot add any method to the request interface, and therefore I cannot implement the method in enumeration classes.

Thank you in advance

+5
source share
4 answers

The switch you specified is clearly not working.

I have a (rather strange) substitution: create a โ€œhelper enumerationโ€ that contains all the listed values โ€‹โ€‹and has a Map<Request<Request<T extends Response>>, HelperEnum> , for example:

 private enum HelperEnum { TYPE1(TypeAction.TYPE1), TYPE2(TypeAction.TYPE2), TYPE3(TypeAction.TYPE3), OTHERTYPE1(OtherTypeAction.OTHERTYPE1), OTHERTYPE2(OtherTypeAction.OTHERTYPE2), private Request<T extends Response> source; private HelperEnum(Request<T extends Response> source) { this.source = source; } private static Map<Request<T extends Response>, HelperEnum> map; public static HelperEnum lookUp(Request<SomeEnumClassThatImplementsResponse> source) { if (map == null) { map = Arrays.stream(HelperEnum.values()) .collect(Collectors.toMap(x -> x.source, x -> x)); } return map.get(source); } 

(unverified! Especially the places where I use Request<T extends Response> may be wrong, I have to test them first, but you should get this idea.)

So you can do

 switch(HelperEnum.lookUp(a_request)){ case TYPE1: .... case TYPE2: .... case TYPE3: .... case OTHERTYPE1: .... case OTHERTYPE2: .... } 
+4
source

You can use a card instead of a switch:

 interface MyRequestTypeAction{ void doSomething(); } Map<Request, MyRequestTypeAction> requestActions = new HashMap<>(){{ put(TypeAction.TYPE1,()->System.out.printLine("TypeAction.TYPE1")); put(TypeAction.TYPE2,()->System.out.printLine("TypeAction.TYPE2")); put(TypeAction.TYPE3,()->System.out.printLine("TypeAction.TYPE3")); put(OtherTypeAction.OTHERTYPE1,()->System.out.printLine("OtherTypeAction.OTHERTYPE1")); put(OtherTypeAction.OTHERTYPE2,()->System.out.printLine("OtherTypeAction.OTHERTYPE2")); }} requestActions.get(a_request).doSomething(); 
+4
source

Unfortunately, you cannot use switch for your actual code, but you can do it with the if :

 final List<Request> req = new LinkedList<>(); for (Request request : req) { if (TypeAction.TYPE1.equals(request)) { //code } else if (OtherTypeAction.OTHERTYPE1.equals(request)) { //code } } 

Perhaps you can add another field for query and listing, and then you can equal this element.

+1
source

If you have a behavior where, for example, a Request can initiate several of the listed actions or the implementation of individual actions is very different from other actions, so you need a more flexible solution, you can go as follows:

 public enum RequestHandlers { TYPE1_HANDLER(TypeAction.TYPE1::equals, Request::methodA), TYPE2_HANDLER(r -> r == TypeAction.TYPE2), OTHERTYPE1_HANDLER(OtherTypeAction.OTHERTYPE1::equals), COMMON_HANDLER(x -> true, MyLogger::trace); private final Predicate<Request<?>> requestFilter; // selects supported requests for this handler private final Consumer<Request<?>> consumer; // implements this handler behaviour private RequestHandlers(Predicate<Request<?>> p, Consumer<Request<?>> consumer) { this.requestFilter = p; this.consumer = consumer; } private RequestHandlers(Predicate<Request<?>> p) { this.requestFilter = p; this.consumer = Request::methodB; // default behaviour for all handlers } public static void handle(Request<?>... requests) { Arrays.stream(RequestHandlers.values()) .forEach(handler -> Arrays.stream(requests) .filter(handler.requestFilter) .forEach(request -> handler.consumer.accept(request))); } } 

Note that the criteria when an action matches a given query are configured by the Predicate filter and the Consumer action.

+1
source

Source: https://habr.com/ru/post/1263430/


All Articles