oopclass-designresponsibility

Code design: Who's responsible for changing object data?


Assuming I have some kind of data structure to work on (for example images) which I want to pre- and postprocess in different ways to make further processing steps easier. What's the best way to implement this responsibility with an OOP language like C++?

Further assuming I have a lot of different processing algorithms with inherent complexity I very likely want to encapsulate them in dedicated classes. This means though that the algorithm implementations externally have to set some kind of info in my data to indicate it having been processed. And that also doesn't look like clean design to me because having been processed seems like an info associated with the data and thus something the data object itself should determine and set on its own.

It also looks like a very common source of error in complex applications: Someone implements another processing algorithm, forgets to set the flags in the data appropriately, something in completely different parts of the application won't work as expected and someone will have lots of fun spotting the error.

Can someone outline a general structure of a good and fail-save way to implement sth like this?


Solution

  • To make sure I understand what you are asking, here are my assumptions based on my reading of the question:

    1. The data is some kind of binary format (presumably an image but as you say it could be anything) that can be represented as an array of bytes
    2. There are a number of processing steps (I'll refer to them as transformations) that can be applied to the data
    3. Some transformations depend on other such that, for example, you would like to avoid applying a transformation if its pre-requisite has not been applied. You would like it to be robust, so that attempting to apply an illegal transformation will be detected and prevented.

    And the question is how to do this in an object-oriented way that avoids future bugs as the complexity of the program increases.

    One way is to have the image data object, which encapsulates both the binary data and a record of the transformations that have been applied to it, be responsible for executing the transformation through a Transformation object delegate; and the Transformation objects implement both the processing algorithm and the knowledge of whether it can be applied based on previous transformations.

    So you might define the following (excuse my Java-like naming style; it's been a long time since I've done C++):

    1. An enumerated type called TransformationType
    2. An abstract class called Transformer, with the following methods:
      • A method called 'getType' which returns a TransformationType
      • A method called 'canTransform' that accepts a list of TransformationType and returns a boolean. The list indicates transformations that have already been applied to the data, and the boolean indicates whether it is OK to execute this transformation.
      • A method called 'transform' that accepts an array of bytes and returns an array of (presumably modified) bytes
    3. A class called BinaryData, containing a byte array and a list of TransformationType. This class implements the method 'void transform(Transformer t)' to do the following:
      • Query the transformer's 'canTransform' method, passing the list of transformation types; either throw an exception or return if canTransform returns false
      • Replace he byte array with the results of invoking t.transform(data)
      • Add the transfomer's type to the list

    I think this accomplishes what you want - the image transformation algorithms are defined polymorphically in classes, but the actual application of the transformations is still 'controlled' by the data object. Hence we do not have to trust external code to do the right thing wrt setting / checking flags, etc.