Supponiamo che sto scrivendo un codice C ++ per visualizzare oggetti "Foo". Ho due modi per ottenere un "Foo": calcolarlo dai dati, o prendere i pezzi di un "Foo" precompilato e costruire un nuovo "Foo".
Ora, una volta che viene calcolato un "Foo", è garantito che sia buono per la visualizzazione, ma cambiarlo può rompere questa ipotesi. Pertanto, ho deciso di rappresentare "Foos" nel mio codice da una classe Foo che non ha metodi di muting: una volta costruita e inizializzata, non cambia.
Ma c'è un secondo modo per creare un "Foo": costruirlo da componenti di "Foo" precalcolati. Ho trovato diversi metodi per creare un Foo dai dati precompilati:
Metodo 1: metodi Costruttore / Statici
Forse il metodo più ovvio sarebbe aggiungere un nuovo costruttore o un metodo statico a Foo , chiamarlo fromPrecomputed , che leggerà i componenti del Foo precompilato e creerà un nuovo oggetto Foo , controllando che è valido Per spiegare perché mi piacerebbe evitarlo, devo complicare il mio esempio: diciamo che un componente di "Foo" è una raccolta di "Bars". Ora, in termini di implementazione, a volte una "Barra" è rappresentata come std::vector<std::vector<Bar> > , a volte come Bar array[][2] , a volte come std::vector<std::pair<Bar,Bar> > , e così via ... Potrei avere l'utente di riorganizzare i loro dati in un modulo standardizzato e un singolo costruttore per questo standard, ma questo potrebbe richiedere all'utente di eseguire una copia extra. Non voglio fornire un metodo statico per ogni formato: readPrecomputedFormatA , readPrecomputedFormatB e così via: questo ingombra l'API.
Metodo 2: Crea Foo mutabile
Se esponessi il metodo addBar(Bar) di Foo , potrei consentire all'utente di scorrere la loro raccolta di "Bar" a modo loro. Questo, tuttavia, rende Foo mutabile. Quindi ho potuto calcolare un Foo che abbia senso per la visualizzazione, quindi usare addBar per aggiungere un Bar che rende Foo non più un "Foo". Non va bene.
Metodo 3: Crea una classe "builder" di un amico
Creo una classe chiamata FooBuilder che ha il metodo addBar(Bar) esposto. Rendo FooBuilder un amico di Foo e aggiungo un costruttore a Foo che prende un FooBuilder . Chiamando questo costruttore, controlla che FooBuilder contenga un oggetto "Foo" valido, quindi scambia la sua rappresentazione vuota di Foo con ciò che è all'interno di FooBuilder . Tutti sono felici.
L'unica "confusione" sul metodo n. 3 è che richiede un'amicizia, ma credo valga la pena mantenere l'incapsulamento. Ma questo mi ha fatto pensare: è un modello stabilito? O c'è un altro, migliore modo di farlo che non conosco?