Potresti prendere il browser web / HTML route. Cioè, ogni volta che il tuo programma incontra alcune informazioni di configurazione che non capisce (come qualcosa aggiunto in una versione futura o rimosso da una versione precedente), lo ignora, e invece presta attenzione solo alle sezioni che capisce.
Questo include il requisito che le singole opzioni si comportino in modo coerente tra le versioni. In questo caso, o il tuo file di configurazione diventerà rapidamente contorto e ripetitivo.
Nel tuo esempio, V1
non sa A\A4
, quindi leggerà il resto del file, ma semplicemente lo ignorerà. Allo stesso modo, V2
non si preoccupa di A\A2
, quindi qualsiasi cosa in quella sezione viene ignorata da V2
. V3
reintroduce A\A2
, che è stato ignorato, anziché rimosso da V2
, quindi è ancora lì, pronto per essere letto e utilizzato.
La chiave per questo è mai rimuovere o modificare le opzioni esistenti . Puoi solo ignorare le opzioni esistenti o aggiungerne di nuove, a meno che tu non voglia creare una modifica irruzione .
Ecco un esempio più approfondito di un programma fittizio che utilizza un file di configurazione per ricordare alcune impostazioni della finestra. Supponi che il tuo file di configurazione V1 assomigli a questo:
[WindowDimensions]
width=400
height=300
[WindowLocation]
x=100
y=100
Quindi V1 ha una dimensione e una posizione per la finestra all'avvio. Ecco un piccolo codice pseudo per leggerlo e accedere alle variabili:
Dictionary loadConfig() {
String configFile = readFile("config.ini")
Dictionary config = parseIni(configFile) // parses the file into a tree of Dictionaries
config = fillMissingDefaults(config) // check for missing elements
// and fill any with (V1) defaults
Log("Window width: %d, height: %d",
config["WindowDimensions"]["width"],
config["WindowDimensions"]["height"]) // logs "Window width: 400, height: 300"
Log("Window location: (%d, %d)",
config["WindowLocation"]["x"],
config["WindowLocation"]["y"]) // logs "Window location: (100, 100)"
return config
}
Quindi, vengono visualizzati completamente display olografici 3D e tutti ne acquistano uno. V2 è scritto per supportarli. Sfortunatamente, la tecnologia è ancora nuova e le finestre sono sempre a schermo intero, anche se la risoluzione è regolabile. Quindi il file di configurazione V2 sarebbe simile a questo:
[WindowDimensions]
width=400
height=300
depth=200
[WindowLocation]
x=100
y=100
Abbiamo aggiunto una profondità a WindowDimensions
per tenere conto della terza dimensione. Nota che la sezione WindowLocation
è ancora lì. V2 non ne ha bisogno (tutto è a schermo intero), ma, dal momento che vogliamo mantenere la retrocompatibilità con V1, rimane lì. Ora, per il caricatore di configurazioni V2:
Dictionary loadConfig() {
String configFile = readFile("config.ini")
Dictionary config = parseIni(configFile) // identical to parseIni() in V1
config = fillMissingDefaults(config) // check for missing elements
// and fill any with (V2) defaults
Log("Window width: %d, height: %d, depth: %d",
config["WindowDimensions"]["width"],
config["WindowDimensions"]["height"],
config["WindowDimensions"]["depth"]) // logs "Window width: 400, height: 300, depth: 200"
return config
}
Si noti che il config
del dizionario restituito da parseIni()
contiene ancora WindowLocation
e tutti i suoi elementi secondari, ma, poiché V2 non gli interessa, semplicemente non lo usa. Allo stesso modo, V1 può ancora usare questo nuovo file di configurazione, anche se ora c'è un nuovo elemento nel dizionario config["WindowDimensions"]
per bambini.
Poiché config
contiene tutto da config.ini
, questo ha il vantaggio aggiunto di V2 di salvare le impostazioni di WindowLocation
nonostante non si sappia, semplicemente scrivendo l'intero dizionario.
Ora cosa succede se il file di configurazione è stato appena generato da V2 e quindi non ha alcuna menzione di WindowLocation
? Ecco a cosa servono le impostazioni predefinite. Se V1 legge un nuovo file di configurazione che in precedenza era stato scritto solo da V2, allora userebbe, ad esempio, un percorso predefinito di (300, 300) e lo salverà nel file di configurazione per l'utilizzo futuro di V1, insieme a tutti la roba V2 di cui "non" sa.