Come scrivere costruttori che potrebbero fallire nel creare un'istanza appropriata di un oggetto

11

A volte è necessario scrivere un costruttore che può fallire. Ad esempio, supponiamo di voler istanziare un oggetto con un percorso file, qualcosa di simile a

obj = new Object("/home/user/foo_file")

Se il percorso punta a un file appropriato, tutto va bene. Ma se la stringa non è un percorso valido, le cose dovrebbero rompersi. Ma come?

Potresti:

  1. genera un'eccezione
  2. restituisce oggetto nullo (se il tuo linguaggio di programmazione consente ai costruttori di restituire valori)
  3. restituisce un oggetto valido ma con un flag che indica che il suo percorso non è stato impostato correttamente (ugh)
  4. altri?

Suppongo che le "migliori pratiche" dei vari linguaggi di programmazione possano implementarlo diversamente. Per esempio penso che ObjC preferisca (2). Ma (2) sarebbe impossibile implementare in C ++ dove i costruttori devono avere il vuoto come tipo di ritorno. In tal caso, prendo quello che viene utilizzato (1).

Nel tuo linguaggio di programmazione di scelta puoi mostrare come gestirai questo problema e spiegherai perché?

    
posta garageàtrois 20.03.2011 - 20:24
fonte

6 risposte

7

Non è mai bello fare affidamento su un costruttore per fare il lavoro sporco. Inoltre, non è chiaro per un altro programmatore, indipendentemente dal fatto che il lavoro debba essere svolto o meno nel costruttore, a meno che non ci sia una documentazione esplicita in tal senso (e che l'utente della classe lo abbia letto o sia stato detto) .

Ad esempio (in C #):

public Sprite
{
    public Sprite(string filename)
    {
    }
}

Cosa succede se l'utente non vuole caricare subito il file? Cosa succede se vogliono fare il caching su richiesta del file? Non possono Potresti pensare di inserire un argomento bool loadFile nella funzione di costruzione, ma in questo modo questo diventa complicato dato che ora hai ancora bisogno di un metodo Load() per caricare il file.

Dato lo scenario attuale, sarà più flessibile e più chiaro per gli utenti della classe fare questo:

Sprite sprite = new Sprite();
sprite.Load("mario.png");

O in alternativa (per qualcosa come una risorsa):

Sprite sprite = new Sprite();
sprite.Source = "mario.png";
sprite.Cache();

// On demand caching of file contents.
public void Cache()
{
     if (image == null)
     {
         try
         {
             image = new Image.FromFile(Source);
         }
         catch(...)
         {
         }
     }
}
    
risposta data 21.03.2011 - 00:26
fonte
7

In Java, potresti usare le eccezioni o usare il modello di fabbrica, che ti consentirebbe di restituire null.

In Scala, puoi restituire un'opzione [Foo] da un metodo di fabbrica. Ciò funzionerebbe anche in Java, ma sarebbe più ingombrante.

    
risposta data 20.03.2011 - 21:11
fonte
3

Genera un'eccezione.

È necessario controllare il valore null se è possibile restituirlo (e non verrà controllato)

Questo è ciò che le eccezioni controllate sono per. Sai che potrebbe fallire. I chiamanti devono gestirlo.

    
risposta data 20.03.2011 - 23:54
fonte
3

In C ++ , i costruttori sono usati per creare / inizializzare i membri della classe.

Non c'è una risposta giusta a questa domanda. Ma quello che ho osservato fino ad ora, è che il più delle volte è il client (o chiunque userà la tua API) che sceglie come gestire questa roba.

A volte potrebbero chiederti di allocare tutte le risorse di cui l'oggetto potrebbe aver bisogno sul costruttore e lanciare un'eccezione se qualcosa fallisce (interrompendo la creazione dell'oggetto), o non fare nulla di ciò sul costruttore, e assicurati che la creazione abbia sempre successo, lasciando queste attività a qualche funzione membro.

Se decidi tu di scegliere il comportamento, le eccezioni sono il modo C ++ predefinito per gestire gli errori e dovresti usarle quando puoi.

    
risposta data 21.03.2011 - 02:33
fonte
1

Puoi anche creare un'istanza dell'oggetto senza parametri, o con solo parametri che non falliscono mai, e quindi usi una funzione di inizializzazione o un metodo da cui puoi lanciare un'eccezione sicura o fare quello che vuoi.

    
risposta data 20.03.2011 - 21:56
fonte
-4

Preferisco non inizializzare alcuna classe o elenco nel costruttore. Inizializza una classe o un elenco ogni volta che ne hai bisogno. Eg.

public class Test
{
    List<Employee> test = null;
}

Non farlo

public class Test
{
    List<Employee> test = null;

    public Test()
    {
        test = new List<Employee>();
    }
}

Inizializza invece quando richiesto Eg.

public class Test
{
    List<Employee> emp = null;

    public Test()
    { 
    }

    public void SomeFunction()
    {
         emp = new List<Employee>();
    }
}
    
risposta data 04.08.2015 - 11:23
fonte

Leggi altre domande sui tag