可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a group project where we are forced to use interfaces and enumerations provided.
Imagine a situation like 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 an other class, I have a List of Request like this : List<Request> req = new LinkedList<Request>()
What I want to do is : make a switch like below :
switch(a_request){
CASE TYPE1: ....
CASE TYPE2: ....
CASE TYPE3: ....
CASE TYPE2: ....
CASE OTHERTYPE1: ....
CASE OTHERTYPE2: ....
}
How can I manage to do this please ?
IMPORTANT NOTE : I can't add methods into the interfaces and into the enums but I can create new enums that implements the interfaces you can see above. I'd rather not have two enums that do the same thing if possible.
EDIT : It's different to the possible duplicate answer in that I can't add any method in the Request interface and so I can't implement a method in the enum classes.
Thanks in advance
回答1:
The switch you mention does obviously not work.
I have a (quite weird) substitution: create a "helper enum" which contains all values listed, and have a Map<Request<Request<T extends Response>>, HelperEnum>
, like this:
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);
}
(untested! Especially the places where I use Request<T extends Response>
might be wrong; I'd have to test them first. But you should get the idea.)
This way you can then do
switch(HelperEnum.lookUp(a_request)){
case TYPE1: ....
case TYPE2: ....
case TYPE3: ....
case OTHERTYPE1: ....
case OTHERTYPE2: ....
}
回答2:
You could use a map 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();
回答3:
In case you have a behaviour, where e.g. a Request
could trigger several enumerated actions, or individual actions' implementations differ greatly from other actions, so you need a more flexible solution, you could go that way:
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's 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 the action fits a given request, is configurable by a filter Predicate
and the action by a Consumer
.
回答4:
Unfortunately, you can't use switch
for your actual code, but you can do this using if
statement:
final List<Request> req = new LinkedList<>();
for (Request request : req) {
if (TypeAction.TYPE1.equals(request)) {
//code
}
else if (OtherTypeAction.OTHERTYPE1.equals(request)) {
//code
}
}
Maybe you can add more field to request and enums, and then you can equals this filed.