2

I am running in the exact problem Robert Martin mentioned when having a class named Manager, mine has too much (redudant) code.


I am writing a system doing computations on many buffers containing data form a timestamped source.

  • The Buffers store different data types, they are template classes.
  • When a new Observation arrives, a BufferManager distributes and processes fields of the Observation to the different Buffers.
  • A common user operation is to access a time interval of a given buffer.

I have a BufferID emum of names in the BufferManager, one for each Buffer and then I have dictionaries (std::map) in the BufferManager, one for each type of Buffer.

The user then gets a desired interval of a Buffer by calling:

Type1Interval int1 =  BufferManager.getType1BufferInterval(BufferID, starTime, endTime)
...
TypeNInterval intN = BufferManager.getTypeNBufferInterval(BufferID, starTime, endTime)

where the only difference between two such functions is that getTypeJBufferInterval accesses the dictionary containing buffers of type J.


How can I, given a BufferID and a time interval, return the corresponding Buffer(values) without having to have all these different functions?

1
  • 1
    About your question: who is Robert Martin and what problem did he mention? (could you add a link/quote?) Also, coould you please post (at last) the public API of the classes you mention?
    – utnapistim
    Commented Aug 20, 2015 at 8:59

1 Answer 1

1

You can use the single responsibility rule to split apart this manager class.

From your description, the BufferManager holds the collection of buffers, distributes and processes the observations, and provides access to the intervals of the buffers.

The first step is to split the data from the manager. The map and the enum don't belong to the manager. Maybe you want to tie them together, in which case you'd make a separate class that owns the map and enum and say call it BufferMap.

Then you can have 2 different classes (or 3 if distributing and processing are separable). So make an ObservationProcessor, and a BufferIntervalCalculator. Then your 2 methods become:

BufferIntervalCalculator bufferIntervalCalculator(bufferMap);
ObservationProcessor observationProcessor(bufferMap);
observationProcessor.Process(observation);

Type1Interval int1 = bufferIntervalCalculator.calculateInterval<Type1Interval>(BufferId, startTime, endTime);
...
TypeNInterval intN = bufferIntervalCalculator.calculateInterval<TypeNInterval>(BufferId, startTime, endTime);
6
  • Thank you for your answer. Good idea with splitting the BufferMap and the BufferIntervalCalculator. But the main question remains: In bufferIntervalCalculator.calculateInterval<TypeJInterval>, one needs to access the map containing buffers of type J, and if we dont want to use dynamic_cast how would you do this?
    – 1v0
    Commented Aug 24, 2015 at 15:44
  • It's very hard to answer as I don't know the implementation details of your BufferMap, but from your description I expected the buffers to be separate and it would be pretty simple to create specialisations of a templated method which selected the data from the correct buffer. If that isn't applicable, could you give some more detail? Commented Aug 24, 2015 at 15:59
  • Thanks for your comment. The BufferMap just consist of N different std::maps, one for each type 1...N of Buffers. The problem is that I would have to write a function Buffer<T> getBuffer<T>(BufferID) in the BufferMap class which accesses the correct std::map but I don't know how to do this without dynamic_cast
    – 1v0
    Commented Aug 24, 2015 at 16:05
  • So if I get this right you have an array( or vector etc) of std::maps of some generic base? Commented Aug 24, 2015 at 16:52
  • yes or lets even say simple, I have an std::map<BufferID, Buffer<int>> intBufferDict and and std::map<BufferID, Buffer<double>> doubleBufferDict; and three BufferIDs BuffInt, BuffInt2, BuffDouble and now if I want a function getBuffer<int>(BuffInt2) which returns a Buffer storing ints.
    – 1v0
    Commented Aug 24, 2015 at 17:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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