2010-11-11 3 views
0

Est-il possible en Java de créer une méthode/classe d'usine statique qui utilise une interface comme type paramétré et renvoie une classe d'implémentation de cette interface donnée?Java statique paramétrée usine statique générique

Bien que ma connaissance de Generics est limité, voici ce que je veux faire:

// define a base interface: 
public interface Tool { 
    // nothing here, just the interface. 
} 

// define a parser tool: 
public interface Parser extends Tool { 
    public ParseObject parse(InputStream is); 
} 

// define a converter tool: 
public interface Converter extends Tool { 
    public ConvertObject convert(InputStream is, OutputStream os); 
} 

// define a factory class 
public class ToolFactory { 
    public static <? extends Tool> getInstance(<? extends Tool> tool) { 
     // what I want this method to return is: 
     // - ParserImpl class, or 
     // - ConverterImpl class 
     // according to the specified interface. 
     if (tool instanceof Parser) { 
      return new ParserImpl(); 
     } 
     if (tool instanceof Converter) { 
      return new ConverterImpl(); 
     } 
    } 
} 

Je veux limiter le code client seulement insérer une interface « type » dans la méthode getInstance() qui se prolonge à partir de l'interface d'outil que j'ai spécifiée. De cette façon, je sais avec certitude que le type d'outil inséré est un outil légitime.

code client devrait ressembler à ceci:

public class App { 
    public void main(String[] args) { 

     Parser parser = null; 
     Converter converter = null; 

     // ask for a parser implementation (without knowing the implementing class) 
     parser = ToolFactory.getInstance(parser); 

     // ask for a converter implementation 
     converter = ToolFactory.getInstance(converter); 

     parser.parse(...); 
     converter.convert(... , ...); 
    } 
} 

L'usine doit passer sur le type de l'interface (négligente si elle est nulle ou non), défini avant demande de l'usine. Je sais que cela ne fonctionnera pas comme je l'ai écrit, mais j'espère que l'un des lecteurs sait ce que je veux accomplir. Le type de retour de la méthode getInstance est le même que le paramètre entrant. Ainsi, lorsqu'une interface Parser est transmise, elle renvoie également un analyseur Parser p = new ParserImpl(); retour p;

Merci d'avance de votre aide.

Répondre

6

Quelques choses:

  1. Votre usine devrait presque certainement prendre une classe à instancier, plutôt qu'un objet outil . Avoir quelqu'un créer un Parser pour passer dans votre méthode afin d'obtenir un Parser est un peu de poulet et d'oeuf.
  2. Je ne sais pas si vous êtes autorisé à avoir des paramètres génériques pour les méthodes qui sont des caractères génériques; Je ne présume pas puisque cela serait absurde et inutile. Lorsque vous paramétrez une méthode, vous devez donner un nom au paramètre générique afin que vous puissiez y faire référence plus tard.

Mettre ces ensemble, votre méthode d'usine pourrait ressembler à ceci:

public static <T extends Tool> T getInstance(Class<T> toolClass) { 
    if (Parser.class.isAssignableFrom(toolClass) { 
     return new ParserImpl(); 
    } 
    else if (Converter.class.isAssignableFrom(toolClass) { 
     return new ConverterImpl(); 
    } 

    // You'll always need to have a catch-all case else the compiler will complain 
    throw new IllegalArgumentException("Unknown class: " + toolClass.getName()); 
} 

Si vous souhaitez restreindre le type de toolClass être une interface, vous ne pouvez pas le faire à la compilation , mais vous pouvez bien sûr introduire un contrôle d'exécution toolClass.isInterface(). Par ailleurs, cette commutation statique codée en dur n'est pas très agréable en général. À mon avis, il serait plus agréable de mettre la relation classe-constructeur dans un Map et de rechercher dynamiquement le processus de construction. Peut-être même stocker la valeur comme Callable<? extends Tool> et ajouter une méthode protégée permettant aux autres classes d'enregistrer les mappages. Cela ne veut pas dire que votre version actuelle ne fonctionne pas, mais qu'elle ne s'adapte pas très bien, et pour le moment, je ne pense pas que cela justifie d'avoir une usine distincte plutôt que d'appeler simplement l'appelant. toolClass.newInstance() eux-mêmes.

+0

C'est exactement la façon de le faire. –

+0

Merci pour votre réponse. D'une manière ou d'une autre, je n'arrive pas à ce que cela fonctionne comme je l'avais en tête ... Pourriez-vous s'il vous plaît élaborer sur les appels du code client et le Callable suggestion?Je vais ignorer le mappage car l'application ne dispose que de quelques outils et ne s'étend pas au-delà. – user504342

Questions connexes