3

Je développais une classe simple, appelée Simulator, qui applique une liste de Simulation à une entrée donnée. Pour chaque entrée, les simulations peuvent produire une sortie ou non, en fonction de certaines conditions que l'entrée doit remplir pour chaque simulation. Le résultat produit par le Simulator est une liste de sortie.Clavier d'informations et style de codage de programmation fonctionnelle

Voici le code.

class Simulator { 
    final List<Simulation> simulations; 

    // Some initialization code... 

    List<Ouput> execute(Input input) { 
     return simulations 
      .stream() 
      .filter(s -> s.processable(input)) 
      .map(s -> s.prepareOutput(input)) 
      .collect(Collectors.toList()); 
    } 
} 

Comme vous pouvez le voir, d'abord, je vérifie si une entrée est traitable par un Simulation, filtrage des simulations pour lesquelles il n'est pas, et l'application de ces simulations à l'entrée. D'un point de vue orienté objet, j'expose des classes internes de Simulation. L'opération de vérification effectuée par la méthode processable doit être masquée dans la méthode prepareOutput.

Cependant, ayant processable visible à Simulator, je peux appliquer une approche plus fonctionnelle, ce qui est très pratique.

Quelle approche est la meilleure? Y a-t-il d'autres solutions qui me manquent?

+2

Si vous pensez que vous exposer des internes, alors pourquoi le faites-vous alors? Quelques autres questions à se poser: Que se passe-t-il si j'appelle l'une de vos simulations avec 'someSimulation.prepareOutput (null)'? Est-ce que c'est même possible? Ou que se passe-t-il si j'appelle 'prepareOutput' avec un paramètre d'entrée qui n'est pas traitable par une simulation donnée? Ai-je besoin de savoir ou de vérifier sa capacité de traitement de l'extérieur? Est-ce qu'il retourne «null» ou lance-t-il une exception? Est-ce que 'Optional 'est une option? – Roland

Répondre

4

Depuis votre classe Simulation expose déjà l'opération prepareOutput, qui peut échouer, il n'y a pas d'exposition supplémentaire lorsque vous offrez la méthode processable pour détecter à l'avance, si l'opération prepareOutput échouerait. En fait, c'est une bonne conception de l'API d'offrir un tel contrôle, tant qu'il n'est pas trop coûteux à calculer à l'avance.

Vous pouvez toujours envisager d'offrir l'opération de traitement en bloc au sein de la classe Simulation.

public class Simulation { 
    public Output prepareOutput(Input input) { 
     … 
    } 
    public static List<Output> prepareWhenPossible(List<Simulation> list, Input input) { 
     return simulations.stream() 
      .filter(s -> s.processable(input)) 
      .map(s -> s.prepareOutput(input)) 
      .collect(Collectors.toList()); 
    } 
} 

Il est important de préciser à l'appelant qu'il sautera éléments pour lesquels l'opération n'est pas possible, au lieu de mettre en œuvre un comportement « tout ou rien ».

Cela n'exclut pas encore d'exposer processable, si son implémentation est peu coûteuse. Ce n'est pas comme si c'était une opération par ailleurs impossible, car il est toujours possible de simplement appeler prepareOutput et de laisser tomber le résultat pour savoir si l'opération est possible. Avoir une méthode processable à cet effet est beaucoup plus propre.

+0

Je pense que vous rencontrez le problème: si la méthode 'processable' est disponible pour d'autres types, il est important que la méthode' prepareOutput' l'invoque en interne. Dans cette perspective, 'prepareOutput' devrait renvoyer un' 'optionnel de toute façon. –

1

Si vous avez besoin de se cacher processable, pourquoi ne pas le faire un peu différent:

Optional<Output> prepareOutput(Input input) { 

     boolean isProcessable = processable(input); // processable is private 

     if(isProcessable){ 
      // prepare Output 
      return Optional.of(Output); 
     } 
     return Optional.empty(); 

} 

Et puis quelque chose comme ceci:

List<Ouput> execute(Input input) { 
    return simulations 
     .stream() 
     .map(s -> s.prepareOutput(input)) 
     .filter(Optional::isPresent) 
     .map(Optional::get) 
     .collect(Collectors.toList()); 
} 
+1

Mais cela ne cache que «processable» techniquement, pas sémantiquement, car tout le monde pourrait écrire une méthode 'boolean traitable (Simulation s, Input i) {return s.prepareOutput (i) .isPresent(); } ', donc tout ce qui se cache' processable' atteint, rend ce test potentiellement moins efficace. – Holger

+1

@Holger merci, bon point. Je pensais que c'était juste de cacher cette seule méthode. plus un pour votre réponse pour le traitement en bloc .. – Eugene