For learning purposes I am writing a socket based client/server application. I have designed a custom protocol to ensure I can process my packets correctly. While inspecting some older parts of code today I realized that my way of creating my data packets contains much redundant code.
I have different types of packets, e.g. ImagePacket, MessagePacket etc. The creation of all types differs only in minor stuff, the header and delimiter creation for example is the same.
To improve this, i came up with a solution like this (simplified):
abstract class Packet
{
public Packet(object o)
{
MemoryStream memoryStream = new MemoryStream();
AddHeader(ref memoryStream);
AddData(ref memoryStream, obj);
AddDelimiter(ref memoryStream);
_packetBytes = memoryStream.ToArray();
memoryStream.Close();
}
protected abstract void AddData(ref MemoryStream ms, object obj);
The AddData method is implemented as abstract method and overridden in the concrete classes whereas AddHeader and AddDelimiter are defined in the abstract class Packet itself.
This works fine and I don’t have as much duplicated code as before but I am not happy with
passing an object to AddData because it is not made clear that i must not give a string to the ImagePacket constructor.
// correct
Packet myMsgPacket = new MessagePacket("hello world");
Packet myImagePacket = new ImagePacket(image);
// wrong, but will be compiled :(
Packet myChaosPacket = new ImagePacket("muaha you're doomed");
If I had to to implement a check for the correct data type being passed I would end up with tons of stupid code again.
How can I achieve the reduction of duplicated code but also get rid of the problem mentioned above?
This sounds like you need to use the factory pattern
MyFactory.CreatePacketwould then return anIPacketUpdate: As per the comment below, I should’ve been clearer. Your factory can have a number of overloaded CreatePacket() methods which take different data types…
and if you have multiple types of packet which contain just String (Eg Message packet, Status packet or similar) You could create an Enum indicating which string packet is desired…
Inside you packet factory, you can have common functions which deal with all the duplicated code – eg
AddDelimiter()– This will keep your code DRY