2010-07-16 28 views
9

Làm thế nào để bạn 'de-serialize' một lớp dẫn xuất từ ​​dữ liệu tuần tự? Hoặc có lẽ tôi nên nói, có cách nào tốt hơn để 'de-serialize' dữ liệu vào các lớp học có nguồn gốc? Ví dụ, giả sử bạn có một lớp cơ sở ảo thuần túy (B) được thừa hưởng bởi ba lớp khác, X, Y và Z. Hơn nữa, chúng ta có một phương thức, serialize(), sẽ dịch X: B, Y: B và Z: B vào dữ liệu được tuần tự hóa.Làm thế nào để bạn 'de-serialize' một lớp dẫn xuất từ ​​dữ liệu tuần tự?

Bằng cách này, nó có thể được giới hạn trên một ổ cắm, một đường ống có tên, v.v ... cho một quá trình từ xa.

Vấn đề tôi gặp phải là, làm cách nào để tạo đối tượng thích hợp từ dữ liệu được tuần tự hóa?

Giải pháp duy nhất tôi có thể đưa ra là bao gồm số nhận dạng trong dữ liệu được tuần tự hóa cho biết loại đối tượng có nguồn gốc cuối cùng. Trong trường hợp người nhận, trước tiên phân tích trường kiểu có nguồn gốc từ dữ liệu tuần tự hóa, và sau đó sử dụng một câu lệnh chuyển đổi (hoặc một loại logic nào đó) để gọi hàm tạo thích hợp.

Ví dụ:

B deserialize(serial_data) 
{ 
    parse the derived type from the serial_data 

    switch (derived type) 
     case X 
      return X(serial_data) 
     case Y 
      return Y(serial_data) 
     case Z 
      return Z(serial_data) 
} 

Vì vậy, sau khi biết các loại đối tượng có nguồn gốc chúng tôi gọi thích hợp có nguồn gốc constructor loại.

Tuy nhiên, điều này cảm thấy khó xử và cồng kềnh. Tôi hy vọng có một cách làm hùng hồn hơn để làm điều này. Lanhung?

+5

serialization nhỏ gọn (bit-wise) có thể cắn vào ngay trong mông, đặc biệt là nếu bạn có kế hoạch để tiết kiệm những thứ vào các tập tin. Nhiều năm trôi qua và các lớp học thay đổi, bạn sẽ hơi say khi bạn cố gắng tải lại chúng. Vì lý do đó, việc tạo các tệp tự tạo tài liệu và phiên bản là một ý tưởng hay. Chỉ khi khách hàng và máy chủ ở tất cả các lần đồng ý về giao thức được sử dụng, là nó OK để gửi byte thẳng. Nếu không, sau đó tôi sẽ sử dụng 'XML/JSON'. Tuy nhiên, tôi cũng sẽ xem xét những thứ có thể làm cho điều này dễ dàng hơn, chẳng hạn như 'SOAP', v.v. –

+0

@Hamish +1, làm cho câu trả lời đó trở thành một câu trả lời! –

Trả lời

2

Thực tế, đó là vấn đề chung hơn là việc tuần tự hóa được gọi là Virtual Constructor.

Cách tiếp cận truyền thống là Factory, dựa trên ID trả về loại có nguồn gốc phù hợp. Có hai giải pháp:

  • phương pháp switch như bạn thấy, mặc dù bạn cần phải phân bổ trên heap
  • phương pháp prototype

Phương pháp nguyên mẫu đi như vậy:

// Cloneability 
class Base 
{ 
public: 
    virtual Base* clone() const = 0; 
}; 

class Derived: public Base 
{ 
public: 
    virtual Derived* clone() const { return new Derived(*this); } 
}; 

// Factory 
class Factory 
{ 
public: 
    Base* get(std::string const& id) const; 
    void set(std::string const& id, Base* exemplar); 

private: 
    typedef std::map < std::string, Base* > exemplars_type; 
    exemplars_type mExemplars; 
}; 

Đó là phần nào truyền thống để làm cho một singlet Factory, nhưng đó là một vấn đề hoàn toàn.

Đối với việc deserialization phù hợp, nó dễ dàng hơn nếu bạn có một phương pháp ảo deserialize để gọi trên đối tượng.

