• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Inheritance / Komposition of multiple abstract classes

 
Christian Heupel
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi together

first of all: I have already found a lot of help in this forum the last time and just want to say its awesome what you guys are doing here! Hope i will find time and muse to contribute a bit myself

Now i have a problem for which i was not able to find a solution so far and hope one of you might give me some nice idea on how to work something out:

I am currently working in a project where I need to consume a specific set of webservices. Basically these services can be categorized as webservices that 1) retrieve data 2) push data and 3) do both. All these webservices obey certain workflows which I want to capture in an abstract class that looks something like this:


Building on this, I have two sub-classes that implement some functionality to receive data, validate return codes. For receiving information, I also need to convert the data i get from the webservice to data that makes sense to the domain my code is placed in. These classes look somewhat like that:



And:


On this basis, I can pretty much implement quiet a nice range of providers, and really only focus on the individual parts of each webservice (and what needs to be done around that stuff...). Now my problem is: How do i write a provider which must be able to do both send and receive data on the same webservice?

In other words: How do I reuse the already implemented functionality of two abstract classes? If these classes weren't abstract, I would simply have some interface providing all the functionality and use composition + delegation to create an abstract class, since these classes are already abstract, i cannot simply create private members (I could but then i would have to implement their abstract functions which i would love to omit..).

Does anyone have some kind of suggestion? (Maybe I'm doing something wrong in my design from the beginning, but i cannot really find a good way to do it differently).

Thanks a lot in advance!
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I didn't read all that code, but if you want one class to implement two services, then composition is probably a good bet.



You mention something about how you can't use composition because you only have abstract classes. I'm not really sure what you're saying there, and it doesn't make sense. If you want a Sender, then you need a concrete implementation of Sender. If you have an abstract Sender class, then you need to finish the implementation. And in particular, if you want to use composition like this, then you need to create a concrete Sender and a concrete Receiver.

On the other hand, if you don't already have or can't easily create these concrete classes, then maybe you don't gain much by composition. The benefit of composition is that you get to use an existing class's implementation without coupling yourself to it as a subclass. So maybe you just want to implement those methods directly in SR and skip the composition.

Finally, and I think this may be what you're really getting at, if there's a lot of code in an abstract Sender and a lot of code in an abstract Receiver, and you're saying you want to use both of those codebases but can't because you can't extend two classes, then we're back to what I first said: Create concrete subclasses of those two, and delegate to them, as in my example.
 
Christian Heupel
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi and thanks for your quick reply.

First of all: My problem is not the "getting it to work". It's the "making it as good as possible" part that's bugging me. Well there is a lot that I might have not pointed out as I should have and you might have seen in the code, so let met point out the issues here:

The main issue I'm having with this is that both the "sender" and "receiver" inherit from the same (abstract) parent. When I want to use composition for a class that represents "both functionalities", I am forced to create redundant code. As an Example:



If you want to use composition to create a "MultipicationAndDivisionCalculator", you will have to implement "add" and "subtract" two times, one of which will never be used. Instead I want it to stay abstract (maybe this is still not the "final class" and should stay concrete..). The Generics used in that whole stuff also keep me from liking this solution as I need to specify the generic types in the very moment I instantiate the classes and lose their power for children of this "coupled" class (I would have to create a concrete MultiplicationAndDivisionCalculator) for every possible Combination of each generic type in worst case (sorry for mixing up the generics from the former example into this little example here ). Also I don't really want to create the "MultiplicationAndDivisionCalculator" and create the other Calculators as Facades of it since this would limit my possibilities as well (and again the generics would make it just ugly..).

Do you now feel like my problem might be a bit more understandable?

Best,
Chris
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Christian Heupel wrote:
The main issue I'm having with this is that both the "sender" and "receiver" inherit from the same (abstract) parent. When I want to use composition for a class that represents "both functionalities", I am forced to create redundant code. As an Example:



If you want to use composition to create a "MultipicationAndDivisionCalculator", you will have to implement "add" and "subtract" two times, one of which will never be used.


My first choice would be to redesign the type hierarchy so that this didn't happen in the first case. Assuming you can't do that, the next best thing would be a less extreme rearrangement. For MultCalc's and DivCalc's implementations of Calculator, rather than have them implement the methods directly, they could delegate to a simple concrete Calculator implementation. If you have them accept that object as a c'tor parameter, then when the MulDivCalc class delegates to them, it can pass them both the same Calculator. This way there's no dead object, and the only repeated code is the calls to the Calculator delegate.



 
Christian Heupel
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Don't forget that I am using generics in my original example. This is absolutely useless if I use composition on the level of multi- and div- calculators. Imagine it to look like this:



I would need a Calculator for every SuperType possible then.. In addition, your example shows exactly my point. You need to implement the "add" function (and if its just to delegate..) and the "subtract" function in both, MultiCalc and DivCalc.. that's exactly what i would like to avoid.

My goal would be that only the very concrete leafs in the hierachy-tree would have to implement the abstract functions of all their ancestors
 
Matthew Brown
Bartender
Posts: 4567
8
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It might be worth having a look at the Bridge pattern. There's an object-oriented principle that classes really ought to vary for only one reason, and if you need to vary for more than one reason the suggested approach is to factor out the bits that vary and use composition.

I think my general approach would be something along the lines of:
- Define interfaces for the methods (or groups of methods) that you need to be able to vary independently of the others.
- Define (concrete) classes to encapsulate any common implementations
- For your final concrete classes, implement the interfaces you need to, and delegate to the utility classes as appropriate.

Which does sound a bit like what Jeff is suggesting. Yes, you might need to add quite a bit of delegating code, but that can't be helped. Each "proper" implementation will only be written once (and I'm assuming in real example these will be more complicated than "a + b"). And if the generic types you're interested in have stuff in common you may be able to group them in some way.

