Metodi astratti vs variabili di istanza per oggetti riutilizzabili

8

Ho un bel po 'di codice Java che sto rielaborando per essere riutilizzato. Il problema è che ci sono molti pezzi che sono specifici del progetto, quindi c'è un alto livello di accoppiamento tra il progetto dell'applicazione e il progetto del codice base.

Confronta le seguenti situazioni in cui utilizziamo una classe che implementa l'uso di metodi astratti per estrarre le risorse dalla classe figlio e una in cui dichiariamo semplicemente le variabili di istanza.

Metodi astratti:

public abstract class SuperBaseClass {

    public abstract int getNumberOne();
    public abstract String getStringOne();
    public abstract String getStringTwo();

    public printStuff() {
        Log.i("IntAndTwoStrings", String.format("%i %s and %s",
                            getNumberOne(), getStringOne(), getStringTwo()));
    }

}

public class ReusedAppClass extends SuperBaseClass {

    public int getNumberOne() {
        return 1;
    }
    public String getStringOne() {
        return "String1";
    }
    public String getStringTwo() {
        return "String2";
    }

    public ReusedAppClass() {
        printStuff();
    }

}

Variabili di istanza:

public class SuperBaseClass {

    protected int numberOne;
    protected String stringOne;
    protected String stringTwo;

    public printStuff() {
        //Possibly throw RuntimeExceptions if the app didnt set these
        Log.i("IntAndTwoStrings", String.format("%i %s and %s",
                            numberOne, stringOne, stringTwo));
    }

}

public class ReusedAppClass extends SuperBaseClass {

    public ReusedAppClass() {
        numberOne = 1;
        stringOne = "String1";
        stringTwo = "String2";
        printStuff();
    }

}

C'è un compromesso? La situazione del metodo astratto è eccessiva, o è per questo che sono state create le classi astratte?

    
posta Styler 06.02.2012 - 22:25
fonte

4 risposte

8

Penso che i metodi astratti siano la scelta migliore. Se l'implementazione di queste proprietà non è qualcosa di cui le sottoclassi devono preoccuparsi, potresti anche volere che la classe base ne sia responsabile, cioè utilizzare i campi privati nella base classe con accessor pubblici e mutatori protetti:

public class SuperBaseClass {

    private int numberOne;
    private String stringOne;
    private String stringTwo;

    public int getNumberOne() { return numberOne; }
    public String getStringOne() { return stringOne; }
    public String getStringTwo() { return stringTwo; }

    protected void setNumberOne(String numberOne) { this.numberOne = numberOne; }
    protected void setStringOne(String stringOne) { this.stringOne = stringOne; }
    protected void setStringTwo(String stringTwo) { this.stringTwo = stringTwo; }

    public printStuff() {
        Log.i("IntAndTwoStrings", String.format("%i %s and %s", getNumberOne(), getStringOne(), getStringTwo()));
    }
}

Questo tipo di approccio fornisce un strong incapsulamento, ovvero la quantità di codice che può modificare direttamente i tuoi campi è ridotta al minimo.

    
risposta data 07.02.2012 - 02:58
fonte
5

L'approccio astratto alla classe costringe anche la classe estesa a "inizializzare" le variabili mentre con le variabili di istanza protette i valori predefiniti potrebbero essere facilmente usati portando a confusione / bug se non estesi.

    
risposta data 07.02.2012 - 15:57
fonte
3

IMHO un approccio migliore è usare la composizione ed evitare del tutto l'ereditarietà se si tratta solo di personalizzare alcuni campi. Dici "per ottenere le risorse dalla classe figlio", quindi fallo:

public class MyResources() {

private int numberOne;
private String stringOne;
private String stringTwo;

public int getNumberOne() {
    return numberOne;
}

public void setNumberOne(int numberOne) {
    this.numberOne = numberOne;
}

public String getStringOne() {
    return stringOne;
}

public void setStringOne(String stringOne) {
    this.stringOne = stringOne;
}

public String getStringTwo() {
    return stringTwo;
}

public void setStringTwo(String stringTwo) {
    this.stringTwo = stringTwo;
}
}

Quindi istanzia gli oggetti MyResources nelle classi e personalizzali come richiesto. Se hai ancora bisogno di avere una gerarchia di classi puoi avere il tuo oggetto risorsa nella classe base ed ereditarlo nelle classi figlie:

public abstract class SuperBaseClass {

protected MyResources resources;

public SuperBaseClass() {
    resources.setStringOne("Hello");
}

public class ReusedAppClass extends SuperBaseClass {

public ReusedAppClass () {
    super();
    resources.setStringOne("Hi");
}
}
    
risposta data 07.02.2012 - 13:46
fonte
2

Se tutte queste variabili sono proprietà della classe base e i bambini dipendono uniformemente da esse, dichiararle nella base è appropriato e aggiungere get / setter / accessor astratti sarebbe il modo per consentire ai bambini di massaggiare i dati come vedono in forma. Questo non è affatto eccessivo e OOP è progettato per esprimere questo tipo di relazioni.

Se ti accorgi che stai portando troppa quantità di questo tipo di dati alla classe base (o questi dati non sono universalmente comuni a tutti i bambini) allora potrebbe essere il momento di una più grande refactoring della classe base in un contenitore per altre classi di base più specifiche per organizzare la logica e il codice. Questo sarebbe un po 'più complesso ma consentirebbe un design più pulito, e con una buona nomenclatura uno più facile da seguire.

In entrambi i casi, devi prima analizzare che cosa ti aspetti di riutilizzare prima di cambiare le cose. La creazione di un framework riutilizzabile dal codice esistente finirà in un luogo molto diverso rispetto alla riorganizzazione dei dati e delle operazioni su quei dati per il riutilizzo dei moduli, ad esempio.

    
risposta data 07.02.2012 - 00:34
fonte

Leggi altre domande sui tag