Richiedere un certo metodo per chiamarsi prima un altro è chiamato Accoppiamento sequenziale , ed è spesso considerato un antipattern. Prendi ad esempio questo generatore di codice:
cg.enterScope();
... // add operations inside this scope
cg.leaveScope();
Qui, leaveScope
deve sempre essere chiamato dopo enterScope
, altrimenti viene emesso un codice errato. Questo può essere banalmente refactored per usare un tipo Scope
:
Scope(scoped_operations).generate_code(cg);
Il tuo caso è più complicato, dato che vuoi inizializzare pigramente un membro statico prima che vengano create tutte le istanze di quella classe. Immagino che assomigli a
TheClass.initialize();
var instance = new TheClass(); // first use
Il primo passo è rendere initialize
threadsafe. Quindi, deve registrare se è già stato eseguito. Se è così, ogni chiamata futura semplicemente cortocircuito:
static bool is_initialized = false;
static synchronized void initialize() {
if (is_initialized) return;
...; // normal initialization
is_initialized = true;
}
Ora possiamo fare questa chiamata all'interno del costruttore per assicurarci che la classe sia sempre inizializzata prima dell'esecuzione di altri codici:
TheClass(...) {
if (!is_initialized) initialize(); // try to avoid call to synchronized method
...;
}
Se l'inizializzazione non deve avvenire pigramente, è possibile utilizzare varie soluzioni più semplici. (In questo contesto, l'inizializzazione pigra significa che l'inizializzazione viene eseguita sempre solo se viene creata un'istanza). Per qualcosa come economico come creazione di un oggetto List, probabilmente vorrai inizializzarlo indipendentemente da qualsiasi oggetto creato. Lingue diverse hanno meccanismi diversi, per esempio
// Java, C#
static List<Foo> myList = new List<Foo>();
// Java: static initializer block
static {
myList = new List<Foo>();
}
Se il valore di inizializzazione non è noto al momento della compilazione, ma è piuttosto fornito da un utente, questo si complica nuovamente. In alcune lingue è possibile parametrizzare le classi stesse, ad es. %codice%. Nelle lingue prive di un Metaobject Protocol, è possibile utilizzare Pattern di fabbrica : TheClass = new TheMetaClass(42); instance = new TheClass()
. All'inizio sembra simile all'esempio accoppiato sequenzialmente, ma con una fabbrica il sistema di tipi può garantire che l'inizializzazione sia avvenuta prima che venga creata un'istanza.