views:

31

answers:

3

For example, let's say this is my abstract class:

abstract class A{
    int x;
    int y;

    void foo(A fooMe);
}

...and B and C are two classes which extend A.

What I want is for B to only be able to call foo() on other Bs, and for C to only be able to call foo() on other Cs. But I want this to be out of the hands of the programmer who's extending my A class - that is, I want a way to ensure this functionality within As code alone.

What can I do? (If possible) I'd like to avoid any hack or generics solution that's too messy - I still want foo to be able to be called like this, for example:

B b=new B();
B bb=new B();
bb.foo(b);

Edit: I'm now willing to accept a solution which uses generics, if anyone has any ideas... (I couldn't think of one)?

+1  A: 

You could make foo be final in A, and implement it as follows: have it raise an exception unless fooMe.getClass() equals this.getClass(), and otherwise call abstract method fooHook. Of course, subclasses will have to override fooHook, not foo.

I believe the final-plus-hook approach is inevitable: if a subclass could override foo, there's no way A's code alone could guarantee that any checks performed in its foo aren't just going to be blithely bypassed by a subclass.

Alex Martelli
(+1) That's a cool idea. I'll definitely be using this if I can't find another solution - although optimally I'd like to have any such error spotted at compile time, and not at runtime.
Cam
@incrediman, unfortunately I don't believe you can get it at compile time, at least without the messy generics you want to avoid, i.e. in ways letting your simple, sample code still run (but I'll be listening for suggestions and hope I'm wrong!-).
Alex Martelli
@Alex: Hm. Well although your solution avoids the generics as I asked, I think I'd rather have it use (even messy) generics than not catch stuff at compile time. I'll look into it a bit myself and post back if I find anything. Thanks again!
Cam
@incrediman, if you want to allow `A x = new B();` followed elsewhere by `someb.foo(x)` (which is quite correct in term of runtime classes), even the generics won't help.
Alex Martelli
Alright I think I'll stick with this - I couldn't find anything else, and especially in my situation there's no doubt a misuse would absolutely be caught during testing. Thanks.
Cam
A: 

Here's a hack, but it's not compile time. I don't think Java generics don't have enough covariant/contravariant type support.


class B extends A {
    @Override
    void foo(A foome) {
        if (foome.getClass() != getClass()) {
            throw new UnsupportedOperationException("...");
        }
    }
}
Tralkdu
A: 

You could enforce such a thing if you use aspect-oriented programming. Before advice could check and throw an exception for those cases that violated your requirements.

duffymo