2012-03-15 11 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は独自の工場とピクルスのコレクションを持っていることに注意してください。ここに問題があります:Barの逆シリアル化コンストラクタが呼び出されると、別のPickleFactoryを取得する方法がありません。元のPickleFactoryはBarFactoryによってBarに渡されましたが、逆シリアル化コンストラクタはBarFactoryによって呼び出されませんでした。

この問題を解決する私の現在の計画は、Barのすべてのシリアライズ可能なメンバーをBarDataObjectという独自のクラスに抽出することです。それからBarDataObjectを直列化可能にしますが、Bar自体は作成しません。 BarDataObjectをパラメータとして受け取り、BarDataObjectのすべての情報を埋め込んだBarを構築するBarFactoryに関数を追加します。

しかし、Pickle でもには、それを作成した工場から入手したサービスクラスがあり、それもシリアル化できません。だから、PickleからDataObjectを抽出する必要があり、BarDataObjectはPickleDataObjectを保持する必要があります。また、Pickleにもデータとサービスが混在するメンバー変数があるとしますか?私はそのためにもDataObjectを作成し維持する必要があります。私のプロジェクトには、シリアル化する必要がある他の多くのものがあり、おそらく同じ問題に直面するだろうと考えると、これは本当に酷いようです。

もっと良い解決策がありますか?私は何か間違っているのですか?DI賢明ですか?私はDIとNinjectで作業を始めましたが、サービスクラスを注入されたオブジェクトを直列化する良い方法を思いつく人はいません。

+0

シリアル化情報を受け取る 'BarFactory'クラスにコンストラクタを追加できますか? – Matthew

+3

Fooはどのような種類のオブジェクトですか?それは「新鮮な」か「注射可能な」か? (http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/)。 –

+0

@Matthew - 私が行った場合、SerializationInfoはどのように工場に持ち込まれますか? Barのプライベートコンストラクタが呼び出された時点で、既にBarコンストラクタに入っているので、Barを作るように工場に依頼するのは時期尚早です。BarはBarFactoryについて知らないでしょう。 – tandersen

答えて

9

私の経験では、サービスクラスだけが依存関係を持ち、サービスクラスは直列化の対象にならないようにしてください。

シリアル化したいクラスがありますが、注入されたサービスに依存しているという事実は、コードの匂いのようです。

それはあなたがBarで達成しようとしている正確に何を伝えることは困難ですが、私は何を見ることができますから、私はPickleはPOCOも作り、およびカスタムBarクラスの代わりにList<Pickle>を使用してお勧めしたいです。

あるいは、Barは漬物以外の直列化可能な情報を有することが意図されている場合、ピクルスプロパティでBar POCOします

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

POCOSが依存関係を持っていないので、彼らは工場を必要とすべきではありません、このクラスは完全に直列化可能でなければなりません。 BarPickleで実行したい複雑な関数がある場合は、それらのメソッドのパラメータとしてBarPickleを使用する別々のユーティリティサービスに抽象化する必要があります。

+0

私はStripingWarriorに同意します:データと動作を分離する必要があります。 – Steven

+0

答えをいただきありがとうございます、私の直接の問題のために働くかもしれないようです。基本的には、私はBarとPickleからすべてのサービスを受け取り、代わりにFooがそのようなサービス(工場のような)と話すように提案していますか?ファイン。しかし、後でFooをシリアライズする必要がある場合はどうしますか?私もFooをPOCOにして、Fooを作った人にFoos、Bars、Picklesのすべてのサービスを移しますか?それは最終的にはあまりにも多くの責任を持っている醜いクラスに結びつくだろうか? – tandersen

+1

@tandersen:あなたは原理を理解しているようです。彼のコメントにリンクされているMark Seemanの記事で提案されているのと同じ戦略です。 (マークは文字通り、.NETのDIに関する本を書きました)。私はあなたがこのパターンに従えば責任を分けてクラスサイズを小さく保つのはかなり簡単だと思います。そうでない場合は、新しい質問を投稿して、SOコミュニティがあなたの特定のケースに対していくつかの有用なパターンを指摘できるかどうかを確認してください。 – StriplingWarrior

関連する問題