views:

640

answers:

4

Given two java classes, A and B, where A is usually instantiated via B, such as:

    A myA = B.createA();

Can I create a subclass of A (let's call it SubA) and somehow have it be instantiated by the B.createA() method?

(Note that I cannot modify A and B....)

I know that not all instances of A are instances of SubA, thus I cannot do this:

    SubA mySubA = B.createA();

Similarly, I cannot cast it like this either:

    SubA mySubA = (SubA) (B.createA());

for the same reason -- it will get a ClassCastException.

Am I being dense and forgetting something fundamental, or is there no way to do this?

(Late addition: I'm so sorry, I should have mentioned that A and B have roughly 50 methods each, and all I want to do is add a single property to SubA, along with a getter and a setter. I'd really rather not implement all 50 of A's methods to invoke the corresponding method in the superclass's object.)

+3  A: 

This is usually done via a proxy:

class SubA extends A {
    private A proxiedClass;

    public SubA(A a) {
        proxiedClass = a;
    }

    public int anyMethodInA() {
        return proxiedClass.anyMethodInA();
    }
}

...

SubA mySubA = new SubA(B.createA());

Doing this manually is rather verbose, so most people use some kind of a AOP library (like AspectJ) to only intercept method calls they are interested in.

andri
Strictly, that's more of a Decorator than a Proxy. http://en.wikipedia.org/wiki/Decorator_pattern
Charlie Martin
And what if you need to reference A's private fields or methods?
Steve Kuo
+1  A: 

You could create a wrapper around it, with SubA having a constructor that takes A as the parameter.

Like this:

SubA mySubA = new SubA(B.createA());

Since all instances of SubA are instances of A, you could then assign it to your existing A variable and override any necessary methods.

A myA = new SubA(B.createA());

I can't think of any other clean way of doing it.

Erich Mirabal
+3  A: 

It sounds like like what you'd really like is to modify the behavior of both the original A and B. In that case, you could try extending both classes (where the extension of B is purely to specify a slightly different factory method for creating SubAs).

class SubA extends A {
    /** This is the one special aspect of SubA justifying a sub-class.
        Using double purely as an example. */
    private double specialProperty;

    public double getSpecialProperty() { return specialProperty; }
    public void setSpecialProperty(double newSP) { specialProperty = newSP; }

    public SubA() {
        super();
        // Important differences between SubAs and As go here....
        // If there aren't any others, you don't need this constructor.
    }

    // NOTE: you don't have to do anything else with the other methods of
    // A.  You just inherit those.
}

class SubB extends B {
    // Purely for the purposes of a slightly different factory method
    public A createA() {
        return new SubA();
    }

    // Or if you need a static method 
    // (this is usually instead of the first choice)
    public static A createA() {
        return new SubA();
    }
}

Note that at this point, you could create one of your SubB factory objects and make it look like the original B like so:

B myNewB = new SubB();
A myA = myNewB.createA();

Or, if you're using the static factory instead, it isn't quite as close a match (but it's close).

A myA = SubB.createA();

Now, if you really need to do something with the sub-property, you'll have access to it via the child interface. I.e., if you create the object like so:

SubA mySubA = SubB.createA();
mySubA.setSpecialProperty(3.14);
double special = mySubA.getSpecialProperty();

Edit to discuss "Late addition":

At this point, your SubA object should be exactly what you want. It will inherit the 50 methods from the parent (A) and you can add your additional property to the child, plus the getter and setter. I changed the code above to illustrate what I mean.

Bob Cross
For the limited information I gave in my question, this absolutely answers it. I'll have to do some digging and some experimentation to see if it works in the real situation I'm in, but I sure appreciate this answer!
Scott
Glad to hear it. Good luck!
Bob Cross
+1  A: 

If you are just wanting to add a field to A without object oriented such as changing behaviour, you could add it as an "external field". Use a WeakHashMap to map from instance of A onto the field value (just so long as the field value doesn't directly or indirectly reference A or you'll have an object life time contention issue):

private static final Map<A,FieldType> map =
    new java.util.WeakHashMap<A,FieldType>(); // thread-safe from 1.6, IIRC

public static FieldType getField(A a) {
    return map.get(a);
}
public static void setField(A a, FieldType value) {
    map.set(a, value);
}

Really we should be using WeakIdentityHashMap, but it doesn't exist in the Java library!

Tom Hawtin - tackline
It took me a few reads to get what you are saying; I would point out that what this does is externally associate a value with an instance of A, with the association automatically becoming eligable for GC when the A instance is no longer reachable.
Software Monkey
and i would also add that this method is probably not such a good idea unless you know exactly what you are doing. It makes the property distanced from the object its meant to be associated with, and can be come a maintenance nightmare. The decorator pattern mentioned in the other answers are more appropriate - i cant think of a reason why one would use a weak hashmap to add a property like this.
Chii
If you see an instance of the object more than once, my solution will behave consistently. Using a substitute object will result in confusing behaviour. And given that is is stated that A is a class presumably with state, a decorator would be carrying around redundant state which is a really bad idea.
Tom Hawtin - tackline