2016-05-26 11 views
10

Ecco il mio codice per Scene.java. Ha diversi tipi di oggetti, che sono tutti inclusi in un ArrayList comune chiamato targets. Tutti condividono un metodo toString() che restituisce il loro identificatore. Voglio utilizzare l'elenco targets per determinare se c'è qualche oggetto nella scena corrispondente a un dato identificativo, indipendentemente dal suo tipo:Conversione da oggetto Java a sottoclasse

ArrayList<NPC> npcs = new ArrayList<NPC>(); 
ArrayList<Item> items = new ArrayList<Item>(); 
ArrayList<EnviromentalObject> enviromental_objects = new ArrayList<EnviromentalObject>(); 

ArrayList<Object> targets; 

public Object check_for_target(String target_name){ 
    targets.addAll(npcs); 
    targets.addAll(items); 
    targets.addAll(enviromental_objects); 
    for (Object target : targets){ 
     if (target.toString() == target_name){ 
      return target; 
     } 
    } 
    return null; 

Ecco il codice in Game.java, che verifica la presenza di un dato identificativo . Se c'è una corrispondenza con la scena corrente, voglio conoscere il tipo dell'oggetto e trattarlo come il suo vero tipo. In questo momento, ho il seguente codice e sapevo che non avrebbe funzionato, ma forse mi aiuterà a farmi un'idea.

Object target = current_scene.check_for_target(target_name); 
     if (target == null){ 
      System.out.println(UNRECOGNIZED_TARGET_MESSAGE); 
     } else { 
      String target_type = target.getClass().getName(); 
      target = (target_type) target; 
     } 

Quale sarebbe il modo corretto di ottenere il tipo di oggetto e poi essere in grado di utilizzare metodi che dell'oggetto? In questo momento, mi vengono dati solo i metodi di Object. Devo creare una superclasse per NPC, Item e EnviromentalObject?

+4

Una parentesi: 'se (target .toString() == target_name) {'-> Questa linea ti darà dei problemi. Usa .equals() per gli oggetti. – Chill

+2

È possibile utilizzare la parola chiave 'instanceof' per verificare il tipo di un oggetto. – Chill

+0

Non una risposta alla tua domanda, ma più generale ... Stai usando un 'Elenco' di' Item's che è un problema separato dall'implementazione Lista scelta di 'ArrayList', quindi dovresti dichiarare' Elenco voci = new ArrayList <>(); '- nota anche che non devi ripetere' 'sul lato destro. In questo modo, se in seguito decidi che 'LinkedList' funziona meglio, non devi ridichiarare tutto. –

risposta

14

In pratica, è possibile verificare se un oggetto è un'istanza di una classe specifica.

potrebbe essere qualcosa di simile:

if(target instanceof NPC) { 
    System.out.println("target is a NPC"); 
} 
else if(Target instanceof Item) { 
    System.out.println("target is an Item"); 
} 

if(target instanceof EnviromentalObject) { 

    System.out.println("target is EnviromentalObject"); 
} 

Edit: come abbiamo parlato nei commenti Penso che si possa modificare il codice per raggiungere una soluzione migliore. Il codice sopra riportato funziona ancora, ma può essere una buona pratica utilizzare i modelli di progettazione che sono noti come best practice nella programmazione. Per questa situazione, pensa di utilizzare l'interfaccia java e definire i metodi di condivisione che ogni oggetto potrebbe implementarli in base alle sue necessità. Nel modo più semplice stampano il loro identificatore. Facciamo un esempio:

public interface SceneThings() { 

    public void printIdentifire(); 

    public String doSomeOtherThings(); 

} 

Ogni oggetto può implementa l'interfaccia superiormente da necessita come:

public class Item implements SceneThing { 

... 

public void printIdentifire(){ 

//print its identifier here. 
System.out.print("ID:ITEM###"); 

} 

public String doSomeOtherThings(){ 

    //do some other works !!! 
} 
... 
} 

per gli altri elementi come sopra. E quindi è possibile utilizzare un singolo array per tenerli senza preoccuparsi di loro classe origine in questo modo:

ArrayList<SceneThings> targets = new ... 

SceneThing obj = new Item(); 
targets.add(obj); 

Spero che questo ti può aiutare a definire una soluzione migliore nel tuo caso.

+0

Grazie a un compagno di gruppo – db2791

+0

benvenuto, continua :) – Sir1

+0

Mentre funzionerà, in generale è considerato un odore di codice, se non un anti-pattern. Dovresti davvero creare un'interfaccia implementata da tutte le tue classi che includa la funzionalità condivisa. –

7

Uno dei modi come potrebbe essere fatto di dichiarare una superclasse o interfaccia Target e utilizzarlo per mantenere gli obiettivi matrice, il codice di esempio completo con classe astratta:

ArrayList<NPC> npcs = new ArrayList<NPC>(); 
ArrayList<Item> items = new ArrayList<Item>(); 
ArrayList<EnviromentalObject> enviromental_objects = new ArrayList<EnviromentalObject>(); 

ArrayList<Target> targets; 

public Target check_for_target(String target_name) { 
    targets.addAll(npcs); 
    targets.addAll(items); 
    targets.addAll(enviromental_objects); 
    for (Target target : targets) { 
     if (target.toString().equals(target_name)) { 
      return target; 
     } 
    } 
    return null; 
} 

private abstract class Target {} 
private class NPC extends Target {} 
private class Item extends Target {} 
private class EnviromentalObject extends Target {} 
+3

sono quasi d'accordo (vedi il mio commento sulla Q), ma userei le interfacce piuttosto che una superclasse. In ogni caso, perché è un approccio migliore rispetto all'infinito 'instanceof's. –

+0

@StephenP sì, il punto è giusto, l'interfaccia potrebbe essere più applicabile qui, ma la classe astratta è anche un progetto valido. Le informazioni nella domanda non sono sufficienti per determinarlo, ma aggiornerò la risposta per menzionare l'interfaccia, grazie – erkfel

+1

È sempre meglio usare un'interfaccia di una classe astratta, se l'interfaccia farà un lavoro adeguato, dal momento che in Java è possibile solo estendere * una * classe, ma è possibile implementare tutte le interfacce desiderate. –