2012-03-15 89 views
8

我正在使用通过Ninject进行依赖注入的项目。到目前为止,它工作得很好,而且我很喜欢DI,但现在我已经决定需要序列化一些对象,并且我发现在DI模式之后很难做到这一点。如何序列化工厂创建的对象

说我有一个叫Foo的类,它有酒吧的列表,并让他们通过工厂,像这样:

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

    ... 

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

这里的酒吧,被当_barFactory.MakeBar()被调用做。我希望酒吧被序列:即酒吧拥有自己的工厂和泡菜的集合

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 
    } 
} 

通知。这是问题:当Bar的反序列化构造函数被调用时,我没有办法让它成为另一个PickleFactory。原始PickleFactory由BarFactory提供给Bar,但反序列化构造函数未由BarFactory调用。

我目前的计划,解决这个问题将是提取所有可序列化成员的酒吧变成它自己的类称为BarDataObject。然后我会使BarDataObject可序列化,但不是Bar本身。我将向BarFactory添加一个函数,该函数接受一个BarDataObject作为参数,并为您填充来自BarDataObject的所有信息的Bar。

但是,假设Pickle 有它从工厂得到的服务类,它不能被序列化。所以我必须从Pickle中提取一个DataObject,并且我的BarDataObject必须保持PickleDataObject。假设腌汁有一个混合了数据和服务的成员变量?我也必须为此创建和维护一个DataObject。这似乎是一个真正的失望,特别是考虑到我的项目还有很多其他需要序列化的东西,他们可能会面临同样的问题。

那么有没有更好的解决方案?我做错了什么,DI智者?我刚刚开始与DI和Ninject合作,但我似乎无法找到任何想出序列化注入了服务类的对象的好方法的人。

+0

你可以添加一个构造函数到接受序列化信息的'BarFactory'类吗? – Matthew 2012-03-15 21:02:08

+3

Foo是什么类型的对象?它是一种“新的”还是“可注射的”? (http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/)。 – 2012-03-15 21:11:08

+0

@Matthew - 如果我这样做,我将如何获得SerializationInfo到工厂?当Bar的私有构造函数被调用时,要求工厂制作Bar已经太迟了,因为我们已经在Bar构造函数中了,Bar在任何情况下都不知道BarFactory。 – tandersen 2012-03-15 21:16:13

回答

9

根据我的经验,只有服务类应该有依赖关系,服务类不应该被序列化。

事实上,你有一个类,你想序列化,但依赖于一个注入服务,似乎对我来说是一种代码味道。

这很难告诉你想与Bar完成什么,但是从我所看到的,我建议做Pickle是一个POCO,并使用List<Pickle>不是自定义Bar类。

或者,如果Bar旨在具有其他序列化的信息,除了泡菜,使Bar一个POCO用泡菜属性:

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

因为波苏斯不会有依赖性,它们不应该要求的工厂,所以这个类应该是完全可序列化的。如果您想要在Bar s和Pickle s上执行复杂的功能,应将它们抽象为单独的实用程序服务,它们将Bar s和Pickle s作为其方法参数。

+0

我同意StripingWarrior:你应该分开数据和行为。 – Steven 2012-03-15 21:30:29

+0

感谢您的回答,似乎它可能适用于我眼前的问题。基本上,你建议我把Bar和Pickle的所有服务都拿走,让Foo和那些服务(比如工厂)交谈?精细。但是如果后来我还需要序列化Foo呢?我是否也让Foo成为POCO,并将Foos,Bars和Pickles的所有服务移入制作Foo的人?最终是不是会导致一个丑陋的班级承担太多的责任? – tandersen 2012-03-15 22:39:56

+1

@tandersen:这听起来像你理解原理。 Mark Seeman在他的评论中提到的文章中提出了同样的策略。 (顺便说一下,Mark在.NET中写了一本关于DI的书)。我认为如果你遵循这种模式,你会发现分离责任和保持小班的规模很容易。如果没有,请随时发布一个新问题,看看SO社区是否可以针对您的特定情况指出一些有用的模式。 – StriplingWarrior 2012-03-15 22:58:00

相关问题