Copia difensiva nella classe cliente o nella classe di servizio?

3

Ho un metodo di servizio che riceve parametri come Map . Dovrò aggiungere nuovi attributi a questa mappa all'interno del servizio. Se si passa l'oggetto Map originale al parametro anziché una copia, l'oggetto dei parametri originali verrà modificato.

La mia domanda qui è: quale classe è responsabile per mantenere l'integrità dell'oggetto parametro?

La classe% co_de dovrebbe superare una copia nel caso in cui Client modifichi i parametri, o dovrebbe il 'Service Service Client'?

public class Client{
    public void search(){
         Map<String, Object> parameters = new HashMap<>();

         // defensive parameters copy here?
         new Service().search(parameters);
         // parameters can be changed if I don't use a defensive copy
    }
}

public class Service{
    public ... search(Map<String, Object> parameters){
        // defensive parameters copy here?
        parameters.put("newParam", 1);
    }    
}
    
posta Renato Dinhani 31.10.2014 - 17:08
fonte

2 risposte

3

In breve: se il Cliente si preoccupa dei parametri dopo il fatto, allora dovrebbe creare una copia difensiva profonda della mappa (non solo la mappa, ma anche i valori). Se il Servizio deve modificare la raccolta, deve creare una copia difensiva. Ma possiamo fare di meglio ...

Per passare in sicurezza la Mappa (ma non per passare in sicurezza il suo contenuto), il Cliente non ha bisogno di copiare la mappa, può usare Collections.unmodifiableMap () per creare una vista non modificabile.

Se il Cliente si preoccupa della mappa dopo il fatto, allora probabilmente si preoccupa anche del contenuto della mappa. Il Cliente sa come fare una copia difensiva di tutte le sottoclassi di Oggetto che saranno incluse nella mappa? Se gli oggetti reali in uso sono tipi immutabili, il Cliente non ha bisogno di sapere come fare una copia difensiva di essi, e il passaggio della collezione non modificabile è sufficiente.

Se il Object s utilizzato è di tipo mutabile, il Cliente deve crearne una copia profonda, o deve inviare copie (o immutabili) di qualunque Servizio abbia a che fare con la mappa. Ad esempio, se il servizio in realtà intende chiamare .toString() su tutti gli oggetti nella mappa, è possibile che il contratto possa essere modificato in modo che il servizio accetti un Map<String, String> . Forse Service è un po 'più intelligente e può anche gestire Object s che potrebbe implementare Collection , e usa il metodo .toString() per non-collezioni, ma itera su raccolte e chiama .toString() su ognuna di quelle. Se questo è il caso, forse il Cliente può contenere la logica per arrivare a quel passo, e il contratto è cambiato in Map<String, List<String>> ; ricorda di passare le viste non modificabili delle collezioni e non le raccolte stesse.

Ove possibile, preferisco passare viste non modificabili o raccolte immutabili (ad esempio, dalla libreria Guava), contenenti oggetti immutabili. Se Service ha effettivamente bisogno di modificare la raccolta dovrebbe fare una copia (perché dovrebbe sapere che gli effetti collaterali sono generalmente indesiderabili), se necessario profonda. Scoprirai di provare se Service produce effetti collaterali, perché genererà un'eccezione quando proverai a modificare la collezione non modificabile / immutabile, nel qual caso il Cliente deve creare una copia mutevole della collezione, passarla e poi mai usalo di nuovo.

    
risposta data 01.11.2014 - 00:50
fonte
4

Come regola generale, non scrivo metodi che hanno effetti collaterali quando si scrive un'interfaccia per essere chiamata dagli altri. I metodi con effetti collaterali sono in generale cattivi, anche se potrebbe accadere che tu esegua qualche modifica di stato minore diversa da quella prevista.

Anche se il cliente non ha bisogno di usare questi dati, non penso che ipotesi come questa dovrebbero essere fatte quando si tratta dell'interfaccia. Mi spingerei fino a passare un ImmutableDictionary al server per chiarire questo fatto Il server dovrebbe utilizzare questi parametri e applicarli. In questo caso, probabilmente dovresti semplicemente copiarli, anche se il server può fare con quelle informazioni qualunque cosa voglia. Non è in grado di cambiare quei dati, a meno che, naturalmente, non fosse l'azione prevista, a mio modesto parere.

    
risposta data 31.10.2014 - 18:24
fonte

Leggi altre domande sui tag