Geralmente, evito que a classe saiba como se serializar por alguns motivos. Primeiro, se você deseja (des) serializar de / para um formato diferente, agora precisa poluir o modelo com essa lógica extra. Se o modelo for acessado por meio de uma interface, você também poluirá o contrato.
public class Image
{
public void toJPG(String filePath) { ... }
public Image fromJPG(String filePath) { ... }
}
Mas e se você quiser serializá-lo para / de um PNG e GIF? Agora a turma se torna
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) { ... }
}
Em vez disso, normalmente gosto de usar um padrão semelhante ao seguinte:
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) { ... }
}
Agora, neste ponto, uma das advertências com esse design é que os serializadores precisam conhecer identity
o objeto que está serializando. Alguns diriam que esse design é ruim, pois a implementação vaza para fora da classe. O risco / recompensa é realmente de sua responsabilidade, mas você pode ajustar levemente as aulas para fazer algo como
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);
}
}
Este é mais um exemplo geral, pois as imagens geralmente têm metadados que os acompanham; coisas como nível de compactação, espaço de cores etc. que podem complicar o processo.
ImageSerializer
interface são gravadas), aImageSerializer
interface também precisará crescer. EX: Um novo formato suporta compactação opcional, os anteriores não -> adicionaram configurabilidade de compactação àImageSerializer
interface. Porém, os outros formatos estão repletos de recursos que não se aplicam a eles. Quanto mais eu penso sobre isso, menos acho que a herança se aplica aqui.void serialize(Image image, Stream outputStream, SerializerSettings settings);
Então é apenas um caso de conectar a lógica de compressão e metadados existente ao novo método.A serialização é um problema em duas partes:
Na medida do possível, a estrutura deve ser mantida separada da mecânica . Isso aumenta a modularidade do seu sistema. Se você enterrar as informações no 2 da sua classe, interromperá a modularidade, porque agora sua classe deve ser modificada para acompanhar as novas formas de serialização (se elas surgirem).
No contexto da serialização de imagens, você deve manter as informações sobre serialização separadas da própria classe e mantê-las nos algoritmos que podem determinar o formato da serialização - portanto, diferentes classes para JPEG, PNG, BMP etc. o algoritmo de serialização aparece, você simplesmente codifica esse algoritmo e seu contrato de classe permanece inalterado.
No contexto do IPC, você pode manter sua classe separada e, em seguida, declarar seletivamente as informações necessárias para serialização (por anotações / atributos). Em seguida, seu algoritmo de serialização pode decidir se deseja usar JSON, Google Protocol Buffers ou XML para serialização. Ele pode até decidir se deve usar o analisador Jackson ou o analisador personalizado - há muitas opções que você obteria facilmente ao projetar de forma modular!
fonte