Ich vermeide es im Allgemeinen aus mehreren Gründen, dass die Klasse weiß, wie sie sich selbst serialisiert. Wenn Sie ein anderes Format (de) serialisieren möchten, müssen Sie das Modell jetzt mit dieser zusätzlichen Logik belasten. Wird auf das Modell über eine Schnittstelle zugegriffen, verschmutzen Sie auch den Vertrag.
public class Image
{
public void toJPG(String filePath) { ... }
public Image fromJPG(String filePath) { ... }
}
Aber was ist, wenn Sie es zu / von einem PNG und GIF serialisieren möchten? Jetzt wird die Klasse
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) { ... }
}
Stattdessen verwende ich normalerweise gerne ein Muster, das dem folgenden ähnelt:
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) { ... }
}
Zu diesem Zeitpunkt besteht eine der Einschränkungen bei diesem Entwurf darin, dass die Serialisierer wissen müssen, welches identity
Objekt serialisiert wird. Einige würden sagen, dass dies ein schlechtes Design ist, da die Implementierung außerhalb der Klasse leckt. Das Risiko / die Belohnung dafür liegt in der Tat bei Ihnen, aber Sie können die Klassen leicht anpassen, um so etwas wie zu tun
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);
}
}
Dies ist eher ein allgemeines Beispiel, da Bilder normalerweise Metadaten haben, die damit einhergehen. Dinge wie Komprimierungsgrad, Farbraum usw., die den Prozess erschweren können.
ImageSerializer
Erstellung weiterer Implementierungen der Schnittstelle) auch dieImageSerializer
Schnittstelle wachsen muss. EX: Ein neues Format unterstützt die optionale Komprimierung, die vorherigen Formate haben keine -> zusätzliche Konfigurationsmöglichkeit für die Komprimierung derImageSerializer
Benutzeroberfläche. Aber dann sind die anderen Formate mit Funktionen überfüllt, die für sie nicht zutreffen. Je mehr ich darüber nachdenke, desto weniger denke ich, dass Vererbung hier gilt.void serialize(Image image, Stream outputStream, SerializerSettings settings);
Dann müssen nur die vorhandene Komprimierungs- und Metadatenlogik mit der neuen Methode verknüpft werden.Die Serialisierung ist ein zweiteiliges Problem:
Die Struktur sollte so weit wie möglich von der Mechanik getrennt sein . Dies erhöht die Modularität Ihres Systems. Wenn Sie die Informationen zu # 2 in Ihrer Klasse vergraben, brechen Sie die Modularität, da Ihre Klasse jetzt geändert werden muss, um mit den neuen Möglichkeiten der Serialisierung Schritt zu halten (sofern sie verfügbar sind).
Im Zusammenhang mit der Bildserialisierung würden Sie die Informationen zur Serialisierung von der Klasse selbst trennen und sie eher in den Algorithmen aufbewahren, die das Format der Serialisierung bestimmen können - daher verschiedene Klassen für JPEG, PNG, BMP usw. Wenn morgen eine neue Der Serialisierungsalgorithmus wird mitgeliefert. Codieren Sie einfach diesen Algorithmus, und Ihr Klassenvertrag bleibt unverändert.
Im Kontext von IPC können Sie Ihre Klasse getrennt halten und anschließend die für die Serialisierung erforderlichen Informationen selektiv deklarieren (durch Anmerkungen / Attribute). Dann kann Ihr Serialisierungsalgorithmus entscheiden, ob Sie JSON, Google Protocol Buffers oder XML für die Serialisierung verwenden. Es kann sogar entscheiden, ob Sie den Jackson-Parser oder Ihren benutzerdefinierten Parser verwenden möchten - es gibt viele Optionen, die Sie bei modularem Design leicht finden!
quelle