If you can trim down your original example to the essentials it might be easier to suggest an implementation, because it sounds like the calculator example wasn't a close enough match - but here's a calculator implementation with some generics included.
 
Winston Gutkowski
Bartender
Pie
Posts: 10422
63
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Christian Heupel wrote:I would need a Calculator for every SuperType possible then...

I don't think you would, but what you might need is some sort of ResultType interface. I've actually added an 'Arithmetic' interface myself, which could theoretically be implemented by most of the java.lang.Number classes, because all it does is define
T add(T value);
T subtract(T value);
T multiply(T value);
and
T divide(T value);
which most of them already implement.

Further to the good advice that you've already received, I'd just add that when you've got your interfaces sorted out, you might want to look at abstract skeleton implementations. I'm a great believer in them, and it may help to reduce the effort in implementing your 'leaf' classes. The Java Collections Framework contains a lot of good examples (Collection←AbstractCollection, List←AbstractList, etc). It does take a bit of work to get them right though

HIH

Winston

PS: If you could break up some those enormous lines in your code, it would make everything a lot easier to read. Thanks.
 
Jeff Verdegan
Bartender
Posts: 6109
6
Android IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Christian Heupel wrote:Don't forget that I am using generics in my original example.


I ignored that part because it didn't seem relevant to the overall design solution. At this point, I have to conclude that either you're misunderstanding something, or I am, and your issue is more complex than I had initially thought. I'll let others take up the torch from here. Good luck!
 
Campbell Ritchie
Sheriff
Pie
Posts: 49361
62
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Winston Gutkowski wrote: . . . PS: If you could break up some those enormous lines in your code, it would make everything a lot easier to read. Thanks.
I’ve done that. It might make it worse, since the original code mixes tabs and spaces
 
Christian Heupel
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello together,

while sleeping a bit over this topic, I realized that I made it more complex in my head than it is and you are all absolutely right (of course.. ^^)

About the formatting: Sorry if there is some inconvenience, how should it be formatted best (for future posts)? I'm a little surprised that it should contain spaces as well (except of the short example, which shouldn't contains tabs because i just wrote it in here and tabs didn't work).

Once again, thanks for discussing on this and bringing some light into ;-)

Best,
Christian

 
It is sorta covered in the JavaRanch Style Guide.
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic