Mutevole con logica interna o immutabile con logica esterna?

5

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?

    
posta Ahmad 14.04.2015 - 08:54
fonte

1 risposta

3

Nel tuo esempio:

int i =1;
while (true)
{
    Immutable im = new Immutable(i);
    i = im.Print(); // get the previous obeject's state
    i++; // logic outside
}

Immutable dovrebbe restituire il nuovo stato che la soluzione mutabile avrebbe memorizzato, cioè i + 1 . Hai già il vecchio stato . Restituire il vecchio stato e costringere il chiamante ad aggiornare lo stato stesso è inutile. Lo hai fatto correttamente nel tuo vero problema, in cui restituisci la parte rimanente della stringa invece della stringa originale.

Dovresti preferire una soluzione immutabile se non hai buone ragioni altrimenti. Una buona ragione potrebbe essere che la soluzione immutabile è troppo lenta, ma prima devi definire chiaramente cosa è "abbastanza veloce" e profilare l'applicazione per dimostrare che il collo di bottiglia è la tua classe immutabile e che l'alternativa mutevole risolverà il problema.

    
risposta data 14.04.2015 - 18:07
fonte