2012-03-15 22 views
8

Tôi đang làm việc trên một dự án sử dụng tiêm phụ thuộc thông qua Ninject. Cho đến nay, nó đang làm việc rất tốt, và tôi thích DI rất nhiều, nhưng bây giờ tôi đã quyết định tôi cần serialize một số đối tượng, và tôi đang tìm thấy nó khó khăn để làm điều đó sau DI mẫu.Cách sắp xếp các đối tượng được tạo bởi các nhà máy

Nói rằng tôi có một lớp được gọi là Foo, trong đó có một danh sách các Bars, và làm cho họ thông qua một nhà máy, như thế này:

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

    ... 

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

Dưới đây là Bar, mà được thực hiện khi _barFactory.MakeBar() được gọi. Tôi muốn Bar có thể được tuần tự hóa:

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

Lưu ý rằng Bar có nhà máy riêng và bộ sưu tập dưa chua. Đây là vấn đề: khi các nhà xây dựng deserialization của Bar được gọi, tôi không có bất kỳ cách nào để có được nó PickleFactory khác. Bản gốc PickleFactory đã được BarFactory trao cho Bar, nhưng nhà xây dựng deserialization không được BarFactory gọi.

Kế hoạch hiện tại của tôi để giải quyết vấn đề này là trích xuất tất cả các thành viên có thể tuần tự hóa của Bar thành lớp riêng của nó được gọi là BarDataObject. Sau đó, tôi sẽ làm cho BarDataObject serializable, nhưng không phải Bar chính nó. Tôi sẽ thêm một chức năng để BarFactory mà chấp nhận một BarDataObject như một tham số và xây dựng một Bar cho bạn điền vào với tất cả các thông tin từ BarDataObject.

Tuy nhiên, giả sử Pickle cũng có các lớp dịch vụ mà nó nhận được từ nhà máy sản xuất nó, không thể được sắp xếp theo thứ tự. Vì vậy, tôi sẽ phải trích xuất một DataObject từ Pickle là tốt, và BarDataObject của tôi sẽ phải giữ một PickleDataObject. Và giả sử Pickle có một biến thành viên với một hỗn hợp dữ liệu và dịch vụ? Tôi sẽ phải thực hiện và duy trì một DataObject cho điều đó là tốt. Điều này có vẻ như một con số thực sự, đặc biệt là xem xét dự án của tôi có nhiều thứ khác mà tôi cần phải sắp xếp theo thứ tự, và có thể họ sẽ phải đối mặt với cùng một vấn đề.

Vì vậy, có giải pháp tốt hơn không? Tôi có làm gì sai không, DI-wise? Tôi vừa mới bắt đầu làm việc với DI và Ninject, nhưng tôi dường như không thể tìm thấy bất kỳ ai đang tìm ra cách tốt để sắp xếp các đối tượng đã được tiêm các lớp dịch vụ.

+0

Bạn có thể thêm một hàm tạo vào lớp 'BarFactory' của bạn chấp nhận thông tin tuần tự hóa không? – Matthew

+3

Loại đối tượng nào là Foo? Nó có phải là 'mới' hay 'tiêm' được không? (http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/). –

+0

@Matthew - Nếu tôi đã làm, làm thế nào tôi sẽ nhận được SerializationInfo đến nhà máy? Khi nhà xây dựng tư nhân của Bar được gọi, đã quá muộn để yêu cầu nhà máy sản xuất Bar, vì chúng tôi đã ở trong nhà xây dựng Bar, và Bar không biết gì về BarFactory trong mọi trường hợp. – tandersen

Trả lời

9

Theo kinh nghiệm của tôi, chỉ các lớp dịch vụ mới có phụ thuộc và các lớp dịch vụ không bao giờ phải chịu sự tuần tự hóa.

Thực tế là bạn có một lớp học mà bạn muốn tuần tự hóa, nhưng dựa vào một dịch vụ được tiêm, có vẻ như là một mùi mã với tôi.

Thật khó để nói chính xác những gì bạn đang cố gắng để hoàn thành với Bar, nhưng từ những gì tôi thấy, tôi muốn đề nghị làm Pickle là một POCO, và sử dụng một List<Pickle> thay vì một Bar lớp tùy chỉnh.

Hoặc, nếu Bar được thiết kế để có thông tin serializable khác ngoài Pickles, làm Bar một POCO với một tài sản Pickles:

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

Vì POCOs sẽ không phải phụ thuộc, họ không nên yêu cầu các nhà máy, Vì vậy, lớp này nên được hoàn toàn serializable. Nếu có các chức năng phức tạp mà bạn muốn thực hiện trên Bar s và Pickle s, chúng sẽ được trừu tượng hóa thành các dịch vụ tiện ích riêng biệt mất Bar s và Pickle s làm thông số phương pháp của chúng.

+0

Tôi đồng ý với StripingWarrior: Bạn nên tách biệt dữ liệu và hành vi. – Steven

+0

Cảm ơn câu trả lời, có vẻ như nó có thể làm việc cho vấn đề trước mắt của tôi. Về cơ bản, bạn đang đề nghị tôi đưa tất cả các dịch vụ ra khỏi Bar và Pickle, và có Foo nói chuyện với những dịch vụ đó (như các nhà máy) thay vào đó? Khỏe. Nhưng nếu sau này tôi cũng cần serialize Foo? Tôi có làm cho Foo trở thành một POCO hay không, và di chuyển tất cả các dịch vụ cho Foos, Bars, và Pickles thành người đã tạo ra Foo? Không phải điều đó cuối cùng sẽ dẫn đến một lớp học xấu xí lớn có quá nhiều trách nhiệm sao? – tandersen

+1

@tandersen: Có vẻ như bạn hiểu nguyên tắc. Đó là chiến lược tương tự được đề xuất trong bài viết Mark Seeman liên quan đến trong bình luận của mình. (Mark theo nghĩa đen đã viết cuốn sách trên DI in .NET, nhân tiện). Tôi nghĩ bạn sẽ tìm thấy nó khá dễ dàng để tách biệt trách nhiệm và giữ kích thước lớp học nhỏ nếu bạn làm theo mẫu này. Nếu không, vui lòng đăng câu hỏi mới và xem liệu cộng đồng SO có thể chỉ ra một số mẫu hữu ích cho trường hợp cụ thể của bạn hay không. – StriplingWarrior

Các vấn đề liên quan