Diseño de código: Código duplicado o buena implementación

7

Estoy trabajando en la aplicación en C #, donde necesito serializar y deserializar algunas clases en / desde XML. Estas operaciones serán implementadas en Class Library. Elegí la clase XMLSerialization para serializar / deserializar estas clases en un archivo XML. Como saben, esta implementación utiliza la reflexión, que tiene la condición de que la clase serializada / deserializada debe tener un constructor sin parámetros. Sin embargo, la clase serializada tiene un parámetro que es obligatorio, que es un buen candidato como parámetro para el constructor, para asegurarse de que esté correctamente inicializado. He creado una clase de administrador para la serialización con dos métodos, uno para almacenar en archivo y otro para cargar desde archivo. Pensé en múltiples soluciones:

  1. Para la clase serializada, cree dos constructores, uno sin parámetros y otro con parámetro obligatorio. Esta clase puede ser fácilmente serializada, pero puede estar mal inicializada, lo que puede causar problemas (tal vez en otros lugares, por ejemplo, si la clase se usa en cualquier servicio web).
  2. Como esta implementación está en la biblioteca de clases, es posible crear la clase A (para serializar), que será pública y tendrá un constructor con un parámetro obligatorio. Los métodos de los administradores tomarán como parámetro esta clase A o la clase de retorno A después de que se cargue. Pero internamente crearía la clase B, que será 1: 1 como clase A, pero con un constructor sin parámetros para propósitos de serialización o deserialización. Esta clase B será interna, lo que significa que es visible solo en el ensamblaje actual, por lo que no puede suceder, que puede ser mal inicializada cuando la biblioteca de clases está vinculada. Sin embargo, esto provoca código duplicado. Imagina, que puede haber más clases como esta y más complejas. Esto significa otro gasto.
  3. La última solución, que me viene a la mente, es implementar la serialización por mí mismo utilizando Linq para XML. Esta solución es segura y sin código duplicado, pero la implementación es difícil para las clases grandes. O incluso peor, cuando queremos cambiar los nombres de los elementos o cambiar entre los elementos y los atributos, tenemos que revisar esta implementación cada vez con cuidado y cambiarla (en lugar de cambiar los atributos).

Mientras trato de encontrar una mejor solución (quizás haya otra, que no conozco) y de obtener buenos modales en las aplicaciones de programación. ¿Qué piensa usted, cuál es la mejor solución (tal vez en un escenario y en otro escenario otra solución)? ¿Para mantener un código duplicado o un código complejo (quizás de una experiencia real)?

    
pregunta joettriscik 13.05.2016 - 22:40

4 respuestas

3

Simplemente trataría las clases que va a serializar y deserializar como DTO y elegir qué utilidad Método que desea realizar la serialización / deserialización. De esa manera solo necesitas una clase para llevar la información.

Cada método de utilidad puede contener alguna validación de parámetros, si está preocupado por un parámetro incorrecto. Si desea mantener los métodos en el DTO, cree un par de métodos de fábrica que acepten una fuente de datos de serialización y devuelva un DTO.

Lo único que no haría es tener dos clases modelo solo porque desea crear una nueva automáticamente, pero una nueva manualmente con un constructor obligatorio. Eso crea dos lugares diferentes para sus datos y viola el principio de la Fuente única de la verdad.

Mantenlo simple, soldado.

    
respondido por el Robert Harvey 14.05.2016 - 00:26
2

Me resulta bastante molesto que muchas bibliotecas de serialización requieran constructores sin parámetros.

Con la capacidad de anotar parámetros, uno podría, en teoría, especificar asociaciones entre los parámetros del constructor y los elementos de serialización, para que la biblioteca de serialización pueda recopilar todos los elementos necesarios y pasarlos al constructor del objeto deserializado. Lamentablemente, todavía no he encontrado una biblioteca de serialización que ofrezca esta característica.

Además, la capacidad de serializar objetos con constructores parametrizados es necesaria incluso si no planeamos parametrizarlos con valores deserializados; por ejemplo, para implementar inyección de dependencia sin recurrir a la magia como Spring.NET.

Por lo que sé, la forma en que la mayoría de las personas manejan esto es tener dos conjuntos de clases separadas, una para la lógica de la aplicación con la que trabajar y otra solo para la serialización.

Resulta que esto no es tan malo, porque el modelo de datos con el que desea trabajar en la lógica de su aplicación generalmente no es exactamente el mismo que el modelo de datos que tiene sentido persistir.

Por ejemplo, es posible que desee tener la libertad de cambiar el modelo de datos de su aplicación mientras mantiene la compatibilidad con los archivos de serialización que se crearon a partir de versiones anteriores de su modelo de datos. Si todo lo que tiene es un conjunto de clases, en el momento en que realice un cambio en su modelo de datos, todos sus datos antiguos serán repentinamente ilegibles. Si mantiene su modelo de datos de aplicación por separado de su modelo de datos de serialización, entonces puede tener diferentes versiones (concurrentemente existentes) de su modelo de datos de serialización para usar con diferentes versiones de archivos de serialización existentes.

    
respondido por el Mike Nakis 14.05.2016 - 00:58
2

Mantenga esto pragmático: crear una gran cantidad de código duplicado o repetitivo debería ser un no-go, así como reimplementar un mecanismo de serialización maduro del marco por usted mismo. Así que morder la bala y proporcionar un constructor sin parámetros, esto, en realidad, no resulta ser tan malo como podría pensarse.

Puede hacer que el constructor sea privado y proporcionar un método estático dentro de la clase para la deserialización, lo que garantiza que el "atributo constructor obligatorio" se pase al objeto después de la deserialización. Eso hace que al menos sea improbable que alguien olvide establecer el atributo adicional.

    
respondido por el Doc Brown 14.05.2016 - 01:32
1

¿Qué hay de los dos métodos estáticos en la clase para seralizar y ser suilizante? El parámetro es un argumento de esta función y se almacena como una constante en algún lugar.

Si terminas teniendo muchos de estos objetos, crea una clase que tenga una lista de estos. Esto debería tener la capacidad de relacionar los métodos en toda la lista. También tomaría un delegado de filtro y le daría una nueva lista después del filtrado (no borre los datos antes de guardar). Sería también los dos métodos estáticos. La clase y el otro parámetro son argumentos.

    
respondido por el Akash 14.05.2016 - 12:35

Lea otras preguntas en las etiquetas