I'm having trouble designing a good architecture for a particular portion of my application, especially where maintaining state is involved.
I have a group of parsing operations:
My class Reader reads in a block of data into a buffer and handles the overall control flow.
My class Parser takes the block of data in the buffer and a ParsedDataHandler, and divides it up into smaller chunks for the ParsedDataHandler to manage.
ParsedDataHandler is an interface that I am trying to design; I think I want to do something like this ("BlockInfo" represents some data structure containing various bits of state that will include a ByteBuffer holding the entire block of raw data. "ChunkMetadata" represents information including the position of each chunk within the block, and any other information the Parser has determined about the chunk)
interface ParsedDataHandler
{
void beginBlock(BlockInfo bi);
void handleParsedData(BlockInfo bi, ChunkMetadata m);
void endBlock(BlockInfo bi);
}
so Reader will call ParsedDataHandler.beginBlock() to let it set up any state at the beginning of a block, and is committed to leaving a designated portion (probably all) of the BlockInfo constant until it makes a matching call to ParsedDataHandler.endBlock() -- afterwards it might reuse the data buffer for the next block. Parser runs through the data block and splits it into chunks according to a predefined data protocol, and will call ParsedDataHandler.handleParsedData() multiple times, once for each chunk. One reason for the contract to include a buffer that remains fixed, is so that ParsedDataHandler can copy the whole block of data at the beginning or end, and doesn't have to reassemble the chunks into the one block when they were there together all the time.
So there's a division of responsibility:
Readeris just responsible for managing the overall routine and reading in the data, it couldn't care less about anything else.Parseris the thing that splits the data block into chunks and it couldn't care less about what to do with them or how the data got thereParsedDataHandleris the interface I'm trying to design so that concrete classes can implement it and work correctly, withoutReaderorParsercaring what it does, or without it caring about how to divide up the block into chunks or where the data came from.
My question is, should the burden on maintaining any state be on the class implementing ParsedDataHandler and kept out of BlockInfo? And if the semantics of my interface include the fact that the raw data block in BlockInfo will not change between calls of beginBlock() and endBlock(), should I then only pass it in to beginBlock() and not to the other calls? or is it okay to send it along for convenience's sake?
Is there a better design pattern to handle a situation like this?