Delphi: Transporting Objects to remote computers
Hallo.
I am writing a tier2 ordering software for network usage. So we have client and server.
On the client I create Objects of TBest in which the Product ID, the amount and the user who orders it are saved. (So this is a item of an Order).
An order can have multiple items and those are saved in an array to later send the created order to the server. The class that holds the array is called TBestellung.
So i created both
TBest.toString: string;
and
TBest.fromString(source: string): TBest;
Now, I send the toString result to the server via socket and on the server I create the object using fromString (its parsing the attributes received). This works as intended.
Question: Is there a better and more elegant way to do that? Serialisation is a keyword, yes, but isn't that awful / difficult when yo开发者_高级运维u serialize an object (TBestellung in this case) that contains an Array of other Objects (TBest in this case)?
//Small amendment: Before it gets asked. Yes I should create an extra (static) class for toString and fromString because otherwise the server needs to create an "empty" TBest in order to be able to use fromString.
There are free serialization libraries for Delphi (also for Free Pascal):
- JSON: SuperObject and lkJSON
- XML: OmniXML and NativeXML
JSON and XML are cross-platform / cross-language which might be helpful for future interfaces to other systems like PHP-based web shop for example. They are also free and open standards (no vendor lock-in)
Update: I would not use the constructor-based approach, while maybe looking trivial in the beginning, (de)serialization can become a complex process which would add more and more non-class-specific code to the classes which need serialization. Instead, I would use 'builder' / 'parser' classes (Factory pattern) to keep responsibilities clear and dependencies low.
No, serializing an array of sub-objects inline inside of a main object isn't particularly messy or difficult if the deserialization code knows how to read that. XML does stuff like that all the time. So does DFM format, and it works great.
There's no magic involved. All the data needed to recreate the entire state of the object needs to be passed from the sender to the receiver one way or another. As long as the serializer and the deserializer speak the same protocol, and the receiver is able to recreate the same object that the sender sent, then your code is working fine and doesn't need to be tweaked unless it's causing significant performance problems.
Also, WRT your small amendment, if the purpose of TBest.fromString is to create a new TBest object, then it ought to be declared as a constructor, not a static anything. That's one of the cool things about Delphi: we can give our constructors actual, descriptive names. "Create" is just a convention.
Did you check n-tier remoting frameworks already available for Delphi? I can remember of:
- Datasnap (comes with Delphi Ent and Arch)
- DataAbstract by RemObjects
- kbmMW by Components4Developers
These frameworks are 5+ years on market, so you get all ugly details already solved and tested.
Edit: on comment about pricing:
- Datasnap is included in Enterprise and Architect versions of Delphi. If you have one of those then it's "free", if you have Delphi professional, then it will cost you.
- kbmMW has one free edition (check their site)
We use HitXML (open source), which does all (de)serialization automatically (using RTTI): http://code.google.com/p/hitxml/
Works OK as long as you use published methods (RTTI), and you can also use properties of "array of TRTTIEnabled".
I use SuperObject with Delphi 2010: http://code.google.com/p/superobject/wiki/first_steps and search "RTTI & marshalling in Delphi 2010".
You should take a look on the "Delphi On Rails" project: http://code.google.com/p/delphionrails/ This server is what you need.
We serialise objects using a TStreamable base class. These classes are for nothing else but transporting information between layers/tiers in a DCOM client/server application.
The base class knows how to serialise a regular Delphi stream from and to a variant array of bytes. The interface methods in the DCOM interface take variant params where we want to pass complex objects between client and server.
We also keep our client and server versions in sync, so we don't have any versioning issues between different versions of client and server.
So each sub-class simply reads and writes to/from a Delphi stream, and the base class serialises that to a variant.
For collections of other objects, for us, it's as simple as the parent object writing the count of contained objects into the stream, and then asking each contained object to append itself to the same stream. And simply reverse the process at the other end. It goes without saying that the contained classes also inherit from our base TStreamable class.
精彩评论