Quando dovresti creare / distruggere l'oggetto sottostante in una classe che lo avvolge

0

(nota: ho usato Java per semplificare la spiegazione della mia domanda, ma il linguaggio attuale è irrilevante per questo dilemma)

TL; DR: Ho un wrapper attorno ad alcune classi sottostanti. A che punto dovrei istanziare la classe sottostante (nel costruttore, in un metodo separato, al primo utilizzo) e perché?

Diciamo, per esempio, che voglio creare una semplice classe da leggere da un file (può essere in realtà qualsiasi cosa in cui la funzionalità principale di una classe dipende da una o più classi sottostanti, ma la lettura dei file sembra più semplice da spiegare ). Questa classe traccerà / semplificherà un'altra classe chiamata File . In passato, implementavo la mia classe di lettore di file in questo modo:

class MyFileReader {
    private File file;

    public MyFileReader(String filename) {
        this.file = new File(filename);
    }

    public String read() {
        this.file.read(...);
    }
}

Quindi, la creazione del mio oggetto apre immediatamente il file (se esiste la possibilità che il file non esista, vorrei generare un'eccezione nel costruttore).

Al giorno d'oggi, di solito implementerei quella classe in questo modo:

class MyFileReader {
    private File file;
    private boolean isOpen = false;

    public void open(String filename) {
        if (this.isOpen) close();
        this.file = new File(filename);
        this.isOpen = true;
    }

    public void close() {
        if (this.isOpen) {
            this.file.close();
            this.isOpen = false;
        }
    }

    public String read() {
        if (this.isOpen) {
            this.file.read(...);
        }
    }
}

In altre parole, la creazione dell'oggetto è separata dall'apertura effettiva del file (se esiste la possibilità che il file non esista, farei in modo che il metodo open restituisca un valore booleano che indica se la classe è riuscita ad aprire il file con successo) ed è possibile che l'oggetto esista senza file attualmente aperti.

Infine, un altro approccio che ho usato di rado è aprire il file "pigramente", quando è necessario, in questo modo:

class MyFileReader {
    private File file;
    private String filename;
    private boolean isOpen = false;

    public MyFileReader(String filename) {
        this.filename = filename;
    }

    public String read() {
        if (!this.isOpen) {
            this.file = new File(filename);
            this.isOpen = true;
        }

        this.file.read(...);
    }
}

Ora la domanda è: quale di questi approcci è il migliore? E, dal momento che la risposta è probabilmente "dipende", da cosa dipende e in quali scenari è meglio applicare ciascuno di questi metodi?

    
posta fstanis 26.09.2014 - 20:29
fonte

2 risposte

3

Nella mia esperienza, come regola generale, dovresti creare un'istanza dell'oggetto sottostante non appena hai abbastanza informazioni per crearlo e distruggerlo quando l'ambito o l'oggetto che lo possiede termina. In altre parole, non appena sai che non hai bisogno delle informazioni in esso contenute e puoi permetterti il costo di distruzione del runtime.

Le considerazioni includono:

  • Stato valido degli oggetti - l'oggetto wrapper ha il diritto di esistere senza il core? Gli oggetti dovrebbero sempre esistere in uno stato valido . Se il tuo wrapper ha bisogno che l'oggetto core abbia un senso, dovresti istanziare il core non appena installi il wrapper.
  • Nullability - ha senso che il wrapper contenga un valore nullo? Se è così, dovrebbe contenere un riferimento nullable. Ha senso scambiare gli oggetti all'interno del wrapper? In tal caso, dovresti creare gli oggetti principali quando sai quale oggetto deve essere spostato.
  • Facilità d'uso: la tua interfaccia facilita l'utilizzo da parte del client della funzionalità fornita dall'oggetto?
  • Facilità di uso improprio - La tua interfaccia rende facile l'uso del tuo oggetto sbagliato ?
  • Proprietà - chi possiede la risorsa sottostante? Dovrebbero decidere quando viene distrutto.

Se il tuo esempio di lettore di file, la seconda opzione rende facile l'uso sbagliato dell'oggetto, perché posso facilmente chiamare read () prima di specificare quale file leggere. Userò la prima o l'ultima opzione, o forse forniremo entrambi combinando una variante dell'ultima opzione con una funzione di fabbrica chiamata get_open_file (nomefile).

    
risposta data 26.09.2014 - 21:50
fonte
0

Penso che la vera risposta sia un po 'soggettiva, ma ci sono 3 scenari che mi vengono in mente (e ce ne sono di più):

  1. Decoratore - > si passa l'oggetto sottostante nel costruttore
  2. Proxy - > se l'oggetto sottostante è costoso da creare, rimandare la sua creazione finché non ne hai effettivamente bisogno.
  3. Singleton - > come proxy, crea l'istanza su richiesta se costoso
risposta data 26.09.2014 - 20:45
fonte