2010-06-07 6 views
3

Je souhaite définir une classe de base qui définit une méthode principale qui instancie la classe et exécute une méthode. Il y a quelques problèmes cependant. Voici la classe de base:Héritage de la méthode principale

public abstract class Strategy 
{ 
    abstract void execute(SoccerRobot robot); 

    public static void main(String args) 
    { 
     Strategy s = new /*Not sure what to put here*/(); 
     s.execute(new SoccerRobot()) 
    } 
} 

Et voici un exemple classe dérivée:

public class UselessStrategy 
{ 
    void execute(SoccerRobot robot) 
    { 
     System.out.println("I'm useless") 
    } 
} 

Il définit d'une simple méthode execute, qui devrait être appelé dans une méthode principale lors de l'utilisation en tant que l'application principale . Cependant, pour ce faire, j'ai besoin d'instancier la classe dérivée à partir de la méthode principale de la classe de base. Ce qui ne semble pas possible. Je préférerais ne pas avoir à répéter la méthode principale pour chaque classe dérivée, car elle semble quelque peu déséquilibrée.

Existe-t-il une bonne façon de procéder?

+0

Votre conception semble un peu en arrière. Cela n'aurait-il pas plus de sens d'instancier un 'SoccerRobot' avec une stratégie particulière? –

+0

SoccerRobot représente les propriétés physiques du robot, pas l'application elle-même. Il fournit un contrôle de haut niveau du robot (navigateTo, getBallAngle, etc.). Donc, je ne pense pas que cela devrait tenir la stratégie. – Eric

Répondre

7

Déplacer la principale méthode dans une classe à part. préoccupations distinctes
stratégie (le nom dit tout)
lanceur (assemblage de composants ensemble et déclenchement d'exécution)

public class Launcher 
{ 
    public static void main(String args) 
    { 
     Strategy s = new UselessStrategy(); 
      //OR Strategy s = CreateInstance(args[0]) ; 
      //OR equiv mechanism for Dependency Injection if you don't want to hardcode the derived strategy to use. 
     s.execute(new SoccerRobot()) 
    } 
} 
1

Vous ne pouvez pas instancier une classe abstraite, mais vous pouvez certainement instancier une classe dérivée à partir de la classe de base. Il suffit donc de supprimer abstraite de la définition de la classe

public class UselessStrategy 

et faire

Strategy s = new UselessStrategy(); 
+0

Cette première erreur était une copie-et-coller-o. Et j'aimerais que la méthode principale de la classe de base fonctionne si je devais dériver une autre classe de Stratégie, disons «Stratégie utile». Je voudrais que la méthode principale sache d'une manière ou d'une autre de quelle classe on l'appelle, et instancie cette classe. – Eric

+0

La méthode principale de la classe de base ne "fonctionne" pour aucune classe dérivée, seulement pour elle-même, comme toute autre méthode statique. Mais puisque les gens ont inventé les paramètres de la ligne de commande, il n'y a pas vraiment besoin d'avoir plusieurs méthodes principales dans votre cas. Utilisez les paramètres comme une entrée pour l'usine pour créer vos stratégies. – unbeli

3

méthodes statiques telles que le « principal », ne sont pas héritées, mais peuvent être appelés directement. Pour contourner ce problème, vous pouvez paramétrer le nom de classe comme argument à la méthode principale:

public static void main(String args) throws Exception 
{ 
    String className = (args.length > 0) ? args[0] : 'UselessStrategy'; 
    Strategy s = (Strategy) Class.forName(className).newInstance(); 
    s.execute(new SoccerRobot()) 
} 

Si Class.forName est impossible, le maintien d'une cartographie des noms de classe peuvent fournir une table de consultation, par le commentaire de Andreas_D:

private static Map<String, Class<? extends Strategy>> STRATEGY_NAME = 
    new HashMap<String, Class<? extends Strategy>>(); 

static { 
    STRATEGY_NAME.put("Useless", UselessStrategy.class); 
    STRATEGY_NAME.put("Better", BetterStrategy.class); 
} 

public static void main(String args[]) throws Exception { 
    String className = (args.length > 0) ? args[0] : null; 
    Class<? extends Strategy> klass = STRATEGY_NAME.get(className); 
    if (klass == null) klass = UselessStrategy.class; 
    Strategy s = klass.newInstance(); 
    s.execute(); 
} 

Des méthodes automatisées pour maintenir la cartographie pourraient être conçues, telles que l'utilisation de la réflexion, si le besoin s'en fait sentir.

+0

'Class.forName' est un no-go sur ma plate-forme. – Eric

+0

C'est plus qu'une solution de contournement, pour moi, c'est LA solution. –

+0

'Class.forName' n'est pas nécessaire, il existe d'autres façons de mapper une clé transmise avec le vecteur d'argument à une classe concrète. –

0

D'où provient la principale méthode? S'il prend des arguments, alors vous pouvez décider d'une stratégie concrète basée sur ces arguments, instancier cette classe de stratégie et appeler la méthode execute dessus.

+0

La méthode 'main' est appelée lors de l'exécution du programme. La classe 'UselessStrategy' serait compilée, ce qui aurait pour effet d'appeler la méthode' main' dans 'Strategy' – Eric

1

Je le repenserais.

Placez le code que vous souhaitez exécuter ailleurs, de préférence une méthode non statique, et appelez-le. main() ne devrait pas être utilisé de cette façon.

Je vous recommande de créer une classe Stratégie séparée au lieu de main.

2

Vous pouvez définir la classe dans un bloc statique de la sous-classe.

public abstract class Strategy 
{ 
    protected static Class<? extends Strategy> instanceClass; 

    abstract void execute(SoccerRobot robot); 

    public static void main(String args) 
    { 
     Strategy s = instanceClass.newInstance() 
     s.execute(new SoccerRobot()) 
    } 
} 

puis

public class UselessStrategy extends Strategy 
{ 
    static { 
     instanceClass = UselessStrategy.class; 
    } 

    void execute(SoccerRobot robot) 
    { 
     System.out.println("I'm useless") 
    } 
} 
Questions connexes