2012-02-14 9 views
14

के साथ कार्य करना इस प्रकार मैं एक Picture के लिए एक मौजूदा आंतरिक डेटा मॉडल है:प्रोटोकॉल बफ़र और आंतरिक डेटा मॉडल

package test.model; 
public class Picture { 

    private int height, width; 
    private Format format; 

    public enum Format { 
    JPEG, BMP, GIF 
    } 

    // Constructor, getters and setters, hashCode, equals, toString etc. 
} 

मैं अब protocol buffers का उपयोग कर इसे क्रमानुसार करने चाहते हैं। मैं एक Picture.proto फ़ाइल कि Picture वर्ग के क्षेत्र दर्पण लिखा और PictureProtoBuf की एक classname साथ test.model.protobuf पैकेज के अंतर्गत कोड संकलित किया है:

package test.model.protobuf; 

option java_package = "test.model.protobuf"; 
option java_outer_classname = "PictureProtoBuf"; 

message Picture { 
    enum Format { 
    JPEG = 1; 
    BMP = 2; 
    GIF = 3; 
    } 
    required uint32 width = 1; 
    required uint32 height = 2; 
    required Format format = 3; 
} 

अब मैं अब कि यह सोचते हैं रहा हूँ अगर मैं एक Picture है जब मैं अपने डाटा मॉडल में एक गणना है

Picture p = new Picture(100, 200, Picture.JPEG); 
PictureProtoBuf.Picture.Builder output = PictureProtoBuf.Picture.newBuilder(); 
output.setHeight(p.getHeight()); 
output.setWidth(p.getWidth()); 

मैं unstuck आ रहा हूँ: मैं क्रमानुसार और कहीं मैं बहुत की तरह एक PictureProtoBuf वस्तु बना सकते हैं और भर में सभी क्षेत्रों को मैप करने, राशि भेजना चाहते हैं। बदसूरत तरह से है कि मैं अभी उपयोग कर रहा हूँ है:

output.setFormat(PictureProtoBuf.Picture.Format.valueOf(p.getFormat().name()); 

हालांकि, इस टूटना का खतरा है और गणन नाम अपने आंतरिक डेटा मॉडल और प्रोटोकॉल बफ़र डेटा मॉडल के बीच लगातार किया जा रहा है पर निर्भर करता है (जो नहीं है .proto फ़ाइलों के भीतर गणना नाम के रूप में एक महान धारणा अद्वितीय होना चाहिए)। अगर मुझे आंतरिक मॉडल से .name() कॉल प्रोटोबफ-जनरेटेड गणना नाम से मेल नहीं खाता है तो मैं गणनाओं पर हाथ-शिल्प स्विच स्टेटमेंट्स देख सकता हूं।

मुझे लगता है कि मेरा सवाल यह है कि क्या मैं इस बारे में सही तरीके से जा रहा हूं? क्या मुझे प्रोटोबफ-जेनरेटेड (test.model.protobuf.PictureProtoBuf) के पक्ष में अपना आंतरिक डेटा मॉडल (test.model.Picture) स्क्रैप करना है? यदि हां, तो मैं अपने आंतरिक डेटा मॉडल (उदाहरण के लिए hashCode(), equals(Object), toString() इत्यादि) में किए गए कुछ नब्बे के दशक को कैसे कार्यान्वित कर सकता हूं)?

+0

