J'évite généralement que la classe sache comment se sérialiser, pour plusieurs raisons. Tout d'abord, si vous souhaitez (dé) sérialiser vers / à partir d'un format différent, vous devez maintenant polluer le modèle avec cette logique supplémentaire. Si le modèle est accessible via une interface, vous polluez également le contrat.
public class Image
{
public void toJPG(String filePath) { ... }
public Image fromJPG(String filePath) { ... }
}
Mais que se passe-t-il si vous souhaitez le sérialiser vers / depuis un PNG et un GIF? Maintenant, la classe devient
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) { ... }
}
Au lieu de cela, j'aime généralement utiliser un modèle similaire au suivant:
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) { ... }
}
Maintenant, à ce stade, l'une des mises en garde avec cette conception est que les sérialiseurs doivent connaître identity
l'objet de la sérialisation. Certains diront que c'est une mauvaise conception, car l'implémentation fuit en dehors de la classe. Le risque / récompense de cela dépend vraiment de vous, mais vous pouvez légèrement modifier les cours pour faire quelque chose comme
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);
}
}
Il s'agit plus d'un exemple général, car les images ont généralement des métadonnées qui vont avec; des choses comme le niveau de compression, l'espace colorimétrique, etc. qui peuvent compliquer le processus.
ImageSerializer
interface sont écrites), l'ImageSerializer
interface devra également se développer. EX: Un nouveau format prend en charge la compression facultative, les précédents ne le faisaient pas -> ajouter une configurabilité de compression à l'ImageSerializer
interface. Mais alors, les autres formats sont encombrés de fonctionnalités qui ne s'appliquent pas à eux. Plus j'y pense, moins je pense que l'héritage s'applique ici.void serialize(Image image, Stream outputStream, SerializerSettings settings);
Ensuite, il s'agit simplement de câbler la logique de compression et de métadonnées existante à la nouvelle méthode.La sérialisation est un problème en deux parties:
Dans la mesure du possible, la structure doit être séparée de la mécanique . Cela augmente la modularité de votre système. Si vous enfouissez les informations sur # 2 dans votre classe, vous rompez la modularité car maintenant votre classe doit être modifiée pour suivre le rythme des nouvelles méthodes de sérialisation (si elles se présentent).
Dans le contexte de la sérialisation d'image, vous devez conserver les informations sur la sérialisation séparément de la classe elle-même et les conserver plutôt dans les algorithmes qui peuvent déterminer le format de sérialisation - par conséquent, différentes classes pour JPEG, PNG, BMP, etc. Si demain un nouveau l'algorithme de sérialisation vient avec vous codez simplement cet algorithme et votre contrat de classe reste inchangé.
Dans le contexte d'IPC, vous pouvez séparer votre classe, puis déclarer sélectivement les informations nécessaires à la sérialisation (par annotations / attributs). Ensuite, votre algorithme de sérialisation peut décider d'utiliser JSON, les tampons de protocole Google ou XML pour la sérialisation. Il peut même décider d'utiliser l'analyseur Jackson ou votre analyseur personnalisé - il existe de nombreuses options que vous obtiendrez facilement lorsque vous concevez de manière modulaire!
la source