Click to See Complete Forum and Search --> : Design-Issue: Is-A-Modelling does not fit
Tomerland
September 11th, 2002, 01:34 AM
Dear gurus,
I have a design problem and I try to describe it as short as possible.
a)
I have an application which needs different sources for images: e.g. from an avi-file, from a frame-grabber_1, from a frame-grabber_2, .....
b)
This seems to be a real 100% "is-a modeling", so I created a base-class CInput and from that I inherited CAvi, CFrameGrabber_1, CFrameGrabber_2,....
c)
The interface is something like that:
CImg *pImg CInput::pleaseGiveMeAnImage();
d)
It works phantastic. Each client of this code uses CInput only.
BUT: Now the problem begins
1)
A framegrabber is only a "real CInput" if I want to have images
2a)
If I want to configure my different CInput's, I need access to internal data-structures (e.g. a structure with 100 entries) and that are totaly different between the different inputs
2b)
Another typical problem is the adjustment of brightness, which does not make sense on an avi
3)
This issues (2a, 2b) do not fit into my design of "Is-a-modelling" with public inheritance. It seems that only a part of my design fits to the nees of reality.
My Question:
Does anybody have an idea how to solve this design-problem in an elegant way?
Thank you
Tomerland
Gabriel Fleseriu
September 11th, 2002, 02:33 AM
Your problem sounds complicated. I don't know all of your requirements, so I will just try to write down a few thoughts:
As you said, CAvi, CFrameGrabber_1 and so on fit into the "is-a" CInput idiom, because all of them are sources you can get a CImg * from.
You say that certain operations apply to some of them, but make no sense for the others (brightness, internal settings).
The solution that springs to mind is to populate CInput with a series of virtual functions that allow you to set-up all input sources. Have the CInput's implementation of this functions throw an exception (e.g. a CImpossibleOperation). In each of CAvi, CFrameGrabber_X and so on, overrid exacltly that virtual functions that make sense for that particular source.
This of course means that you have to move ALL (private) data members to CInput, and have its ctor set them to neutral values. The ctors of the derived classes will then take care of the data members specific to that source, and let the others as the ctor of the base class set them.
Tomerland
September 11th, 2002, 02:56 AM
Thanks Gabriel.
I think you understand my problem fully.
The solution you suggest is a pretty obvious one and I also thought about it.
But what makes me suspicious is the fact that my "fine-designed-base-class" is polluted now with a lot of additional stuff which does not fit to the "is-a-dependencie".
I ask myself if there is not a much more elegant solution - e.g. one nice design-pattern which deals with such design-issues
with regards
tomerland
Graham
September 11th, 2002, 03:28 AM
You are correct that you don't want to introduce anything that a derived class can't do.
Basically, you need to start extending your hierarchy: for example, you might want to add in a CStillImage underneath CImage and derive the frame grabbers from that. CStillImage defines the brightness adjustment. In this way, CAvi (which still derives directly from CImage) isn't asked to do something it can't. Possibly you might want a CMovingImage that CAvi derives from if that needs to introduce specific functions.
I don't fully understand your other problem, but there is probably a design pattern that fits. If you can describe it in a bit more detail, maybe we can think of one.
Gabriel Fleseriu
September 11th, 2002, 03:31 AM
Hmmm. I wonder whether the effort to find a better concept is worth. I also tend to seek good design solutions, but when you're under a dead-line you sometimes have to go with the best solution that is available:). Of course, I don't know your situation.
Could this be a solution?
class CInput
{
// common functionality
};
class CBasicAvi
{
//AVI specific functionality
};
class CBasic... // the rest of specialized functionalities, for the other sources
class CAvi: public CInput, CBasicAvi
{
//...
};
I wrote this out of the bat, there may be aspects I didn't think about.
Tomerland
September 11th, 2002, 03:41 AM
Thanks for your hints ! ! !
Fortunately I do not have time-preasure in my project.
So I have time to look for the "best" solution.
Tomerland
Tomerland
September 11th, 2002, 03:52 AM
Hi Graham.
Let me try to formulate my problem in a more abstract way:
a)
I have a base-class and some derived classes.
b)
All these classes have some interfaces in common (let's say 80%) - this is the reason for "is-a-modelling" by public interitance
c)
But these classes are also different in some behaviour (let's say 20%)
May be [ :-)) ] my right question is: Is "is-a-modelling" the right design.
Thanks
Tomerland
Gabriel Fleseriu
September 11th, 2002, 04:16 AM
Originally posted by Tomerland
Hi Graham.
Let me try to formulate my problem in a more abstract way:
a)
I have a base-class and some derived classes.
b)
All these classes have some interfaces in common (let's say 80%) - this is the reason for "is-a-modelling" by public interitance
c)
But these classes are also different in some behaviour (let's say 20%)
May be [ :-)) ] my right question is: Is "is-a-modelling" the right design.
Thanks
Tomerland
This way I'd say that the 80% belong to the common base class and the rest of 20% in the derived classes. But I'm sure that it's not that simple, or else you wouldn't ask the question.
What Graham says is correctly (IMHO): you need to extend the class hierarchy. The question is to whom apply the properties that differ from source to source: to the resulting CImg or to the underlaying CInput (i.e. to that specific source). It does not make sense to introduce another level of indirection for CImg if the specialized behaviour applies to the CInput children, IMHO.
Maybe you could boil down a simple example (in words) so we can get an idea.
Graham
September 11th, 2002, 05:56 AM
Originally posted by Tomerland
Hi Graham.
Let me try to formulate my problem in a more abstract way:
a)
I have a base-class and some derived classes.
b)
All these classes have some interfaces in common (let's say 80%) - this is the reason for "is-a-modelling" by public interitance
c)
But these classes are also different in some behaviour (let's say 20%)
May be [ :-)) ] my right question is: Is "is-a-modelling" the right design.
Thanks
Tomerland
I understood that, it was the problem you've labelled 2a that wasn't clear:
If I want to configure my different CInput's, I need access to internal data-structures (e.g. a structure with 100 entries) and that are totaly different between the different inputs
What do you mean by "configure"? Why do you need access to internal data structures? I don't quite see the problem: at some point, you're going to have dedicated code that deals with one specific concrete class rather than one of the abstractions. It may that this dedicated code is just the code that creates an appropriate object, but there's got to be something. Surely that is the place where you can do your configuring - where you know exactly what you're dealing with, rather than an abstraction. Or have I missed the point?
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.