2016-02-20 12 views
6

Java - È possibile estendere tutte le sottoclassi di una classe con una singola classe?Java - È possibile estendere tutte le sottoclassi di una classe con una singola classe?

Spieghiamo che con un esempio, il codice effettivo è molto più complesso. Ho una classe di animali con una sua gerarchia di classi. Diciamo che ha due sottoclassi: Testarrosa e Viper.

public class Car { 

    public abstract String getManufacturer(); 
} 

public class Testarossa extends Car{ 

    public String getManufacturer(){ 
     return "Ferrari"; 
    } 
} 

public class Viper extends Car{ 

    public String getManufacturer(){ 
     return "Dodge"; 
    } 
} 

Desidero estendere tutte le sottoclassi Car con una sottoclasse RegisteredCar.

public class RegisteredCar extends Car { 

    private String plateNumber; 

    public RegisteredCar (String plateNumber){ 
     this.plateNumber=plateNumber; 
    } 

    public String getPlateNumber() { 
     return plateNumber; 
    } 
} 

A un certo punto, dovrei essere in grado di creare una nuova registrazione di una sottoclasse specifica. Qualcosa di simile

RegisteredCar c = new RegisteredCar<Viper>("B-3956-AC"); 

e chiamare il c.getManufacturer() per ottenere "Dodge" e c.getPlateNumber() per ottenere B-3956-AC. Ovviamente, dovrei comunque essere in grado di creare un Car c = new Viper();

Questo è un esempio. Avere un attributo in Auto con valore null se non registrato non è sufficiente per ciò di cui ho bisogno.

+3

* "Diciamo che ha due sottoclassi: Gorilla e Lupo" * .. Immagino che dovresti attenersi al tuo esempio di 'Car';). – Tom

+0

ma no, non può essere fatto. –

+0

Non è possibile cambiare la classe base di Viper e Testarossa in RegisteredCar? – sfThomas

risposta

4

Come altri hanno detto, non quello non è davvero possibile e il vostro esempio potrebbero essere risolti modificando il proprio modello

Come alternativa alla successione è possibile utilizzare un'altra classe per avvolgere un'istanza Car.
Vorrei fare Car un'interfaccia (pur avendo RegisteredCar estendono Car dovrebbe funzionare ugualmente) e quindi tentare qualcosa di simile al seguente pseudo codice:

class RegisteredCar<T extends Car> implements Car { 
    private final T car 

    RegisteredCar(T car) { 
    this.car = car; 
    } 

    ... methods for RegisteredCar 
    ... methods from Car delegating to `this.car` 
} 

Chiedo scusa per il codice un po 'male, non ho aperto un IDE e rovino sempre generici senza IDE a portata di mano.

Un'altra possibile soluzione è utilizzare AOP, anche se non so come sia di moda in questi giorni, ma quello che stai descrivendo potrebbe essere una preoccupazione trasversale.

Un'alternativa finale potrebbe essere quella di utilizzare un linguaggio che consente per le estensioni, Tratti, protocollo o qualche altro tipo di 'mix'

+1

Come ho detto a Bhushan, non è perfetto; ma questa è la soluzione migliore che ho trovato finora. Sfortunatamente, deve essere Java :( –

+0

Grazie :). Non è perfetto, ma se sei limitato a Java a volte devi affrontare il breve corso della lingua, nessun linguaggio generico è perfetto. È un peccato, però, poiché la JVM ha alcune grandi lingue con l'interoperabilità Java, ma sembra impossibile convincere i "leader" a mescolare un po 'delle altre lingue quando è appropriato. In bocca al lupo. – Gavin

2

In java è vietato estendere più di 1 classe. Ad esempio, è possibile creare catene da classi ad estensioni. Per risolvere il problema dell'ereditarietà mutiple in Java → viene utilizzata l'interfaccia

+1

Non è un problema di ereditarietà multipla. Non sto cercando di creare una classe che eredita da più classi. È una questione di eredità generica; non sai quale classe stai estendendo. –

10

In breve, non è possibile. Devi sfortunatamente modificare il tuo modello di oggetto.

Per esempio, che dire di avere una classe Registration in questo modo:

public interface Registration<C extends Car> { 
    C getCar(); 

    String getPlateNumber(); 
} 

In questo modo è possibile estrarre le informazioni relative alla registrazione in una sola classe, pur mantenendo le vostre Car modelli.

È quindi possibile fare metodi di supporto come:

Registration<Viper> registeredViper = createRegistration(new Viper(), "B-3956-AC"); 
+0

