2012-03-15 17 views
8

Estoy trabajando en un proyecto que utiliza la inyección de dependencia a través de Ninject. Hasta el momento, está funcionando muy bien, y me gusta mucho DI, pero ahora he decidido que necesito serializar algunos objetos, y me resulta difícil hacerlo siguiendo patrones DI.Cómo serializar objetos creados por las fábricas

Decir que tengo una clase llamada Foo, que tiene una lista de bares, y los hace a través de una fábrica, de esta manera:

public class Foo 
{ 
    private List<Bar> _bars; 
    private BarFactory _barFactory; 

    ... 

    public void MakeBar() 
    { 
     _bars.Add(_barFactory.MakeBar()); 
    } 
} 

He aquí Bar, que se enviaran cuando se llama a _barFactory.MakeBar(). Quiero que Bar sea serializable:

public class Bar : ISerializable 
{ 
    private List<IPickle> _pickles; 
    private PickleFactory _pickleFactory; 

    public Bar(PickleFactory factory) 
    { 
     _pickleFactory = factory; 
    } 

    public void MakePickle(int x) 
    { 
     _pickles.Add(_pickleFactory.MakePickle(x)); 
    } 

    public void GetObjectData(SerializationInfo info, StreamingContext context) 
    { 
     //serialize member variables here 
    } 

    //Constructor called during deserialization 
    private Bar(SerializationInfo info, StreamingContext context) 
    { 
     //fill in member variables with data from SerializationInfo 
    } 
} 

Tenga en cuenta que Bar tiene su propia fábrica y una colección de encurtidos. Aquí está el problema: cuando se llama al constructor de deserialización de Bar, no tengo forma de obtenerlo en otra PickleFactory. El original PickleFactory fue otorgado a Bar por BarFactory, pero el constructor de deserialización no fue llamado por BarFactory.

Mi plan actual para resolver este problema sería extraer todos los miembros serializables de Bar en su propia clase llamada BarDataObject. Entonces haría BarDataObject serializable, pero no Bar en sí. Agregaría una función a BarFactory que acepta un BarDataObject como parámetro y construye una barra para usted llena con toda la información de BarDataObject.

Sin embargo, supongamos que Pickle también tiene clases de servicio que obtuvo de la fábrica que lo fabricó, que tampoco se pueden serializar. Así que tendría que extraer un DataObject de Pickle también, y mi BarDataObject tendría que contener un PickleDataObject. ¿Y supongamos que Pickle tuviera una variable miembro con una combinación de datos y servicios también? Tendría que crear y mantener un DataObject para eso también. Esto parece un verdadero fastidio, especialmente teniendo en cuenta que mi proyecto tiene muchas otras cosas que necesito serializar, y probablemente enfrentarán el mismo problema.

¿Existe una solución mejor? ¿Estoy haciendo algo mal, DI-wise? Acabo de empezar a trabajar con DI y Ninject, pero parece que no puedo encontrar a nadie que haya encontrado una buena manera de serializar objetos que se hayan inyectado con clases de servicio.

+0

¿Puedes agregar un constructor a tu clase 'BarFactory' que acepte la información de serialización? – Matthew

+3

¿Qué tipo de objeto es Foo? ¿Es un "nuevo" o un "inyectable"? (http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/). –

+0

@Matthew - Si lo hiciera, ¿cómo obtendría SerializationInfo de fábrica? Para cuando se ha llamado al constructor privado de Bar, es demasiado tarde para pedirle a la fábrica que fabrique el Bar, dado que ya estamos en el constructor de Bar, y Bar no sabe nada de BarFactory en ningún caso. – tandersen

Respuesta

9

En mi experiencia, solo las clases de servicio deberían tener dependencias, y las clases de servicio nunca deberían estar sujetas a serialización.

El hecho de que tenga una clase que desea serializar, pero que se basa en un servicio inyectado, me parece un olor de código.

Es difícil decir exactamente lo que estamos tratando de lograr con Bar, pero por lo que puedo ver, me gustaría sugerir haciendo Pickle ser un POCO, y usando un List<Pickle> en lugar de una clase personalizada Bar.

O, si Bar está destinado a tener otra información además de la serializable Pickles, que Bar a poco con un Pickles propiedad:

public class Bar 
{ 
    public string Name {get;set;} 
    public List<Pickle> Pickles {get;set;} 
} 

Debido POCOs no tener dependencias, que no deberán exigir fábricas, entonces esta clase debería ser completamente serializable. Si hay funciones complejas que desea realizar en Bar sy Pickle s, deben abstraerse en servicios de utilidad separados que toman Bar sy Pickle s como sus parámetros de método.

+0

Estoy de acuerdo con StripingWarrior: debe separar los datos y el comportamiento. – Steven

+0

Gracias por la respuesta, parece que podría funcionar para mi problema inmediato. Básicamente, está sugiriendo que retire todos los servicios de Bar y Pickle, y haga que Foo hable con esos servicios (como las fábricas). Multa. Pero, ¿y si luego también necesito serializar a Foo? ¿También hago de Foo un POCO y muevo todos los servicios de Foos, Bars y Pickles al tipo que creó Foo? ¿No va a dar lugar eventualmente a una gran clase fea que tenga demasiadas responsabilidades? – tandersen

+1

@tandersen: Parece que entiendes el principio. Es la misma estrategia sugerida en el artículo al que Mark Seeman se relacionó en su comentario. (Mark literalmente escribió el libro sobre DI en .NET, por cierto). Creo que le resultará bastante fácil separar las responsabilidades y mantener el tamaño de las clases pequeñas si sigue este patrón. De lo contrario, no dude en publicar una nueva pregunta y ver si la comunidad SO puede señalar algunos patrones útiles para su caso particular. – StriplingWarrior

Cuestiones relacionadas