2016-01-02 1 views
3

J'ai une classe d'écran, qui est la classe de base de plusieurs types d'écrans, par exemple PauseScreen, MainScreen, etc.Dynamiquement comparer les types en Java

J'ai une pile d'écrans dans mes classes, et mon jeu est Pousser/poping écrans en fonction des boutons.

Mais j'ai besoin de passer d'un écran à l'autre (tout ce qui se passe jusqu'à l'écran nécessaire).

Disons que j'ai un MainScreen, un GameScreen et un PauseScreen. Je dois passer de PauseScreen à MainScreen, (popping PauseScreen et GameScreen).

Quelle est la méthode préférée pour le faire en java? Je pourrais stocker un identifiant dans chaque écran, mais cela ne semble pas correct. Edit: C'est ce que je veux réaliser, j'étais juste curieux de savoir qu'il y avait un meilleur moyen qui ne nécessite pas de créer une énumération (IIRC il est possible d'obtenir le type de la classe à l'exécution, mais peut-être c'est une mauvaise pratique pour ce que je veux faire?).

class X 
{ 
    Stack<Screen> screens = new Stack<Screen>(); 

    void push(Screen s) 
    { 
     screens.push(s); 
    } 

    void pop() 
    { 
     screens.pop(); 
    } 

    void popUntil(Screen.Type t) 
    { 
     // go through the list in reverse order 
     while(screens.next().type != t) 
      screens.pop(); 
    } 
} 

// other places in the code 

app.popUntil(Screen.Type.MainScreen); 
app.popUntil(Screen.Type.GameScreen); 
+0

Principalement opinion fondée !, par exemple utiliser instanceof ou vous l'écran de peut mettre en œuvre et de l'interface avec la méthode int getTypeOfScreen(), la manière préférée? ? Ta façon!!! –

+0

Bien sûr, je pourrais juste le faire et passer à autre chose, mais comme je suis nouveau avec la langue, je voulais d'abord voir s'il y avait de meilleurs moyens pour y parvenir. – Aulaulz

+0

Votre quête est légitime, mais sans connaître votre code exact, il devient très difficile de répondre "de manière préférée", j'aurais probablement préféré une interface commune et appeler un int public getType() avec une belle déclaration de commutateur ... Alors que est préféré ?, le plus rapide, le plus lisible, le code le plus court .... ou la façon dont vous savez le mieux ?? –

Répondre

1

Vous pouvez directement consulter les classes en utilisant l'opérateur .class, qui renvoie une instance java.lang.Class:

class X 
{ 
    // ... 

    void popUntil(Class<? extends Screen.Type> type) 
    { 
     // go through the list in reverse order 
     while(screens.next().getClass() != type) 
     { 
      screens.pop(); 
     } 
    } 
} 

x.popUntil(Screen.Type.MainScreen.class); 
x.popUntil(Screen.Type.GameScreen.class); 

Notez que les instances de java.lang.Class peuvent être comparées à l'aide de l'égalité de référence (== et !=) plutôt que l'égalité d'objet (equals méthode). Toutefois, cette implémentation vérifie uniquement si le type de l'instance est exactement l'argument donné. Si vous voulez vérifier si extends ou implements, vous pouvez utiliser la méthode java.lang.Class#isInstance(Object):

while (!type.isInstance(screens.next())) 
{ 
    screens.pop(); 
} 
1

Utilisez l'opérateur instanceof

Screen screen = stack.pop(); 
if (screen instanceof PauseScreen) { 

} 
else if (screen instanceof MainScreen) { 

} 
else if (screen instanceof GameScreen) { 

} 
else if (/*...*/) { 
    //... 
} 
else { 
    otherStack.push(screen); 
} 
+0

Cela fonctionnerait avec quelque chose comme popUntil (new MainScreen()), mais je ne voudrais pas envoyer une instance de la classe. (Je n'ai pas accès à l'un des écrans en dehors de la classe qui possède la pile.) – Aulaulz

+0

@Aulaulz vous ne pouvez appeler qu'une méthode ou utiliser un champ d'une instance à laquelle vous avez accès Aucun accès ne signifie que vous ne pouvez rien faire cette instance. –

1

Cela pourrait être un bon candidat pour le Visitor pattern.

public interface ScreenVisitor { 
    void visitMain(MainScreen screen); 
    void visitGame(GameScreen screen); 
    void visitPause(PauseScreen screen); 
} 

public class VisitorForStuff implements ScreenVisitor { 
    void visitMain(MainScreen screen) { 
     // do stuff for MainScreen 
    } 
    // etc. 
} 

public abstract class Screen { 
    ... 
    public abstract void visit(ScreenVisitor visitor); 
    ... 
} 

public class GameScreen extends Screen {  
    ... 
    public void visit(ScreenVisitor visitor) { 
     visitor.visitGame(this); 
    } 
    ... 
} 

... 
Screen screen = stack.pop() 
screen.visit(new VisitorForStuff()); 
... 

Le visiteur utilise un mécanisme de double distribution pour permettre une rétrogradation sans risque de type sans utilisation de instanceof et de casting. Bien qu'il n'y ait pas de grande différence entre utiliser instanceof dans un cas particulier, c'est un modèle assez souple - permettant de nombreux types d'implémentations de visiteurs - et il met en évidence les utilisations via des erreurs de compilation, donc quand vous créez une nouvelle implémentation de Screen, vous pouvez étendre l'interface de visiteur et trouver rapidement tous les endroits qui devront être mis à jour pour gérer la visite du nouveau type d'écran.