2017-01-27 2 views
5

У меня есть групповой проект, где мы вынуждены использовать интерфейсы и перечисления.Java-переключатель на перечислении, который реализует тот же интерфейс

Представьте себе ситуацию, как показано ниже:

// 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  
} 

В другом классе, у меня есть список запроса, как это: List<Request> req = new LinkedList<Request>() То, что я хочу сделать, это: сделать переключатель, как показано ниже:

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

Как я могу это сделать, пожалуйста?

ВАЖНОЕ ЗАМЕЧАНИЕ: Я не могу добавлять методы в интерфейсы и в перечисления, но я могу создать новые перечисления, которые реализуют интерфейсы, которые вы можете видеть выше. Я бы предпочел не иметь двух перечислений, которые делают то же самое, если это возможно.

EDIT: Это отличается от возможного дублирующего ответа тем, что я не могу добавить какой-либо метод в интерфейс запроса, и поэтому я не могу реализовать метод в классах перечисления.

Заранее спасибо

+1

В принципе, вы не можете. Просто используйте 'if' вместо этого. – shmosel

+3

Возможный дубликат [оператора switch для совместного использования классов enum в Java] (http://stackoverflow.com/questions/13958754/switch-statement-for-a-joint-of-different-enum-classes-in- java) – shmosel

+1

@MichaelCurry Как вы «реализуете» перечисление? Вы можете реализовать только интерфейсы. – glglgl

ответ

4

Указанный вами переключатель явно не работает.

У меня есть (довольно странно) замена: создать «вспомогательное перечисление», который содержит все значения, перечисленных и имеет Map<Request<Request<T extends Response>>, HelperEnum>, как это:!

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

(непроверенные Особенно те места, где я использую Request<T extends Response> может быть неправильным,.. Я должен проверить их первые Но вы должны получить идею)

Таким образом, вы можете сделать

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

Хорошая идея. Просто замечание: ОП имеет две отличные перечисления. Поэтому он не должен использовать 'SomeEnumClassThatImplementsResponse', но общий предок перечислений:' Request ' – davidxxx

+0

@davidxxx Спасибо, что указали это. Я изменил это. – glglgl

1

К сожалению, вы не можете использовать switch для реального кода, но вы можете сделать это, используя if заявление:

final List<Request> req = new LinkedList<>(); 

for (Request request : req) { 
    if (TypeAction.TYPE1.equals(request)) { 
     //code 
    } 
    else if (OtherTypeAction.OTHERTYPE1.equals(request)) { 
     //code 
    } 
} 

Может быть, вы можете добавить еще поле для запроса и перечислений , а затем вы можете равняться этой поданной.

4

вы можете использовать карта вместо коммутатора:

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(); 
1

В случае, если у вас есть поведение, например. Request может вызвать несколько перечисляемых действий или реализации отдельных действий существенно отличаются от других действий, так что вам нужно более гибкое решение, вы могли бы пойти по этому пути:

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

Следует отметить, что критерии, когда действие приспосабливает данный запрос, настраивается фильтром Predicate и действием Consumer.

Смежные вопросы