EDIT: Nhà máy hoạt động như thế nào?

Trong C++ bạn không thể tạo loại mà bạn không biết.Do đó, ý tưởng ở trên là nhiệm vụ xây dựng một đối tượng Derived được cấp cho lớp Derived, theo phương pháp clone.

Tiếp theo là Factory. Chúng tôi sẽ sử dụng một map sẽ liên kết một "thẻ" (ví dụ "Derived") với một thể hiện của một đối tượng (nói Derived tại đây).

Factory factory; 
Derived derived; 
factory.set("Derived", &derived); 

Bây giờ, khi chúng ta muốn tạo một đối tượng mà chúng ta không biết tại thời gian biên dịch (vì loại được quyết định trên bay), chúng tôi chuyển thẻ cho nhà máy và yêu cầu một đối tượng trở về.

std::unique_ptr<Base> base = factory.get("Derived"); 

Dưới nắp, các Factory sẽ tìm thấy Base* liên quan đến thẻ "Derived" và gọi phương thức clone của đối tượng. Điều này sẽ thực sự (ở đây) tạo một đối tượng của kiểu thời gian chạy Derived.

Chúng tôi có thể xác minh điều này bằng cách sử dụng toán tử typeid:

assert(typeid(base) == typeid(Derived)); 
+0

Tha thứ sự thiếu hiểu biết của tôi. Nhưng tôi không bắt được một Nhà máy giải quyết vấn đề như thế nào. Trong thực tế, tôi đã rơi khỏi xe tải ở lớp nhà máy ở trên. –

+0

Không vấn đề gì, chúng ta đều ở đây để tìm hiểu, tôi đã thêm giải thích về cách nhà máy giải quyết vấn đề xây dựng ảo. Đừng nhầm lẫn với cấu trúc 'map', nó chỉ là một công tắc lạ mắt có thể được lấp đầy khi chạy. –

+0

Cảm ơn bạn đã cung cấp thêm thông tin. Vì vậy, nếu tôi hiểu điều này một cách chính xác. Chúng tôi vẫn cần một số loại thẻ để cho chúng tôi biết loại đối tượng đó là gì. Nhà máy sử dụng thẻ này để tìm hàm "đã đăng ký" trả về bản sao mới. Sửa lỗi nếu tôi sai, nhưng điều này có vẻ giống như câu lệnh chuyển đổi "động". Thay vì có một công tắc mã hóa cứng như tôi đã nói ở trên, nhà máy cung cấp cho bạn cách "linh hoạt" để cung cấp chức năng tương tự? Hay tôi đang thiếu cái gì đó. BTW, THANKS! Tôi đã điều chỉnh giải pháp này cho một vấn đề khác mà tôi đang gặp phải! –

0
 
inmemory: 
-------- 
type1 { 
    chartype a; 
    inttype b; 
}; 
serialize(new type1()); 

serialized(ignore { and ,): 
--------------------------- 
type1id,len{chartypeid,adata,inttypeid,bdata} 

tôi đoán, trong một giao thức tuần tự lý tưởng, mọi kiểu không nguyên thủy cần phải có tiền tố là typeid, len. Thậm chí nếu bạn tuần tự hóa một kiểu đơn lẻ không có nguồn gốc từ bất cứ thứ gì, bạn sẽ thêm một id kiểu, vì đầu kia phải biết kiểu của nó nhận được (bất kể cấu trúc thừa kế). Vì vậy, bạn phải đề cập đến id lớp có nguồn gốc trong serialization, bởi vì một cách logic họ là các loại khác nhau. Đúng nếu tôi đã sai lầm.

+0

Đây là loại hướng tôi đang hướng, nhưng tôi không nghĩ chiều dài là cần thiết. Tất nhiên nó sẽ phụ thuộc vào cách typeid được xác định. Tôi đã hình dung nó như là xác định loại của lớp, mà sau đó sẽ suy ra chiều dài quá. Nhưng tôi nghi ngờ suy nghĩ của tôi cũng dựa trên thực tế là tôi đang sử dụng hàng đợi tin nhắn POSIX để truyền tải để lớp vận chuyển biết chiều dài. –

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