Я, як правило, уникаю, щоб клас з кількох причин знав, як серіалізувати себе. По-перше, якщо ви хочете (де) серіалізувати в / з іншого формату, тепер вам потрібно забруднити модель такою додатковою логікою. Якщо доступ до моделі здійснюється через інтерфейс, ви також забруднюєте контракт.
public class Image
{
public void toJPG(String filePath) { ... }
public Image fromJPG(String filePath) { ... }
}
Але що робити, якщо ви хочете серіалізувати його до / з PNG та GIF? Тепер класом стає
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) { ... }
}
Натомість мені зазвичай подобається використовувати візерунок, подібний до наступного:
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) { ... }
}
На даний момент, одним із застережень із такою конструкцією є те, що серіалізатори повинні знати identity
об'єкт, який він серіалізує. Деякі кажуть, що це поганий дизайн, оскільки впровадження протікає поза класом. Ризик / винагорода за це дійсно залежить від вас, але ви можете трохи налаштувати класи, щоб зробити щось подібне
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);
}
}
Це більше загальний приклад, оскільки зображення зазвичай мають метадані, які йдуть разом з ним; такі речі, як рівень стиснення, кольоровий простір тощо, що може ускладнити процес.