मैंने कोशिश नहीं की है (पूरी तरह से जब से मैं मुख्य रूप से एक .NET व्यक्ति हूं), लेकिन मैं * विश्वास * [protostuff] (http://code.google.com/p/protostuff/) आपको अपने मौजूदा मॉडल के साथ काम करने की अनुमति देता है .. –

+0

धन्यवाद, मैं इसे देख लूंगा! – Catchwa

+0

@MarcGravell - आपके सुझाव के लिए धन्यवाद। आपका झुकाव सही था; protostuff ठीक है जो मैं बाद में था लेकिन बैक एंड पर प्रोटोकॉल बफर को बरकरार रखता है (हालांकि अभी तक Google प्रोटोबफ लाइब्रेरी के साथ इसकी संगतता का परीक्षण नहीं किया है)। – Catchwa

उत्तर

3

हालांकि मौजूदा उत्तर अच्छे हैं, लेकिन मैंने प्रोटोटाफ को देखने के लिए Marc Gravell के सुझाव के साथ थोड़ी और आगे जाने का फैसला किया।

आप अपने आंतरिक डेटा मॉडल के लिए कार्यावधि में स्कीमा बनाने के लिए गतिशील ObjectSchema के साथ protostuff runtime module उपयोग कर सकते हैं

मेरे कोड अब तक कम हो जाता:

// Do this once 
private static Schema<Picture> schema = RuntimeSchema.getSchema(Picture.class); 
private static final LinkedBuffer buffer = LinkedBuffer.allocate(DEFAULT_BUFFER_SIZE); 

// For each Picture you want to serialize... 
Picture p = new Picture(100, 200, Picture.JPEG); 
byte[] result = ProtobufIOUtil.toByteArray(p, schema, buffer); 
buffer.clear(); 
return result; 

यह गूगल पर एक महान सुधार है प्रोटोबफ लाइब्रेरी (मेरा प्रश्न देखें) जब आपके पास अपने आंतरिक डेटा मॉडल में बहुत सारे और बहुत सारे गुण हैं। कोई स्पीड पेनल्टी भी नहीं है जिसे मैं पहचान सकता हूं (मेरे उपयोग के मामलों के साथ, वैसे भी!)

4

यदि आपके पास अपने आंतरिक डेटा मॉडल पर नियंत्रण है, तो आप test.model.Picture को संशोधित कर सकते हैं ताकि enum मान उनके संबंधित प्रोटोबफ समकक्ष को जानते हों, शायद आपके enum रचनाकारों के पत्राचार में गुज़र रहे हैं।

उदाहरण के लिए, Guava'sBiMap (अनन्य मानों के साथ द्विदिश मानचित्र) का उपयोग करने पर हम पाते तरह

enum ProtoEnum { // we don't control this 
    ENUM1, ENUM2, ENUM3; 
} 

enum MyEnum { 
    ONE(ProtoEnum.ENUM1), TWO(ProtoEnum.ENUM2), THREE(ProtoEnum.ENUM3); 

    static final ImmutableBiMap<MyEnum, ProtoEnum> CORRESPONDENCE; 

    static { 
    ImmutableBiMap.Builder<ProtoEnum, MyEnum> builder = ImmutableBiMap.builder(); 
    for (MyEnum x : MyEnum.values()) { 
     builder.put(x.corresponding, x); 
    } 
    CORRESPONDENCE = builder.build(); 
    } 

    private final ProtoEnum corresponding; 

    private MyEnum(ProtoEnum corresponding) { 
    this.corresponding = corresponding; 
    } 
} 

और फिर MyEnum.CORRESPONDENCE.get(protoEnum) अगर हम को देखने के लिए MyEnum एक ProtoEnum करने के लिए इसी चाहते हैं, हम सिर्फ करते हैं, और कुछ दूसरी तरफ जाने के लिए, हम बस MyEnum.CORRESPONDENCE.inverse().get(myEnum) या myEnum.getCorresponding() करते हैं।

+0

आपके उत्तर के लिए धन्यवाद। मुझे लगता है कि मैं अवधारणा को समझता हूं लेकिन मुझे यकीन नहीं है कि मैं इसे कैसे कार्यान्वित करूंगा। क्या आप कुछ कोड लिखना चाहते हैं? – Catchwa

+2

आपके लिए एक स्टब है; क्या यह पर्याप्त स्पष्ट है? –

+0

हाँ, समझ में आता है - धन्यवाद। – Catchwa

1

एक तरह से केवल उत्पन्न enum रखने के लिए है:

package test.model; 
public class Picture { 

    private int height, width; 
    private PictureProtoBuf.Picture.Format format; 

// Constructor, getters and setters, hashCode, equals, toString etc. 
} 

मैं इस कई बार उपयोग किया है, यह या अपने मामले में कोई मतलब नहीं हो सकता है। प्रोटोबफ जेनरेटेड क्लासेस का उपयोग डेटा मॉडल (या कार्यक्षमता जोड़ने के लिए उन्हें विस्तारित करने) के रूप में करते हुए, कभी भी अनुशंसित नहीं किया जाता है।

संबंधित मुद्दे