Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a switch statement be avoided if the return type is unknown by the calling method?

I have been reading a book called Clean Code A Handbook of Agile Software Craftsmanship. The author in the book motivates that a switch statement should be avoided and if it cannot be avoided it should be relegated to factory methods. I have a connection object which is receiving various PDUs (protocol data units). The PDUs vary and they can be received in any order. So if I have a method for example:

public BasePdu ReceiveNext();

because I cannot tell what the packet type is until it has been fully received. In the header of the PDU is an identifier as to which type it should be. This means that the calling method is going to have figure out what the type of the PDU is and based on that call the relevant method to handle it. This sounds like a perfect example for a switch statement. The object that contains the connection I would ideally like to have two threads. One for receiving PDUs and another for servicing a queue of PDUs to be sent.

Now I know that you cannot follow every bit of good advice and that there are just some circumstances which are the exception to the rule. Is this one of them? Or is there a way around this that I just have not yet thought of.

UPDATE:

I hear what a lot of people are saying by creating subclasses of response handlers. The issue is that the containing object has a lot of context and additional information that the handlers would need for example lookups and throttling etc etc. To inject all of this information into subclasses of handlers would be quite a chore to maintain and would also split a lot of logic up when it feels better to be encapsulated in the object that it is in now.

like image 578
uriDium Avatar asked May 23 '11 07:05

uriDium


People also ask

What is a good way to avoid switch statements?

Here are some alternatives to switch statement : lookup table. polymorphism. pattern matching (especially used in functional programming, C++ templates)

Should switch statements be avoided?

IMO switch statements are not bad, but should be avoided if possible. One solution would be to use a Map where the keys are the commands, and the values Command objects with an execute() method. Or a List if your commands are numeric and have no gaps.

Can Switch case have return statement?

The JavaScript switch statement can contain return statements if it is present inside a function.


2 Answers

Personally I wouldn't worry about it too much; if it looks like a good place for a switch statement use one. On the other hand this also looks like a situation where you could use a factory method if each PDU type is handled by a class rather than a method. And, accoding to your book, you're allowed you to use switch statements then

like image 163
Patrick Avatar answered Sep 27 '22 18:09

Patrick


Simply create a PDUParserFactory which create the parser based on a PDU type using switch statements on the PDU type identifier. This is the case where the book says it's ok :)

Update: One possible approach

 class BasePDU
 {
     string Name { get; set; }
     ...
 }

 class PDUType1 : BasePDU
 {
     ...
 }
 ...

 class PDUReceiver
 {
     public event EventHandler<PDUReceivedEventArgs> PDUReceived;

     private void ParsePDU(byte[] data)
     {
          BasePDU pdu;
          switch (byte[0]) // PDU type selector
          {
              ....    parse PDU based on type
          }

          OnPDUReceived(pdu);
     }

      private void OnPDUReceived(BasePDU pdu)
      {
           var handler = PDUReceived;
           if (handler != null)
           {
                handler(this, new PDUReceivedEventArgs(pdu));
           }
      }
 }

Then you can attach listeners to the event:

 pduReceiver.PDUReceived += BaseHandler;
 pduReceiver.PDUReceived += PDUType1Handler;
 ...

 void PDUType1Handler(object sender, PDUReceivedEventArgs e)
 {
      // only care about PDUType1
      if (e.PDU.GetType() != typeof(PDUType1))
            return;
      ....
 }

Alternatively you could also create a event handler dictionary in the receiver, mapping a pdu type to event handlers and then let handlers register for specific types only. This way not all handlers would be called for each received PDU.

Instead of heaving a PDU type hierarchy you could also just have a:

 class PDU
 {
      public PDUType PDUType { get; }
      public byte[] PDUData { get }
 }

then register handlers in the receiver for each PDUType and let the handler do whatever it wants with the data.

It's hard to give more concrete advice without knowing what exactly you want to do with your received packets.

like image 41
ChrisWue Avatar answered Sep 27 '22 19:09

ChrisWue