So che gli oggetti immutabili sono preferiti agli oggetti mutabili per il ragionamento e la manutenzione. Ma nelle occasioni in cui una classe immutabile ha dei costi, lascia che ti spieghi con un semplice esempio:
class Mutable
{
private int i;
public Mutable(int _i) { i = _i}
public void Print() // impure function
{
print(i);
i++; // logic inside
}
}
... caller
Immutable m = new Mutable(1);
while (true)
{
m.Print();
}
Lo chiamo mutabile perché il suo stato interno cambia e Print
varia su ogni chiamata.
Versus.
class Immutable
{
private int i;
public Mutable(int _i) { i = _i}
public int Print() // pure function
{
print(i);
return i; // returns its state
}
}
... caller
int i =1;
while (true)
{
Immutable im = new Immutable(i);
i = im.Print(); // get the previous obeject's state
i++; // logic outside
}
Preferire una soluzione immutabile mi fa fare molto lavoro al di fuori di un oggetto che avrebbe dovuto incapsulare quella logica.
Il mio problema reale ( puoi saltare l'esempio di seguito )
Ho una classe che disegna un testo in una casella:
class TextDrawer
{
private string text;
private Rectangle box;
public TextDrawer(_text, _box) {...}
public void DrawTextInBox()
{
}
}
È probabile che Text
trabocchi dalla scatola e parte di essa non sia stata scritta. Dovrei conoscere la parte non scritta rimanente per disegnarla in una nuova casella (infatti faccio un'istantanea della vecchia casella come fotogramma video e devo creare una nuova cornice per il testo rimanente per realizzare un video del testo)
Ora ho due opzioni:
1- Rendi mutabile TextDrawer
(il suo stato interno è mutabile) e DrawTextInBox
una funzione non pura e su ogni chiamata disegna la parte restante del testo nella casella.
class TextDrawer
{
private string text;
private Rectangle box;
private string remaining;
public TextDrawer(_text, _box)
{
remaining = text = _text;
box = _box;
}
public void DrawTextInBox()
{
draw as you can from remaining
update remaining part;
}
}
2- Conserva TextDrawer
immutable e DrawTextInBox
una funzione pura che restituisce la parte rimanente, quindi il chiamante dovrebbe tenere traccia del rimanente e passarlo di nuovo a TextDrawer
o istanziare un nuovo TextDrawer
di il testo rimanente fino a quando non c'è nulla da scrivere.
class TextDrawer
{
private string text;
private Rectangle box;
public TextDrawer(_text, _box) { ... }
public string DrawTextInBox()
{
draw as you can from text;
return remaining part;
}
}
Il secondo approccio è immutabile, ma in realtà sposta la responsabilità di tracciare la parte rimanente al di fuori della classe. Il primo approccio è mutabile, ma incapsula la logica e ha solo bisogno di una chiamata a DrawTextInBox
per disegnare la parte rimanente.
Domanda : la logica degli esempi precedenti era semplice ma questa logica poteva essere più complessa, quindi non so se estrarre questa logica da una classe per renderla immutabile o lasciare è mutabile e ha la logica dentro?