Domanda

Supponiamo di avere una classe base B e una classe derivata D. Vorrei avere un metodo foo () all'interno della mia classe base che restituisca un nuovo oggetto di qualunque tipo sia l'istanza. Quindi, ad esempio, se chiamo B.foo () restituisce un oggetto di tipo B, mentre se chiamo D.foo () restituisce un oggetto di tipo D; nel frattempo, l'implementazione risiede esclusivamente nella classe base B.

È possibile?

È stato utile?

Soluzione

Non farlo. Crea il " foo " metodo astratto.

abstract class B {
    public abstract B foo();
}

O ricevi una factory astratta attraverso il costruttore della classe base:

abstract class B {
    private final BFactory factory;
    protected B(BFactory factory) {
        this.factory = factory;
    }
    public B foo() {
        return factory.create();
    }
}
interface BFactory {
    B create();
}

Aggiungi tipi di ritorno covarianti e generici a piacere.

Altri suggerimenti

Finché ogni classe ha un costruttore predefinito:

    public B instance() throws Exception {
        return getClass().newInstance();
    }

Beh, potrei essere fuori ma suppongo che dal momento che "questo" si riferisce sempre all'oggetto corrente, potresti fare qualcosa del genere

public B foo() {
    return this.getClass().newInstance();
}

o qualcosa del genere? Se crei un'istanza di D e poi chiami d.foo () dovresti ottenere un'istanza di D restituita come B. Potresti restituirla come un semplice Oggetto ma dovresti essere il più specifico possibile in questa istanza, penso.

A parte il fatto che penso che ci sia probabilmente un difetto di progettazione se si desidera ottenere questo risultato, è possibile provare il seguente approccio.

Nella tua domanda, stai usando metodi statici (di classe), B.foo (), D.foo (), questo non può essere realizzato usando l'ereditarietà perché i metodi statici non hanno una natura dinamica, non prendono parte nel sistema di ricerca. Quindi non hai abbastanza informazioni sul tipo.

Se stai usando una funzione membro foo () potresti avere il seguente costrutto:

public class B {
    public B foo()
    throws IllegalAccessException, InstantiationException {
        return this.getClass().newInstance();
    }
}

public class D  extends B{    
}

public class Test {
    public static final void main(String[] args)
    {
        try {
            System.out.println((new B()).foo());
            System.out.println((new D()).foo());
        } catch (IllegalAccessException e) {
            e.printStackTrace();  
        } catch (InstantiationException e) {
            e.printStackTrace();  
        }
    }
}

Come dicono le altre risposte, puoi usare getClass (). newInstance () se c'è un costruttore senza argomenti in ogni sottoclasse (assicurati di catturare InstantiationException e IllegalAccessException).

Se uno qualsiasi dei costruttori richiede argomenti, è possibile utilizzare reflection o (preferibilmente a mio avviso) definire un metodo come getNewInstance () che è possibile ignorare nella sottoclasse solo se necessario.

per es.

Thing foo() {
    Thing th = getNewInstance();
    // do some stuff with th
    return th;
}

Thing getNewInstance() {
    return getClass().newInstance();
}

Quindi getNewInstance () può essere sovrascritto solo se necessario, per le sottoclassi che non hanno il costruttore predefinito.

Thing getNewInstance() {
    return new BigThing(10, ThingSize.METRES);
}

Penso che questo potrebbe essere possibile fare usando la riflessione, cioè nella tua superclasse hai:

public ClassName getFoo() throws InstantiationException, IllegalAccessException
{
    return getClass().newInstance();
}

Dove ClassName è il nome della classe di base.

Dovrai lanciarlo ovunque tu voglia usarlo però ... Non sono sicuro che sia davvero un'ottima soluzione!

Modifica: i metodi di tipo newInstance () sono generalmente statici e ovviamente non avrai idea di quale sia il tipo della tua sottoclasse con un metodo statico.

Non credo che ci sia modo di ottenere un metodo statico per (dinamicamente) creare un'istanza di una sottoclasse.

@Rik

Bene, il vero problema è che ho una classe base astratta Cosa. E Thing ha un metodo chiamato getNextThing () che restituisce una nuova istanza di Thing.

Quindi, ho una serie di sottoclassi come BigThing, LittleThing, SomethingThing e non voglio continuare a riscrivere il metodo getNextThing () per ognuna di esse. Sembra inutile, dal momento che tutti fanno la stessa cosa ...

Sono errato nel mio approccio?

Non sono sicuro del motivo per cui stai cercando di fare ciò che stai effettivamente cercando di fare. Fornire più di un contesto potrebbe permetterci di darti più aiuto.

public class B <X extends B>{

public X foo() throws InstantiationException, IllegalAccessException{
    return (X)this.getClass().newInstance();
}
}        
public class C extends B<C>{        

}

Lascia che ti offra questo consiglio. Il modo in cui le lezioni di CS tendono ad essere insegnate è che i professori sono innamorati dell'eredità, ma non hanno capito la composizione. Penso che ciò che potresti cercare sia la composizione. Quindi, invece di chiamare getNextThing sulla cosa stessa, forse dovresti pensare di implementare la cosa Iterable

Ciò significa che dovrai solo scrivere un Iteratore che può incapsulare la logica di ottenere la cosa successiva, poiché non sembra adattarsi al tuo modello di eredità. Un altro vantaggio di questo è che puoi ottenere alcuni bei dispositivi sintattici da questo (migliorato per la comprensione del loop).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top