Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

Design Issue (Parallel Inheritance?)

Options
  • 10-12-2009 3:34pm
    #1
    Registered Users Posts: 9,579 ✭✭✭


    Hey,

    Unfortunately, I haven't done enough on design patterns as the course didn't go far enough. A shame but well I still have to learn.

    I've attached a UML diagram of the problem. Basically I've a component that has a well defined interface that accepts some sort of data. Then depending on the 'instance' of that component where it type 1,2 or 3, the appropriate concrete implementations should be used.

    This involves a hierarchy occuring where concrete implementations are horizontally dependant on other's in the parallel hierarchy.

    Is there a design pattern to escape this. For example, If I want a new type of this component, say "4", then I have to implement a new DataHandler_4, Data_4, and Processor_4 implementation all dependent on each other.

    Maybe the solution is obvious to this but the design just smells of problems the way it is. Funnily enough I don't think I'll ever need a 4th one but just in case I'd like to be able to easily main the code and plug in a new one without modifying anything.

    I hope the UML diagram is enough. I can't give away any details of the project.

    This design might also be acceptable. Maybe I've become too obsessed with "perfect design" and cannot progress as a result :p

    Cheers.


Comments

  • Closed Accounts Posts: 1 PVinc


    Hi,

    Basically the problem here if I understand, is that the concrete implementations of these 3 abstract types are to be somehow grouped together.
    This is a very smart motivation, because it'll detect most of programmer mistakes at compile time instead of at runtime.

    With the design you presented in your post, nothing would prevent a Handler1 to deal with a Processor2 and Data3, as I can imagine that the business logic code will work with the abstract objects to use this inheritance structure.

    The easiest solution in that case (in my opinion) is to use the Generics as a restriction on top of the inheritance.

    Basically you can use 1 empty class per data type (view it as an enum but with classes...) say "DataType1" "DataType2" etc...
    All these classes extend an abstract DataType class. The advantage with this is you can actually add descriptive (and processing) methods in these types, instead of having to keep them as names.
    You could imagine have a method DataType.getDescription() (abstract) which will force any DataType (subclass) to explain what the datatype is about etc...

    Then the abstract classes of the model become:
    Abstract_DataHandler<T extends DataType>
    Abstract_Data<T extends DataType>
    Abstract_Processor<T extends DataType>

    And every subclass will use this generics mecanics to force a DataType in their definition:

    DataHandler1 extends AbstractDataHandler<DataType1>
    Data1 extends Abstract_Data<DataType1>
    DataProcessor1 extends Abstract_Processor<DataType1>

    Then in the business logic, the code should take into account the type parameter associated to the abstract class, meaning that a Abstract_DataHandler<T> can only deal with Abstract_Data<T> and Abstract_DataProcessor<T>.

    For example you can imagine (I don't know exactly how your model works in term of business logic but it's just as an example) having an abstract method in Abstract_DataProcessor<T extends DataType> with the following signature:

    Data<T> processData(... data);

    Within the class DataProcessor1 (extends Abstract_DataProcessor<DataType1>) this will ensure than this processing method returns a Data<DataType1> with the type inference done by the compiler. If a Data<DataType2> is attempted to be returned, the compiler will throw an error (such error would have been thrown at Runtime with the previous design).

    So this bring a good lot of advantages:
    - groups the parallel sub-classes to ensure they only work with each other
    - catches errors at compile time (this is the best really)
    - allows describing the data type with huge flexibility

    On a higher reuse point of view, this would also allow inheritance within the dataTypes, allowing for example an new processor to handle multiple types of data...) but I think it's not where you were going :)

    PV.


  • Registered Users Posts: 9,579 ✭✭✭Webmonkey


    Thanks for that long post! :)

    Only realized now that I actually named a class Data. This is specific data thats required internally in the process data class but not actually the data bubbled through the system :( - Sorry that was incredibly miss leading by me.

    There won't be business logic either using this. It's a component that will just have input and output. But depending on the 'instantiation of the specific component', whether 1,2, or 3, the relevent processing methods and data handling methods opperate different and have different Data "state".

    So the whole thing is a component with entry point "handle data". However, when you instantiate the component, you have 3 ways of doing it. The way you specify, changes the dynamics inside (The relevent concrete objects come into play Handle_Data_1, Process_1 and Data_1). The incoming data and out going data of the "generic" component is all the same though, it's just what happens that data internally is what's different.

    I hope that clears up things.

    Thanks once again for the post!


Advertisement