Na ogół unikam, aby klasa wiedziała, jak się serializować, z kilku powodów. Po pierwsze, jeśli chcesz (od) serializować do / z innego formatu, musisz teraz zanieczyścić model tą dodatkową logiką. Jeśli dostęp do modelu uzyskuje się przez interfejs, wówczas również zanieczyszczasz umowę.
public class Image
{
public void toJPG(String filePath) { ... }
public Image fromJPG(String filePath) { ... }
}
Ale co, jeśli chcesz serializować to do / z PNG i GIF? Teraz klasa staje się
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) { ... }
}
Zamiast tego zazwyczaj lubię używać wzoru podobnego do następującego:
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) { ... }
}
W tym momencie jednym z zastrzeżeń dotyczących tego projektu jest to, że serializatory muszą znać identity
obiekt, który serializuje. Niektórzy twierdzą, że jest to zły projekt, ponieważ implementacja wycieka poza klasę. Ryzyko / zysk zależy od ciebie, ale możesz nieco ulepszyć klasy, aby zrobić coś takiego
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);
}
}
Jest to bardziej ogólny przykład, ponieważ obrazy zwykle mają metadane, które są z nimi zgodne; rzeczy takie jak poziom kompresji, przestrzeń kolorów itp., które mogą skomplikować proces.