3

Sometimes when I write a class or piece of code that has to deal with parsing or processing of data, I have to ask myself, if there might be a better solution to the problem.

Example 1: In a recent exam we had to write a simluation for a carsharing service. We were given a city which was divided into several (n*n) districts. Each district worked independently and had two functions. The first one represented the amount of cars that were borrowed and the second one the amount of cars that were returned (in this specific district, per hour). Now we had to calculate some values for each district.

Obviously I had a City-class and a District-class. The question is: Where do i so the simulation part? I could write a function inside the district class or I could write a dedicated (simulator-)class which handles all the processing.

So basically:

City.Simulate()
   foreach District in City
        District.Simulate
return results

or

Simulator(City)
   Simulate
      Get all district objects
         do simulation & collect results
   return results

In the end I decided to go with the first option, but I'm not really satisfied with this approach.

Example 2: Maybe the problem gets clearer with this example. I'm currently writing an MQTT Broker and am currently working on the packet parser. There is one class for each packet type (Connect, Publish, Subscribe, etc.). Where do I do the parsing?

For this project I made a dedicated class for parsing which has a function for each type. However in a previous (similar) project, each packet class provided a custom parsing function.


So a more general question would be: At which point do I outsource the processing of data/to which point do I process the data inside the class itself?

  • In your first example, what would District simulate exactly? It seems to me that it would merely act as a bean class, providing information only. – Neil Jun 12 '17 at 12:59
  • @Neil It would calculate at which time of the day more cars are needed than available. The function inside the district class would simply use the data stored in the object. – Camo Jun 12 '17 at 13:03
  • Ok, so really it's just a table of sorts? There is no calculation? Does the City class then do an hour-by-hour calculation over a period of time? – Neil Jun 12 '17 at 13:06
  • The entire "simulation" consists of calculating the function values for each hour (0-24) and checking whether there are more cars requested than available in this specific district. It's really simple. The data doesn't change, therefore the simulation only needs to be done once. – Camo Jun 12 '17 at 13:13
3

Having worked on this kind of problems many times, I always go with option #2, for two primary reasons:

1. I consider it more true to SRP

"Simulating" is basically its own thing. If you were to ask the question, "what does this class do", the city class in your option #1 has two answers: "keep track of city related data AND calculate statistics related to that data". That "and" implies that it violates the SRP. That's not to say that it is a terrible idea and should never be done that way, but from the basic principles of OOP I would say you are better off separating it into its own class. Now for a more practical reason:

2. Simulations, statistics, calculations, etc often change.

This is the biggest reason for me. Right now your simulation is calculating things like "What districts are oversubscribed when?". That is fairly straight-forward, and if it lived in your city class it would hardly be the end of the world. But what if you decide down the road that you need more statistics? In a real world project that sort of thing is guaranteed to happen. By the end of the year you are going to be performing a dozen different statistical calculations, and the simulations might vary from city to city. In that case you could imagine having a different simulation class for each different kind of statistic that is calculated, and even have classes specific to given cities. That sort of situation would be impossible to manage if everything lived inside your city class, but very easy to manage once you start splitting things into separate classes.

So the short answer is that for the current level of problem you are solving, either way works fine (practically speaking). However, in the long run, statistics and simulation calculations are their own kind of thing and should live in their own class hierarchy for maximum reusability and maintainability.

0

Obviously I had a City-class and a District-class. The question is: Where do i so the simulation part? I could write a function inside the district class or I could write a dedicated (simulator-)class which handles all the processing.

As I see it, a District is only responsible for calculating information relative to the information it has within its own class. This can at times extend to performing calculations with other instances of its own class, for instance, comparing or testing equality, but for the most part, it should be uninterested in anything outside its world (or district in this case).

Therefore it would be the job of City to perform the calculation. City could arguably be thought of as just a container of District instances, and if City were getting bogged down by a lot of logic, I'd seriously consider separating City, the container and City, the simulator. In fact, CitySimulator might be an appropriate name for such a class. But as you mentioned, this is a simple example, so just City should suffice.

Example 2: Maybe the problem gets clearer with this example. I'm currently writing an MQTT Broker and am currently working on the packet parser. There is one class for each packet type (Connect, Publish, Subscribe, etc.). Where do I do the parsing?

If the parsing is simple enough, you'd simply write a Parser class that determines message type, and passes the rest of the message to separate methods, one for each type to parse the rest. Though, in an exam, that's not the answer they're likely looking for.

You could create a Parser class that does nothing except call a list of classes which handle each message type, with two methods: canHandle and handle. canHandle gets called first, and the class which handles that particular type should return true only if it is a message of that type, after which handle gets called which, if done proper, means each class handles its own message type without knowing anything about the others, effectively reducing coupling between them and the Parser class.

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.