Classe con membri che sono mutabili durante la creazione ma immutabili in seguito

22

Ho un algoritmo che crea una collezione di oggetti. Questi oggetti sono mutabili durante la creazione, dal momento che iniziano con molto poco, ma poi vengono popolati con dati in punti diversi all'interno dell'algoritmo.

Una volta completato l'algoritmo, gli oggetti non devono mai essere modificati, tuttavia vengono utilizzati da altre parti del software.

In questi scenari, è considerata una buona pratica avere due versioni della classe, come descritto di seguito?

  • Il mutabile viene creato dall'algoritmo, quindi
  • Al completamento dell'algoritmo, i dati vengono copiati in oggetti immutabili che vengono restituiti.
posta Paul Richards 27.07.2015 - 10:55
fonte

3 risposte

46

Puoi forse utilizzare il schema di build . Usa un oggetto 'builder' separato con lo scopo di raccogliere i dati necessari e quando tutti i dati vengono raccolti crea l'oggetto reale. L'oggetto creato può essere immutabile.

    
risposta data 27.07.2015 - 11:03
fonte
24

Un modo semplice per ottenere ciò sarebbe avere un'interfaccia che permetta di leggere le proprietà e chiamare solo i metodi di sola lettura e una classe che implementa quell'interfaccia che consente anche di scrivere quella classe.

Il tuo metodo che lo crea, si occupa del primo e poi restituisce quest'ultimo fornendo solo un'interfaccia di sola lettura con cui interagire. Ciò non richiederebbe la copia e consente di ottimizzare facilmente i comportamenti che si desidera rendere disponibili al chiamante anziché al creatore.

Prendi questo esempio:

public interface IPerson 
{
    public String FirstName 
    {
        get;
    }

    public String LastName 
    {
        get;
    }
} 

public class PersonImpl : IPerson 
{
    private String firstName, lastName;

    public String FirstName 
    {
        get { return firstName; }
        set { firstName = value; }
    }

    public String LastName 
    {
        get { return lastName; }
        set { lastName = value; }
    }
}

class Factory 
{
    public IPerson MakePerson() 
    {
        PersonImpl person = new PersonImpl();
        person.FirstName = 'Joe';
        person.LastName = 'Schmoe';
        return person;
    }
}

L'unico svantaggio di questo approccio è che si potrebbe semplicemente lanciarlo nella classe di implementazione. Se fosse una questione di sicurezza, allora semplicemente usare questo approccio è insufficiente. Una soluzione per questo è che puoi creare una classe facade per avvolgere la classe mutabile, che presenta semplicemente un'interfaccia che il chiamante funziona con e non può avere accesso all'oggetto interno.

In questo modo, nemmeno il casting ti aiuterà. Entrambi possono derivare dalla stessa interfaccia di sola lettura, ma lanciare l'oggetto restituito ti darà solo la classe Facade, che è immutabile in quanto non cambia lo stato sottostante della classe mutevole incapsulata.

Vale la pena ricordare che questo non segue la tendenza tipica in cui un oggetto immutabile viene costruito una volta per tutte attraverso il suo costruttore. Comprensibilmente, potresti dover gestire molti parametri, ma dovresti chiederti se tutti questi parametri devono essere definiti in anticipo o se possono essere introdotti in seguito. In tal caso, dovrebbe essere utilizzato un semplice costruttore con solo i parametri richiesti. In altre parole, non utilizzare questo modello se copre un altro problema nel programma.

    
risposta data 27.07.2015 - 11:15
fonte
8

Puoi usare il pattern Builder come dice @JacquesB, o in alternativa, perché in realtà questi oggetti hanno sono mutabili durante la creazione?

In altre parole, perché il processo di creazione deve essere distribuito nel tempo, anziché passare tutti i valori richiesti nel costruttore e creare istanze in un colpo solo?

Perché il Builder potrebbe essere una buona soluzione per il problema sbagliato.

Se il problema è che ti ritrovi con un costruttore che ha 10 parametri lunghi e vorresti attenuarlo costruendo l'oggetto poco a poco, potrebbe indicare che il design è incasinato, e questi 10 valori dovrebbe essere "insaccato" / raggruppato in pochi oggetti ... o l'oggetto principale diviso in alcuni più piccoli ...

In tal caso, attenersi sempre all'immutabilità, basta migliorare il design.

    
risposta data 27.07.2015 - 11:10
fonte

Leggi altre domande sui tag