Need advice on how to design this. Composition or inheritance?
I'm trying to design a client / server solution. Currently it contains three projects. The client, the server, and a library that each use (because they both require a lot of the same stuff).
For example, both the client and the server (in this case) read incoming data in the exact same way. Because of this, both the client and the server have their own MessageReader
object. The MessageReader
will first read the first 4 bytes of incoming stream data to determine the length of the data and then read the rest. This is all performed asynchronously. When all the data is read the class raises its own MessageRead
event or if there was an IOException
while reading it raises its own ConnectionLost
event.
So this all works fine. What's the problem? Well, the client and the server are a bit different. For example, while they may read data in the same way, they do not write data in the same way. The server has a Dictionary
of clients and has a Broadcast
method to write to all clients. The client only has a single TcpClient
and can only Write
to the server. Currently all this behavior is within each respective WinForm and I want to move it to a Client
and Server
class but I'm having some problems.
For example, remember earlier when I was talking about the MessageReader
and how it can raise both a MessageRead
event and a ConnectionLost
event? Well, now there's a bit of a problem because in designing the Client
class I have to capture these two events and re-raise them because the client form should not have access to the MessageReader
class. It's a bit ugly and looks like this:
class Client
{
private MessageReader messageReader = new MessageReader();
public delegate void MessageReceivedHandler(string message);
public delegate v开发者_开发技巧oid ConnectionLostHandler(string message);
public event ConnectionLostHandler ConnectionLost;
public event MessageReceivedHandler MessageReceived;
public Client()
{
messageReader.ConnectionLost += messageReader_ConnectionLost;
messageReader.MessageReceived += messageReader_MessageReceived;
}
private void messageReader_MessageReceived(string message)
{
if (ConnectionLost != null)
{
ConnectionLost(message);
}
}
private void messageReader_ConnectionLost(string message)
{
if (MessageReceived != null)
{
MessageReceived(message);
}
}
}
This code is ugly because its basically duplicate code. When the MessageReader
raises the MessageReceieved
handler the Client
has to capture it and basically re-raise its own version (duplicate code) because the client form should not have access to the message reader.
Not really of a good way to solve it. I suppose both Client
and Server
could derive from an abstract DataReader
but I don't think a client is a data reader, nor is the server. I feel like composition makes more logical sense but I can't figure out a way to do this without a lot of code duplication and confusing event handlers.
Ouch, this question is getting a bit long.. I hope I don't scare anyone away with the length. It's probably a simple question but I'm not really sure what to do.
Thanks for reading.
Composition.
I didn't even read your code or text. I find that the average developer (almost) never needs inheritance but they like to use it quite a bit.
Inheritance is fragile. Inheritance is hard to get correct. It's harder to keep it in check with SOLID.
Composition is easy to understand, easy to change, and easy to DI, Mock, and test.
SOLID
I ended up using inheritance for this even though the relationship wasn't strong. The code duplication it got rid of was worth it. Was able to place all the events both classes shared in to the base class.
精彩评论