La serializzazione e la deserializzazione dovrebbero essere la responsabilità della classe che viene serializzata?

15

Sono attualmente nella (ri) fase di progettazione di diverse classi di modelli di un'applicazione C # .NET. (Modello come in M di MVC). Le classi modello hanno già molti dati, comportamenti e interrelazioni ben disegnati. Sto riscrivendo il modello da Python a C #.

Nel vecchio modello Python, penso di vedere una verruca. Ogni modello sa come serializzare se stesso, e la logica di serializzazione ha niente da fare con il resto del comportamento di una qualsiasi delle classi. Ad esempio, immagina:

  • Image class con un .toJPG(String filePath) .fromJPG(String filePath) metodo
  • ImageMetaData class con un metodo .toString() e .fromString(String serialized) .

Puoi immaginare come questi metodi di serializzazione non siano coerenti con il resto della classe, tuttavia è possibile garantire solo la classe per conoscere dati sufficienti per serializzare se stessa.

È prassi comune per una classe sapere come serializzare e deserializzare se stessa? O mi manca uno schema comune?

    
posta kdbanman 04.07.2015 - 02:41
fonte

2 risposte

14

In genere evito che la classe sappia come serializzare se stessa, per un paio di motivi. Innanzitutto, se vuoi (de) serializzare su / da un formato diverso, ora devi inquinare il modello con quella logica extra. Se si accede al modello tramite un'interfaccia, si inquina anche il contratto.

public class Image
{
    public void toJPG(String filePath) { ... }

    public Image fromJPG(String filePath) { ... }
}

Ma cosa succede se vuoi serializzarlo su / da un PNG e GIF? Ora la classe diventa

public class Image
{
    public void toJPG(String filePath) { ... }

    public Image fromJPG(String filePath) { ... }

    public void toPNG(String filePath) { ... }

    public Image fromPNG(String filePath) { ... }

    public void toGIF(String filePath) { ... }

    public Image fromGIF(String filePath) { ... }
}

Invece, in genere mi piace usare un modello simile al seguente:

public interface ImageSerializer
{
    void serialize(Image src, Stream outputStream);

    Image deserialize(Stream inputStream);
}

public class JPGImageSerializer : ImageSerializer
{
    public void serialize(Image src, Stream outputStream) { ... }

    public Image deserialize(Stream inputStream) { ... }
}

public class PNGImageSerializer : ImageSerializer
{
    public void serialize(Image src, Stream outputStream) { ... }

    public Image deserialize(Stream inputStream) { ... }
}

public class GIFImageSerializer : ImageSerializer
{
    public void serialize(Image src, Stream outputStream) { ... }

    public Image deserialize(Stream inputStream) { ... }
}

Ora, a questo punto, uno degli avvertimenti con questo motivo è che i serializzatori hanno bisogno di conoscere l' identity dell'oggetto è serializzazione. Alcuni direbbero che questo è un cattivo design, in quanto l'implementazione perde fuori dalla classe. Il rischio / la ricompensa di questo dipende solo da te, ma potresti modificare leggermente le classi per fare qualcosa di simile

public class Image
{
    public void serializeTo(ImageSerializer serializer, Stream outputStream)
    {
        serializer.serialize(this.pixelData, outputStream);
    }

    public void deserializeFrom(ImageSerializer serializer, Stream inputStream)
    {
        this.pixelData = serializer.deserialize(inputStream);
    }
}

Questo è più di un esempio generale, in quanto le immagini di solito hanno metadati che lo accompagnano; cose come livello di compressione, spazio colore, ecc. che possono complicare il processo.

    
risposta data 04.07.2015 - 05:22
fonte
3

La serializzazione è un problema in due parti:

  1. Informazioni su come creare un'istanza di una classe alias struttura .
  2. Informazioni su come persistere / trasferire le informazioni necessarie per creare un'istanza di una classe aka mechanics .

Per quanto possibile, la struttura dovrebbe essere mantenuta separata dalla meccanica . Ciò aumenta la modularità del tuo sistema. Se si seppelliscono le informazioni al secondo posto all'interno della classe, si interrompe la modularità perché ora la classe deve essere modificata per tenere il passo con i nuovi modi di serializzazione (se vengono).

Nel contesto della serializzazione delle immagini manterrai le informazioni sulla serializzazione separate dalla classe stessa e tienilo piuttosto negli algoritmi che possono determinare il formato della serializzazione - quindi, classi diverse per JPEG, PNG, BMP ecc. Se Domani arriva un nuovo algoritmo di serializzazione che semplicemente codifica quell'algoritmo e il tuo contratto di classe rimane invariato.

Nel contesto di IPC, è possibile mantenere la classe separata e quindi dichiarare in modo selettivo le informazioni necessarie per la serializzazione (mediante annotazioni / attributi). Quindi l'algoritmo di serializzazione può decidere se utilizzare JSON, Google Protocol Buffers o XML per la serializzazione. Può anche decidere se usare il parser Jackson o il parser personalizzato - ci sono molte opzioni che si potrebbero ottenere facilmente quando si progetta in modo modulare!

    
risposta data 04.07.2015 - 06:07
fonte

Leggi altre domande sui tag