Ho un insieme di variabili che non sono conosciute fino al momento dell'esecuzione e saranno condivise da tutte le istanze di quella classe.

4

Senza entrare nella lingua o implementazione specifica:

  • Il valore delle variabili non è noto fino al runtime.
  • Tutte le istanze di questa classe avranno bisogno di questa variabile.

Le soluzioni ovvie:

  • Utilizza una variabile statica che imposto prima di iniziare a utilizzare quella classe, ma ciò è disordinato perché qualsiasi utente dovrebbe ricordarsi di inizializzarsi prima dell'uso.

  • Inserisci il calcolo nel costruttore. Più pulito, ma anche dispendioso perché il valore viene ricalcolato ogni volta. Nel mio caso questo calcolo è molto lento e causa una notevole differenza di prestazioni.

C'è un modo migliore per gestire questo rispetto a questi due metodi?

    
posta Ahmed 06.06.2017 - 20:47
fonte

4 risposte

5

Alcune lingue hanno costrutti solo per eseguire una sola volta i calcoli. Java ha blocchi di inizializzazione statici 1 . C # ha costruttori statici . Altre lingue potrebbero avere costrutti simili.

Sono costituiti da codice chiamato all'avvio del programma o quando viene creata la prima istanza dell'oggetto. Di solito non possono essere chiamati direttamente, il che significa che non è possibile passare i parametri. Se hai bisogno di parametri, dovrai modificare il progetto per rimuovere quel requisito o utilizzare un metodo diverso.

1 Java ha anche blocchi di inizializzazione non statici, noti anche come blocchi di inizializzazione dell'istanza. Sono simili, ma vengono eseguiti ogni volta che viene creata un'istanza di quella classe, anziché solo la prima volta. Il vantaggio è che possono impostare campi di istanza.

    
risposta data 06.06.2017 - 21:22
fonte
5

Le variabili statiche vanno bene se usate per le costanti, che include costanti i cui valori sono calcolati in fase di esecuzione ma non dipendono da alcun input. Le variabili statiche potrebbero anche essere OK se vengono utilizzate solo all'interno di una classe.

Una volta che le variabili statiche diventano parte del flusso di dati esterno, potresti riscontrare una serie di problemi:

  • Ordine di inizializzazione tra più classi. Se non puoi garantire che questo campo sia inizializzato prima che la classe possa essere istanziata, potresti potenzialmente bloccare la tua applicazione. Ciò è particolarmente grave in C ++, dove seguiranno i segfault.

  • Testabilità. Con variabili statiche, non puoi testare un oggetto in isolamento. Devi pensare all'intero gruppo di oggetti che interagiscono con la variabile statica.

  • accoppiamento. Se il codice esterno interagisce con questa variabile statica, questo codice è strettamente accoppiato a quella classe. Ciò rende più difficile l'evoluzione della base di codice nel tempo.

  • correttezza. Se il codice esterno imposta la variabile, potrebbero dare delle assurdità. La correttezza della classe ora dipende dalla correttezza di tutti i suoi clienti, il che è indesiderabile.

Riesco a vedere due soluzioni ragionevoli: inizializzazione pigra o istanziazione tramite factory.

Con l'inizializzazione pigra, il costruttore inizializza il valore, ma solo se è attualmente non inizializzato. Il modo in cui questo deve essere eseguito correttamente dipende dalla lingua, soprattutto se questa inizializzazione deve essere protetta da un errore. Se ricordo bene, la "danza di inizializzazione del pigro singleton" sarebbe simile a questa in Java:

private static volatile Thing variable;

Constructor() {
  if (variable == null) {
    synchronized(Constructor.class) {
       if (variable == null)
         variable = initializeVariable();
    }
  }
}

Ma non citarmi su di esso ...

Con una fabbrica, possiamo evitare completamente le variabili globali. Il valore inizializzato ora è memorizzato nell'oggetto factory e viene passato a ogni istanza creata come dipendenza nel costruttore. Qualsiasi codice che desideri creare un'istanza di oggetti della classe deve essere fornito in fabbrica. Il codice non dovrebbe creare ogni volta una nuova factory, perché ricalcolare il valore di nuovo.

private Thing variable;

private Constructor(Thing variable) {
  this.variable = variable;
  ...
}

public static class Factory {
  private final Thing variable;

  Factory() {
    variable = initializeVariable();
  }

  Constructor create() { return new Constructor(variable); }
}

In Java useremmo un% co_de nidificato, in C ++ probabilmente un public static class Factory . Non conosco il linguaggio C # appropriato.

Se si sta utilizzando un framework di iniezione delle dipendenze, è probabile che si possa evitare di scrivere esplicitamente la factory. Invece, dichiareresti il costoso per calcolare il campo istanza e collegalo al tuo framework in modo che possa essere compilato automaticamente. Quindi, si crea una funzione che può fornire questa dipendenza. Il framework ha probabilmente qualche modalità singleton in modo che la funzione venga invocata una volta sola.

    
risposta data 06.06.2017 - 22:18
fonte
1

In C / C ++, utilizzando le variabili della funzione static puoi:

  1. Inizializza una variabile una volta.
  2. Inizializza una variabile prima che venga eseguito il resto della funzione.

In C ++, puoi usare tale variabile nel costruttore di una classe.

MyClass::MyClass()
{
   static ExpensiveToComputeData data(... arguments to the constructor ...);

   // Rest of the code to properly initialize MyClass.
   // Anything from "data" above can be used to initialize MyClass.
}

Dovrai assicurarti che il costruttore di ExpensiveToComputeData si occupi di leggere / calcolare i dati.

Ciò presuppone che i dati importanti da ExpensiveToComputeData siano disponibili a MyClass .

    
risposta data 06.06.2017 - 21:33
fonte
0

Dovrai calcolare i valori ad un certo punto, giusto? Quindi vuoi scegliere il momento e il luogo migliori.

Ogni istanza della classe ha bisogno del proprio set? In caso contrario, è possibile utilizzare il costruttore statico e utilizzare variabili statiche.

Hai bisogno dei risultati subito dopo la costruzione o solo dopo aver chiamato un metodo? Se non ne hai bisogno immediatamente, puoi avviare un thread nel costruttore e calcolare i risultati in modo asincrono.

    
risposta data 06.06.2017 - 21:07
fonte

Leggi altre domande sui tag