15

I have a class, which wraps another class of a common base type. Because the base type interface is quite large this involves writing a lot of pass-through functions. I am looking for a way to avoid this.

Let's make an example:

      Car
     /   \
Volvo     VolvoWithTrailer

Now I have to implement each and every function in the car interface for VolvoWithTrailer and call the appropriate function on the wrapped Volvo object except maybe GetMaxSpeed() which will return something lower. Basically I will have many functions like

int VolvoWithTrailer::GetNumSeats() {
  return mVolvo.GetNumSeats()
}

An obvious way to solve this would be to make VolvoWithTrailer a subclass of Volvo

    Car
     |
   Volvo
     |
VolvoWithTrailer

but that seems to violate the principle of favoring composition over inheritance.

How else could I avoid writing all those wrappers (the language is C++)? Or - if that is your position - why should I just write them/just use inheritance? Is there any template magic that could help with this?

5
  • 2
    Haven't though this out too much, and thinking in Java. What about a 'Trailer' interface? VolvoWithTrailer would extend the Volvo and implement the Trailer interface?
    – user40980
    Apr 22, 2013 at 21:34
  • 8
    Favor composition over inheritance only when it makes sense to do so. Apr 22, 2013 at 23:13
  • @RobertHarvey: +1. That's a guideline, not a "principle," and certainly not an absolute commandment. Apr 22, 2013 at 23:23
  • 1
    In Python you can solve this with introspection (what C# calls reflection).
    – user16764
    Apr 22, 2013 at 23:56
  • 1
    Doesn't your IDE handle code generation? Apr 23, 2013 at 0:50

2 Answers 2

5

My opinion is that you should write whatever you need to write to make the long-term stability and maintainability of the program better. What's the point in avoiding writing 20 lines of code today, if every time you touch something that uses this code or come back to maintain this Class, it costs you an extra 5 minutes or more because you didn't put in the time today?

So the question then becomes "what do you need to write?" I don't think you provide enough information to be able to give a definitive answer, so I'll just list some things that I would think about in making a decision:

1. Do you need to have the Trailer object by itself, now or in the forseeable future?
If so, you have a pretty good argument for making the wrapper around both composited objects, since you already are going to have to wrap one or the other. Might as well be consistent.

2. Is any of the three types (Car, Trailer, CarWithTrailer) in an area of the code that developers go into frequently or look likelly to become so?
If so, be very careful, because the ramifications of choosing the wrong thing can be very costly amortized over every time the code is touched. If not, it may not make any difference what you decide. Just pick a direction and go with it.

3. What's easiest to understand?
Does one approach jump out at you that someone coming behind you would immediately "get" what you're trying to do? Do your teammates have particular biases that might make one approach harder for them to maintain? If all things are equal, pick the solution that imposes the lowest cognitive load.

4. Are there any additional advantages to using one approach over another?
One thing that jumps out at me is that the wrapper idea has a distinct advantage if you write it that your CarWithTrailerWrapper can wrap any car and any trailer into a CarWithTrailer. Then, you wind up writing all your pass-through methods, but you only write them once, rather than once for each Car Class.

This makes your initial investment in writing the pass-through methods much cheaper as you add more Cars and Trailers. It also helps reduce the temptation to couple things too directly to the Volvo or VolvoWithTrailer, while reducing the consequences of coupling to the CarWithTrailerWrapper, since you can do way more with just that one implementation.

Maybe there are distinct advantages you'd get for free by using the extension method, but I don't see them.

OK, so it looks like I've talked myself round to going ahead and filling in the pass-through methods, for non-trivial applications.

I'm not a C++ programmer, so I have no idea what code generation tools are available to you. The IDE I use can generate methods from an Interface, and I can add code templates that would make writing pass-throughs pretty painless. If you don't have access to an IDE that does this, you can actually get pretty far letting Excel write code for you.

3

Because the base type interface is quite large this involves writing a lot of pass-through functions.

And there's your problem.

Interfaces should handle one responsibility only. Keeping them thin and focused limits the amount of passthrough work you might need to do in case of a decorator, proxy or other wrapper (in addition to making the class simpiler to use, test, maintain and extend).

1
  • 6
    Uh, what? One Class can implement multiple interfaces, and interfaces can inherit from one another. So even if an Interface is quite small, that has nothing to do with whether or not Classes that implement them will need a lot of functions or pass-through functions. The smaller and more well-defined the classes, the more likely it becomes that you will need pass-through functions. Apr 23, 2013 at 1:24

Your Answer

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

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