2013-10-18 7 views
11

Ho la seguente classe che sto usando come base di tutti i modelli nel mio progetto:Java: sostituzione della variabile statica della classe genitore?

public abstract class BaseModel 
{ 
    static String table; 
    static String idField = "id";  

    public static boolean exists(long id) throws Exception 
    { 
     Db db = Util.getDb(); 
     Query q = db.query(); 
     q.select(idField).whereLong(idField, id).limit(1).get(table); 

     return q.hasResults(); 
    } 

    //snip.. 
} 

Sto poi cercando di estendere da esso, nel modo seguente:

public class User extends BaseModel 
{ 
    static String table = "user"; 
    //snip 
} 

Tuttavia, se provo a fare quanto segue:

if (User.exists(4)) 
    //do something 

Quindi, piuttosto che la query: "SELECT id FROM user WHERE id = ?", si produce la query: "SELECT id dal nulla WHERE id = ?". Di conseguenza, l'override del campo nella classe User non sembra avere alcun effetto.

Come si supera questo problema? Se ho aggiunto un metodo setTable() a BaseModel e ho chiamato setTable() nel costruttore di User, il nuovo valore di table sarà disponibile per tutti i metodi della classe User?

+1

Clicked Upvote, nelle risposte pure. – UDPLover

risposta

12

Non è possibile eseguire l'override di metodi o campi statici di qualsiasi tipo in Java.

public class User extends BaseModel 
{ 
    static String table = "user"; 
    //snip 
} 

questo modo si crea un nuovo campo User#table che guarda caso ha lo stesso nome di BaseModel#table. La maggior parte degli IDE ti avviserà di questo.

Se si modifica il valore del campo in BaseModel, verrà applicato anche a tutte le altre classi di modelli.

Un modo è quello di avere i metodi di base generici

protected static boolean exists(String table, long id) throws Exception 
{ 
    Db db = Util.getDb(); 
    Query q = db.query(); 
    q.select(idField).whereLong(idField, id).limit(1).get(table); 

    return q.hasResults(); 
} 

e utilizzarlo nella sottoclasse

public static boolean exists(long id) 
{ 
    return exists("user", id); 
} 

Se si desidera utilizzare il metodo di campo, è necessario creare una classe BaseDAO e avere un UserDAO (uno per ogni classe di modello) che imposta il campo di conseguenza. Quindi crei istanze singleton di tutti i daos.

+1

Perché un IDE dovrebbe avvisare di nascondere i dati? –

+0

@ Click: ho esteso la mia risposta. – Cephalopod

+0

'exists()' è solo un esempio, ho altri 10-20 metodi di supporto. Non voglio sovraccaricarli tutti, preferisco semplicemente cambiare la proprietà del nome della tabella in modo che funzionino tutti. –

2

Per fare ciò che si sta cercando di fare, non effettuare table statico nel BaseModel. Quindi nelle altre classi che ereditano da BaseModel, è possibile impostare table nel costruttore predefinito su qualsiasi cosa si desideri.

static { 
    table = "user"; 
} 
+1

Quindi non posso chiamare 'User.exists()' come metodo statico. –

+0

@ClickUpvote potrebbe essere un'indicazione che stai utilizzando in modo improprio la parola chiave 'static'. Mi consiglia di dare un'occhiata al vostro disegno e rielaborazione a sbarazzarsi della necessità di un 'static' esiste() metodo – StormeHawke

+0

@StormeHawke Cosa c'è di sbagliato con il mio design? Sarà più chiaro se ho creato un'istanza del mio modello utente solo per verificare se l'ID utente specificato è valido? –

8

Poiché Java non consente di ignorare static membri, che, fondamentalmente, è necessario ricorrere alla un po 'più prolisso ma nel complesso più bello singleton pattern, in cui si sta ancora concettualmente la scrittura di codice "statico", ma sei tecnicamente utilizzando istanze (globali/singleton/"statiche"), quindi non sei limitato dalle limitazioni di static.

(si noti che è anche necessario utilizzare metodi perché i campi non partecipano il polimorfismo, e quindi non possono essere ignorati)

public abstract class BaseTable { 
    public abstract String table(); 
    public String idField() { return "id"; } 

    public boolean exists(long id) { 
     // don't build queries this way in real life though! 
     System.out.println("SELECT count(*) FROM " + table() + " WHERE " + idField() + " = " + id); 
     return true; 
    } 
} 

public class UserTable extends BaseTable { 
    public static final User INSTANCE = new UserTable(); 
    private UseTabler() {} 

    @Override public String table() { return "user"; } 
} 

public class PostTable extends BaseTable { 
    public static final Post INSTANCE = new PostTable(); 
    private PostTable() {} 

    @Override public String table() { return "post"; } 
} 

public static void main(String[] args) { 
    UserTable.INSTANCE.exists(123); 
    PostTable.INSTANCE.exists(456); 
} 

Uscite:

SELECT count(*) FROM user WHERE id = 123 
SELECT count(*) FROM post WHERE id = 456 
+0

ecco come sarebbe simile a Scala con qualche riflessione ingenua aggiunto, senza la boilerplate Singleton: http://pastebin.com/3iujwygZ –