2012-03-15 4 views
8

Ninject를 통해 종속성 삽입을 사용하는 프로젝트에서 작업하고 있습니다. 지금까지 잘 작동하고 DI를 많이 좋아하지만 일부 객체를 직렬화해야한다고 결정 했으므로 DI 패턴을 따르기가 어렵습니다. 공장에서 생성 한 객체를 직렬화하는 방법

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

    ... 

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

여기 _barFactory.MakeBar()가 호출 될 때 만들어 도착 바,이다 :

내가 바의 목록을 가지고 있으며,이 같은 공장을 통해 만드는 푸라는 클래스를 가지고 말. Bar를 직렬화하기를 원합니다 :

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의 deserialization 생성자가 호출되면 다른 PickleFactory를 가져올 방법이 없습니다. 원래 PickleFactory는 BarFactory에 의해 Bar에 주어졌지만, Deserialization 생성자는 BarFactory에 의해 호출되지 않았습니다.

현재이 문제를 해결하기 위해 Bar의 모든 직렬화 가능 멤버를 BarDataObject라는 자체 클래스로 추출해야합니다. 그런 다음 BarDataObject를 직렬화 할 수는 있지만 Bar 자체는 만들지 않습니다. BarDataObject를 매개 변수로 받아들이고 BarDataObject의 모든 정보로 채워 넣은 Bar를 작성하는 BarFactory에 함수를 추가합니다.

그러나, 피클 을 가정도는 하나 직렬화 할 수없는 그것을 만든 공장에서 가지고 서비스 클래스가 있습니다. 그래서 Pickle에서도 DataObject를 추출해야하고, BarDataObject는 PickleDataObject를 유지해야합니다. 그리고 Pickle에는 데이터와 서비스가 혼합 된 멤버 변수가 있다고 가정합니다. 나는 그것을 위해 DataObject를 만들고 유지해야 할 것이다. 이것은 정말 불만처럼 보입니다. 특히 프로젝트에 직렬화해야 할 다른 많은 것들이 있다고 생각하면, 그들은 아마도 똑같은 문제에 직면 할 것입니다.

더 나은 솔루션이 있습니까? 내가 뭔가 잘못하고 있는거야, DI 현명한거야? 방금 DI와 Ninject로 작업을 시작했지만 서비스 클래스를 주입 한 객체를 직렬화하는 좋은 방법을 찾은 사람을 찾을 수없는 것 같습니다.

+0

직렬화 정보를 받아들이는'BarFactory' 클래스에 생성자를 추가 할 수 있습니까? – Matthew

+3

Foo는 어떤 유형의 객체입니까? 그것은 'newable'또는 'injectable'인가? (http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/). –

+0

@Matthew - 내가 원한다면 SerializationInfo를 어떻게 공장에 가져갈 수 있습니까? Bar의 private 생성자가 호출되었을 때, Bar 생성자에 이미 있기 때문에 Bar 생성을 요청하기에는 너무 늦습니다. Bar는 BarFactory에 대해 알지 못합니다. – tandersen

답변

9

내 경험상 서비스 클래스 만 종속성이 있어야하며 서비스 클래스는 직렬화의 대상이되어서는 안됩니다.

직렬화하려는 클래스가 있지만 주입 된 서비스를 사용한다는 사실은 코드 냄새처럼 보입니다.

그것은 당신이 Bar으로 달성하기 위해 노력하고 정확히 얘기하기가 어렵습니다,하지만 난 무엇을 볼 수 있습니다에서, 나는 Pickle는 POCO 수있게하고 사용자 정의 Bar 클래스 대신 List<Pickle>을 사용하는 것이 좋습니다 것입니다.

또는 Bar은 절임 속성으로 POCO Bar을, 피클 외에 다른 직렬화 정보를 가지고 있는지 확인하기위한 것입니다 경우 : 포항 강판 종속성이없는 것이기 때문에

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

, 그들은 공장을 필요가 없습니다, 그래서이 클래스는 전적으로 직렬화 가능해야합니다. BarPickle에서 수행하려는 복잡한 함수가있는 경우 메서드 매개 변수로 BarPickle을 사용하는 별도의 유틸리티 서비스로 추상화해야합니다.

+0

StripingWarrior에 동의합니다. 데이터와 동작을 분리해야합니다. – Steven

+0

답장을 보내 주셔서 감사합니다. 즉각적인 문제가있는 것 같습니다. 기본적으로, 당신은 Bar and Pickle에서 모든 서비스를 가져와 Foo가 그 서비스 (공장과 같은)에 대신 이야기하도록 제안하고 있습니까? 벌금. 하지만 나중에 나도 Foo를 직렬화해야한다면? 나는 Foo를 POCO로 만들고, Foo, Bars, Pickles에 대한 모든 서비스를 Foo를 만든 사람으로 옮긴다. 그것은 결국 너무 많은 책임이있는 커다란 추악한 수업을 가져 오지 않을까요? – tandersen

+1

@ tandersen : 원칙을 이해 한 것 같습니다. Mark Seeman의 기사에서 제안 된 것과 동일한 전략이 그의 코멘트에 링크되어 있습니다. (Mark는 문자 그대로 DI의 책을 .NET에 썼습니다.) 이 패턴을 따르면 책임을 분리하고 수업 규모를 작게 유지하는 것이 매우 쉽습니다. 그렇지 않은 경우 자유롭게 새로운 질문을 게시하고 SO 커뮤니티가 특정 사례에 대한 유용한 패턴을 지적 할 수 있는지 확인하십시오. – StriplingWarrior

관련 문제