2017-07-31 20 views
3

在Java 8上運行的Spring Boot應用程序中,我想實現通用行爲來處理不同類型的命令。Java 8流和責任鏈中的通用接口

下面的代碼說明了我想到的解決方案。

的通用處理器圖案

public interface Processor<C extends Command> { 
    TypeCommand getCommandType(); 
    void processCommand(C command); 
} 

public abstract class AbstractProcessor<C extends Command> implements Processor<C> { 
    @Override 
    public void processCommand(C command) { 
     // Some common stuff 
     // ... 

     // Specific process 
     Result result = executeCommand(command); 

     // More common stuff 
     // ... 
    } 

    protected abstract Result executeCommand(C command); 
} 

@Component 
public AddCommandProcessor extends AbstractProcessor<AddCommand> { 

    @Override 
    protected Result executeCommand(AddCommand addCommand) { 
     // Execute command 
     // ... 
     return result; 
    } 

    @Override 
    public TypeCommand getCommandType() { 
     return TypeCommand.ADD_COMMAND; 
    } 
} 

的命令:

public abstract class Command { 
    private final String uid; 
    private final LocalDateTime creationDate; 
    private final TypeCommand type; 
    // Constructor and getters omited ... 
} 

public class AddCommand extends Command { 
    private final Double amount; 
    // Constructor and getters omited ... 
} 

與責任鏈的服務:

@Service 
public class MyService { 

    private final List<Processor<? extends Command>> processors; 

    @Autowired 
    public MyService(final List<Processor<? extends Command>> processors) { 
     this.processors = processors; 
    } 

    public void processCommand(final Command command) { 
     processors.stream() 
      .filter(p -> command.getType() == p.getCommandType()) 
      .findFirst() 
      .ifPresent(processor -> processor.processCommand(command)); 
    } 
} 

不幸的是,該代碼不能編譯。行:

.ifPresent(processor -> processor.processCommand(command)); 

失敗的消息彙總:

processCommand(capture <? extends Command>) in Processor cannot be applied to (Command) 

我沒有看到任何其他的方式來做到這一點的預期。我錯在哪裏?

非常感謝。

+3

更改'private final List >處理器;'到'私人最終名單<處理器>處理器;'如果你可以https://stackoverflow.com/questions/5857561/java-generics-fancy-capture-collision –

+5

[什麼是PECS(生產者擴展消費者超級)?](https://stackoverflow.com/q/2723397/2711488) – Holger

+0

更改'私人最終列表<處理器<?擴展命令>>處理器;'到'私有最終列表<處理器>處理器;'編譯,但然後Spring不會將處理器的實現注入到集合中:'( – CrakBoom

回答

1

您應該能夠放棄仿製藥上Processor<? extends Command> processor逼到Processor processor這將改變誤差爲約原料類型的警告,你可以用@SuppressWarnings("rawtypes")

.ifPresent(processor -> ((Processor) processor).processCommand(command)); 

另一種方法靜音是使processCommand通用和向上轉型Processor<? extends Command> processor的泛型類型,像這樣:

public <C extends Command> void processCommand(final C command) { 
    processors.stream() 
     .filter(p -> command.getType() == p.getCommandType()) 
     .findFirst() 
     .map(processor -> (Processor<C>) processor) 
     .ifPresent(processor -> processor.processCommand(command)); 
} 

,這將給你一個關於一個unchecked鑄警告,你可以用靜音。

這兩種方法都將拋出ClassCastException如果Command返回一個特定TypeCommand不是類型的子類,(第一)Processor返回同一TypeCommand預計(例如,如果SubCommand返回TypeCommand.ADD_COMMAND,但並不AddCommand的子類)。

+0

這兩種方法都可以工作。'ClassCastException'在這裏不是問題,我只有一個'Command'實現,它由'TypeCommand'的值。 ! – CrakBoom