Java-Conversion de classe Dynamique de l'Interface à l'implémentation


J'ai lu d'autres articles connexes, mais je ne sais toujours pas comment, ou s'il est possible de lancer dynamiquement (interface à l'implémentation) en Java. J'ai l'impression que je dois utiliser la réflexion pour le faire.

Le projet particulier sur lequel je travaille nécessite une utilisation de nombreux contrôles instanceof, et il est - à mon avis - un peu incontrôlable, donc j'apprécierais toutes les idées/solutions.

Ci-dessous est un mini exemple que j'ai écrit juste pour clarifier exactement ce que je veux faire. Laissez-moi savoir si vous avez besoin de plus d'informations:

Interface:

public interface IRobot {
    String getName();
}

Implémentations:

public class RoboCop implements IRobot {
    String name = this.getClass()+this.getClass().getName();
    public RoboCop() {}
    public String getName() { return name; }
}

public class T1000 implements IRobot {
    String name = this.getClass()+this.getClass().getName();
    public T1000() {}
    public String getName() { return name; }
}

La classe qui gère les implémentations:

import java.util.LinkedList;
import java.util.List;
public class RobotFactory {

    public static void main(String[] args) {
        new RobotFactory();
    }

    public RobotFactory() {
        List<IRobot> robots = new LinkedList<IRobot>();
        robots.add( new RoboCop() );
        robots.add( new T1000() );
        System.out.println("Test 1 - Do not cast, and call deploy(robot)");
        for(IRobot robot : robots) {
            deploy(robot);  // deploy(Object robot) will be called for each..
        }
        System.out.println("Test 2 - use instanceof");
        for(IRobot robot : robots) { // use instanceof, works but can get messy
            if(robot instanceof RoboCop) {
                deploy((RoboCop)robot);
            }
            if(robot instanceof T1000) {
                deploy((T1000)robot);
            }
        }
        System.out.println("Test 3 - dynamically cast using reflection?");
        for(IRobot robot : robots) {
            //deploy((<Dynamic cast based on robot's type>)robot);  // <-- How to do this?
        }
    }

    public void deploy(RoboCop robot) {
        System.out.println("A RoboCop has been received... preparing for deployment.");
        // preparing for deployment
    }

    public void deploy(T1000 robot) {
        System.out.println("A T1000 has been received... preparing for deployment.");
        // preparing for deployment
    }

    public void deploy(Object robot) {
        System.out.println("An unknown robot has been received... Deactivating Robot");
        // deactivate
    }
}

Sortie:

[RoboCop@42e816, T1000@9304b1]
Test 1 - Do not cast, and call deploy(robot)
An unknown robot has been received... Deactivating Robot
An unknown robot has been received... Deactivating Robot
Test 2 - use instanceof
A RoboCop has been received... preparing for deployment.
A T1000 has been received... preparing for deployment.
Test 3 - dynamically cast using reflection?

Donc, pour résumer, ma question, comment puis-je éviter d'avoir à utiliser instanceof dans ce cas. Grâce.

Author: jpaugh, 2010-10-07

5 answers

, Vous pouvez faire déployer une méthode de IRobot, ou utiliser le visiteur modèle.

Et non, la réflexion ne facilitera pas les choses ici.

 7
Author: meriton, 2010-10-06 20:52:23

Kent Beck dit dans son livreTest Driven Development : Chaque fois que vous utilisez la vérification de type à l'exécution, le polymorphisme devrait aider. Mettez la méthode deploy () dans votre interface et appelez-la. Vous pourrez traiter tous vos robots de manière transparente.

Oubliez la réflexion, vous êtes juste au-dessus de la réflexion. Rappelez-vous vos principes de base orientés objet.

 3
Author: Mike, 2010-10-06 20:54:42

L'envoi des méthodes surchargées se fait statiquement à compiletime, donc votre approche ne peut pas fonctionner. C'est aussi très mauvais design. Ne vous semble-t-il pas particulier que la méthode getName(), le seulement qui diffère entre les classes de robots, ne soit jamais réellement appelé?

Vous devez abandonner les méthodes surchargées et utiliser à la place la substitution de méthodes dans les classes de robots, que vous appelez directement. c'est à dire

public void deploy(IRobot robot) {
    System.out.println("A "+robot.getName()+" has been received..."
                        +" preparing for deployment.");
    // preparing for deployment
}
 3
Author: Michael Borgwardt, 2010-10-06 20:58:00

Vous pouvez éviter instanceof en déplaçant la méthode deploy dans votre interface iRobot et vos implémentations.

L'explication du comportement est que vos trois méthodes de déploiement sont trois méthodes différentes; méthodes surchargées avec des signatures différentes. Au moment de la compilation, il est déterminé lequel est choisi, pas au moment de l'exécution en fonction de la classe réelle...

 2
Author: ivy, 2010-10-06 20:53:09

Au lieu d'utiliser instanceof, vous pouvez utiliser Modèle de Méthode d'Usine

Définition de la méthode d'usine...

Comme d'autres modèles de création, il traite du problème de la création objets (produits) sans spécifier la classe exacte de l'objet qui sera créé.

Vous aurez besoin d'un RobotCreatorFactory qui aura une méthode appelée IRobot createRobot(String robotName) {...} (vu que votre robot renvoie un nom. Mes suggestions sont que chaque robot aura un public static String name NAME = Robocop.class.getName();. À l'intérieur de la méthode que vous aurez une vérification telle que

if (Robocop.NAME.equals(robotName) { return new RoboCop(); }

De cette façon, vous allégez instanceof. Et aussi, vous pouvez utiliser les conseils de @Meriton sur un DeploymentVisitor (en utilisant un modèle de visiteur)....

PS Mon exemple est une explication approximative du modèle de méthode d'usine. Un exemple existe dans Gof book et Wikipedia.

 0
Author: Buhake Sindi, 2010-10-06 21:24:46