How to reach the method of the root ancestor?

M

Marco

Hi all,

I have the following situation:

class A
method m () { (// do A.m job }
}

class B extends A
method m() { super.m(); // do B.m job }
}

class C extends B
method m() { // DON'T do B.m job BUT DO A.m job, i.e.: call A.m()
only; // do C.m job }
}

I wonder if there is a best practice to obtain that, without changing
A or B. "C extends A" is not a good answer, since C has a much else in
common with B, rather than A only.

Thanks in advance.

Marco.
 
S

Stefan Ram

Marco said:
I wonder if there is a best practice to obtain that, without changing
A or B. "C extends A" is not a good answer, since C has a much else in
common with B, rather than A only.

Given specific requirements for the behavior of a program,
I'd redesign the class system, so that this question does
not arise. I only know it from questions of others. I never
encountered it, when I have designed the classes myself.
 
M

Marco

  Given specific requirements for the behavior of a program,
  I'd redesign the class system, so that this question does
  not arise. I only know it from questions of others. I never
  encountered it, when I have designed the classes myself.

Yes, true in general. But suppose A and B are not under my control and
that I want to do what A.m does, but not what B.m does, and that C is
very similar to B for the rest.
 
S

Stefan Ram

Marco said:
Yes, true in general. But suppose A and B are not under my
control and that I want to do what A.m does, but not what B.m
does,

If »A.m« is a static method (as indicated by »A.m« above,
opposed to »A#m«), you can call it directly.
and that C is very similar to B for the rest.

Use inheritance for »is-a« relations only. Even if such a
relation is spoiled by only a single »wrong« method »B.m« then
it still is not an »is a« relationship anymore, so inheritance
is not appropriate.

Technically (notwithstanding legal issues), you now can
decompile A and B and combine the source code to a new class,
which then will be under your control.

If A, B, and the new class now share a lot of common code,
this common code can be factored out to static methods in
another class H.
 
M

Marco

  If »A.m« is a static method (as indicated by »A.m« above,
  opposed to »A#m«), you can call it directly.

Sorry, it's not static and I used a "liberal" syntax that refers to
the Java syntax.
  Use inheritance for »is-a« relations only. Even if such a
  relation is spoiled by only a single »wrong« method »B.m« then
  it still is not an »is a« relationship anymore, so inheritance
  is not appropriate.

Yes, but this is programming in the real world and not doing the
purist Philosopher with strict Ontology concepts...

B does interesting things that I'd like to reuse, but B.m doesn't
behave as I want, while A.m does. I am aware that I could screw C
completely by reversing the m's behaviour to the one of A and using
other B's methods that might rely on B's implementation of m, yet I
wonder what to do with such a trade-off.
  Technically (notwithstanding legal issues), you now can
  decompile A and B and combine the source code to a new class,
  which then will be under your control.

This is copy/paste code, which is quite worse than not committing to
the ontological meaning of is-a.
  If A, B, and the new class now share a lot of common code,
  this common code can be factored out to static methods in
  another class H.

I am trying to solve the problem for the case where m() deals with the
class instance's state, so it's not static.

Thanks for your reply.

Marco.
 
T

Tom Anderson

I have the following situation:

class A
method m () { (// do A.m job }
}

class B extends A
method m() { super.m(); // do B.m job }
}

class C extends B
method m() { // DON'T do B.m job BUT DO A.m job, i.e.: call A.m()
only; // do C.m job }
}

I wonder if there is a best practice to obtain that, without changing
A or B. "C extends A" is not a good answer, since C has a much else in
common with B, rather than A only.

Can't be done.

Your only option is to reimplement A.m's functionality in C.m.

Unless you find some way of sabotaging B.m's specific functionality, by
overriding something or passing in some dodgy parameter.

Ideally, you'd refactor here. But if A and B are third-party classes,
you're stuck. I find myself in this sort of situation quite often -
usually where there's a method i need to call in the library class, but
it's private or protected, so i often end up decompiling or otherwise
analysing it and making a copy somewhere i can see it.

Another strategy is to patch B. If you have access to the source code of B
(directly or via decompilation), you can write a modified version which
lets you write C, and then replace the version in the library by putting
it on your classpath ahead of the original B. For example, you could take:

class B extends A {
void m() {
super.m() ;
doStuff() ;
}
}

And rewrite it as:

class B extends A {
void m(boolean shouldDoStuff) {
super.m() ;
if (shouldDoStuff) doStuff() ;
}
void m() {
m(true) ;
}
}

Then you can implement C like:

class C extends B {
void m() {
super.m(false) ;
doMyOwnStuff() ;
}
}

This is something i do an awful lot.

Luckily, many of the libraries i'm working with are open source, so i can
send my patches back upstream, and hopefully later releases will make them
unnecessary.

tom
 
D

Daniel Pitts

Marco said:
Hi all,

I have the following situation:

class A
method m () { (// do A.m job }
}

class B extends A
method m() { super.m(); // do B.m job }
}

class C extends B
method m() { // DON'T do B.m job BUT DO A.m job, i.e.: call A.m()
only; // do C.m job }
}

I wonder if there is a best practice to obtain that, without changing
A or B. "C extends A" is not a good answer, since C has a much else in
common with B, rather than A only.

Thanks in advance.

Marco.
See if you can use delegation, rather than inheritance.
 
W

Wesley MacIntosh

Marco said:
Hi all,

I have the following situation:

class A
method m () { (// do A.m job }
}

class B extends A
method m() { super.m(); // do B.m job }
}

class C extends B
method m() { // DON'T do B.m job BUT DO A.m job, i.e.: call A.m()
only; // do C.m job }
}

I wonder if there is a best practice to obtain that, without changing
A or B. "C extends A" is not a good answer, since C has a much else in
common with B, rather than A only.

Thanks in advance.

There's no "super.super" in Java, so the class hierarchy would need to
be redesigned from:

class A
method m () { (// do A.m job }
// Other A stuff
}

class B extends A
method m() { super.m(); // do B.m job }
// Other B stuff
}

class C extends B
method m() { A.m(); // do C.m job }
// Other C stuff
}

to:

class A
method m () { (// do A.m job }
// Other A stuff
}

class X extends A
// Doesn't override m!!
// Other B stuff
}

class B extends X
method m() { super.m(); // do B.m job }
// Inherits other B stuff from X
}

class C extends X
method m() { super.m(); // do C.m job }
// Inherits other B stuff from X
// Other C stuff
}

This does what you want: C inherits the behaviors of B other than method
m(), and in C, super.m() calls A.m().

Of course, this only works if the preexisting class B is yours to
modify, or you can convince whoever's it is to factor out a superclass X
as above.

If neither of those applies, you have a problem. You might try
reimplementing A.m() from scratch in C.m() instead of calling super, but
that will not work if A.m() uses private fields of A. You might also try
reimplementing B as your own class MyB and then factoring out X as above.

Or you might need to rethink the whole design of this part of your code.
Delegation might turn out to be better than inheritance for your class
C, for instance. That determination would depend on the detailed
requirements that must be met by your class C.
 
M

Marco

See if you can use delegation, rather than inheritance.

yes, delegation is the only alternative I can think of (apart from
rewriting/refactoring). It forces you to rewrite all the methods, but
it seems that Eclipse can do that automatically.

Thank you all.
 
L

Lew

Yes, but this is programming in the real world and not doing the
purist Philosopher with strict Ontology concepts...

Spurious capitalization and the attempt at snide sarcasm aside, it is
precisely because it is programming in the real world that you should follow
Stefan's advice.
 
L

Lew

Marco said:
yes, delegation is the only alternative I can think of (apart from
rewriting/refactoring). It forces you to rewrite all the methods, but
it seems that Eclipse can do that automatically.

So, you decided to follow the Philosopher's Ontological advice after all.
 
M

Marco

So, you decided to follow the Philosopher's Ontological advice after all.

:) To tell it all, in the specific case that rose the question I've
rewritten/refactored, but I wanted to hear opinions about such a
problem, because it occurs fairly often.

Cheers.
 
L

Lew

Marco said:
:) To tell it all, in the specific case that rose the question I've
rewritten/refactored, but I wanted to hear opinions about such a
problem, because it occurs fairly often.

In point of fact, you effectively demonstrated a best practice as a programmer.

It is true, as you implied about "is-a/has-a" analysis, that there is a lot of
theory running around, and one should hear each "rule" with the proverbial
grain of salt, just in case. Some of those rules will survive the skeptical
eye, and will be applied wisely as the situation requires. What you
demonstrated was that an effective programmer uses tools that get the job
done, even if they follow some theory - provided that the theory is valid for
the task at hand.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top