Ah! Quasi uguale alla mia risposta. Vorrei solo implementare l'interfaccia 'Car', quindi può essere usata dove è stato usato' Car', delegare i metodi implementati all'istanza 'Car'. In aumento la risposta. – Gavin

1

No, non è come C++. L'ereditarietà multipla non è possibile in Java. Tuttavia è possibile implementare più interfacce.

+1

Non è un problema di ereditarietà multipla. Non sto cercando di creare una classe che eredita da più classi. È una questione di eredità generica; non sai quale classe stai estendendo. –

0

Non è possibile ottenere ciò con l'ereditarietà. L'opzione migliore è fare il tipo di RegisteredCar generica, quindi avere una variabile di istanza generica che contiene il tipo di auto previsto:

public class RegisteredCar<T extends Car> { 
    private String plateNumber; 
    private T car; 

    public T getCar() { 
     return this.car; 
    } 
    public T setCar(T car) { 
     this.car = car; 
    } 
    public RegisteredCar (String plateNumber){ 
     this.plateNumber=plateNumber; 
    } 
    public String getPlateNumber() { 
     return plateNumber; 
    } 
} 

Con questo, si sarà in grado di passare in RegisteredCar un oggetto di qualsiasi tipo che è una sottoclasse di macchina.

Come si può notare, ho rimosso la parte extends Car di questa classe, in quanto non è necessario che sia una sottoclasse della macchina stessa.

2

È consigliabile evitare l'ereditarietà il più possibile. Utilizza le astrazioni (interfacce) per rendere elegante il tuo codice e manutenibile. Solo google perché estendere è il male.

public interface Car{ 
     String getManufacturer(); 
    } 

    public interface Registerable{ 
     boolean isRegistered(); 
     void register(String plateNumber); 
     void getPlateNumber(); 
    } 

    public class Viper implements Car, Registerable 
    { 
     //all methods 
    } 
+1

L'ereditarietà delle classi non è affatto male. La tua soluzione costringe il programmatore ad implementare i metodi comuni in ogni sottoclasse. Come può essere mantenibile? –

+1

Se avete bisogno di funzionalità comuni, potete implementare quella funzionalità, astrarla e comporre quell'astrazione in tutte le classi che ne hanno bisogno.In questo modo eviterai la dipendenza dall'implementazione, sarai in grado di cambiare implementazione e nessuno se ne accorgerà perché l'implementazione è completamente nascosta. Questo è chiamato _Composizione sull'eredità_. Piccoli cambiamenti nella superclasse possono rovinare tutti i sottoclassi o comportare bug sottili. La composizione e la dipendenza dalle astrazioni aiuta ad evitare tali problemi. – callOfCode

+0

E ciò non significa la necessità di implementare gli stessi metodi più e più volte. Ciò significa implementazione di funzionalità comuni in un unico posto, astrazione e passaggio dell'astrazione a tutte le classi che ne hanno bisogno. – callOfCode

1

Con l'approccio classe generica come descritto in altra risposta, non sarà in grado di utilizzare RegisteredCar dove è necessario passare l'oggetto Car. per esempio. supponiamo di aver bisogno di generare qualche fattura.

Invoice getInvoice(Car c); 

In questo metodo non è possibile utilizzare RegisteredCar in quanto non è di tipo auto. Tutte le API che richiedono Auto non sono applicabili a RegisteredCar. In alcuni casi potrebbe essere necessario il numero di targa e l'automobile. Potrebbe essere necessario continuare a mappare il numero di targa e le automobili. Vorrei suggerire seguente approccio basato sulla Decorare Pattern e delegare tutta l'automobile chiama ad oggetto macchina passò

public class RegisteredCar extends Car{ 

    public RegisteredCar(Car c, String plateNumber){ 

    }   
    @Override 
    String getColor(){ 
     c.getColor(); 
    } 
} 
+1

Sono d'accordo con la prima parte. Anche se non è perfetto dato che alla fine si mantengono due diverse istanze, e occorre chiamare la nuova Car() e la nuova RegisteredCar(), è una buona soluzione per una carenza di Java. La parametrizzazione della classe (la soluzione di Gavin) va un po 'oltre per quei metodi che richiedono specifici parametri di sottoclassi, ad es. compareTo (Viper a). –

0

C'è una ragione, nelle classi reali, che non si può semplicemente aggiungere la nuova funzionalità per la classe di base esistente ?

public abstract class Car 
{ 
    public abstract String getManufacturer() ; 

    protected String plate_number = null ; 

    public String getPlateNumber() 
    { return this.plate_number ; } 

    public boolean isRegistered() 
    { return (this.plate_number != null) ; } 
} 
Problemi correlati