2

I'm working with an external system which sends event-like data to us. An existing SDK from the third-party guys parses the JSON so in the end we get something like the following class:

public class Event
{
    public string Type;
    public dynamic Data;
}

The requirements are as follows:

  1. All events should have a default handler.

  2. Specific event types might have a handler which overrides the default one and does something else (code and logic duplication in handlers are not a concern as of now).

  3. Type of events may vary so we should be able to easily move the event from their specific handler to a default one or vice versa.

The solution which I thought of was to provide a dictionary with mapping of string to Type, where Type would be a handler type. Then, an appropriate handler would be created via reflection and an event would be passed to it to handle. If the key is not present in the dictionary, a default handler would be created. However, I'm not sure if it's the best way and I don't like to have three entries in the dictionary that point to one type, e.g.

'eventA' => handlerA

'eventB' => handlerA

'eventC' => handlerA

I haven't got a specific reason to dislike that, I just kinda feel that there might be a better way.

I also thought of using generics for that, but it's more of a vague idea and not a concrete concept right now.

Any suggestions on that? I'm pretty sure the issue is not unique but alas, I wasn't able to find a good wording to search.

  • Are you aware that you are reproducing the environment of an object oriented system? As such, it would be useful to examine how such environments dispatch methods, especially ones where types are defined dynamically. What you describe is not far off. – Frank Hileman Apr 13 '17 at 22:38
3

There's probably others, but the three obvious solutions I can think of are:

  1. Use a Dictionary<string, HanderDelegate> map,
  2. Use a switch statement to map the "event" names to their handlers,
  3. Use OO polymorphism (one class per event type) and some sort of factory.

Each has their pros and cons. I personally would go with the dictionary solution, as you suggest. There is no "correct" answer here though.

  • For future maintenance reasons I will prefer option 3 – Umut Kahramankaptan Apr 13 '17 at 11:25
  • 2
    @UmutKahramankaptan, To be honest, I lied in my answer: option 3 has lots of cons and is by far the worst option. But I was trying to keep my answer balanced ;) – David Arno Apr 13 '17 at 11:26
  • 1
    Thanks for the answer. As to your third option, I thought of that in scope of 'generics approach'. However, in this particular case with the third party system, it would require a mapping of their Event with string EventType to our class hierarchy. Of course, that's only specific to my case. – Vlad Stryapko Apr 13 '17 at 11:27
  • For ethical reasons, I do not appreciate lying to others. It will not change my preference within those three options though. Thanks for your honesty. – Umut Kahramankaptan Apr 13 '17 at 11:28
  • By the way, could you please elaborate on why the third approach has more disadvantages? We might be talking about different things, but I think representing events with OOP isn't that bad on the abstract level. – Vlad Stryapko Apr 13 '17 at 11:36
2

Your proposed design is good. I see no reason to object to it. There are possible alternative designs, but I can't think of anything decisively better.

If you have three types of events that are all handled by one handler, that information has to be encoded somewhere in any design. It might feel like "repetition", but it is not; it's three distinct pieces of information. So, don't worry about that.

  • Thanks for the part about repetition, I guess it was just me being a perfectionist. – Vlad Stryapko Apr 13 '17 at 11:37
  • 2
    Dan makes a good point about the repetition. @VladStryapko my advice to you is to resist those urges to be a "perfectionist" because 99%, unless you really know what you're doing, those urges result in bad code that is difficult to maintain. It's a rite of passage in the software world: Your instincts are often wrong. – MetaFight Apr 13 '17 at 12:37
  • That totally makes sense, but the main issue here is to distinguish between useless perfectionist urges and reasonable 'Hey, that might go wrong in the future unless we change it right now'. I've seen examples of both over-engineered and 'under-engineered' code and it's always a question of balance (and, of course, time because we don't live in an ideal world where you can code without deadlines). Thanks for your opinion. – Vlad Stryapko Apr 13 '17 at 13:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.