views:

103

answers:

4

I'm using a Java class library that is in many ways incomplete: there are many classes that I feel ought to have additional member functions built in. However, I am unsure of the best practice of adding these member functions.

Lets call the insufficient base class A.

class A
{
    public A(/*long arbitrary arguments*/)
    {
        //...
    }

    public A(/*long even more arbitrary arguments*/)
    {
        //...
    }

    public int func()
    {
        return 1;
    }
}

Ideally, I would like to add a function to A. However, I can't do that. My choice is between:

class B extends A
{
    //Implement ALL of A's constructors here

    public int reallyUsefulFunction()
    {
        return func()+1;
    }
}

and

class AddedFuncs
{
    public static int reallyUsefulFunction(A a)
    {
        return a.func()+1;
    }
}

The way I see it, they both have advantages and disadvantages. The first choice gives a cleaner syntax than the second, and is more logical, but has problems: Let's say I have a third class, C, within the class library.

class C
{
    public A func()
    {
        return new A(/*...*/);
    }
}

As I see it, there is no easy way of doing this:

C c;
int useful = c.func().reallyUsefulFunction();

as the type returned by C.func() is an A, not a B, and you can't down-cast.

So what is the best way of adding a member function to a read-only library class?

+1  A: 

You have a third option. You could use Scala (a Java compatible language) and its traits, which are mixins by another name.

Brian Agnew
Unfortunately, I don't have that option. I'm using a Java subset for a robotics platform (LeJOS NXJ).
Eric
+2  A: 

Why not use Composition instead of Inheritance?

class ABetterA {
    private A a;

    public ABetterA() {

    }

    // write wrapper methods calling class' A methods and maybe doing something more
}

This way, you could also mimic multiple inheritance...

Helper Method
A: 

Natural and frequent dilemma. Read about the composition vs inheritance alternative. Your second alternative is basically a composition, if we think that the object A is passed in the constructor instead of passing it in each method - that is, we would be using composition to implement a wrapper or decorator pattern.

The issue for class C returning a new instance of class A has no trivial solution, as you guessed, as long as class C decides to take responsability of creating the new instance. This is why one should pause and think before typing a "new" statement inside a class, if there is the possibility that this class will be subclassed. In yout example, it would be nice if you could tell class C what concrete class to return ... but how would it know to create it? Well we could pass him an object who knows how to instantiate an object of class A (or a subclass)... I guess you are enough motivated to read about Factories now, and design patterns in general.

There is no unique best answer, but if want a quick one: I'd make a wrapper, B class does not extend A but has a constructor with A as parameter, it delegates its methods (except the own) to the inside object. When you need to call the method in class C (I'm assuming you cant touch class C), you could write: B b = new B(c.func())

leonbloy
The only way I can touch class C is to derive another modified class from it, and doing so soon makes code unreadable.Is there an easy way way to make `B` extend `A`, and give it a constructor that takes an `A` as an argument?
Eric
No, you are mixing things here (precisely composition and inheritance). Inheritance and decorator (implemented by composition) and two alternative ways you can "touch" a class (i.e. adding behaviour-state to it). If you read about it, you'll find that inheritance is frequently overrated by those new to OOP.
leonbloy
A: 

Another option similar to Brian's sugestion is to use Aspect Oriented Programming (AOP) tool, such as ApectJ, which let you "inject" additional functionality into existing classes, even binary ones. You either preprocess the library jar to get a new one with enhanced classes ("static weaving") or you can do all of this at runtime when the library classes are loaded (so called "load-time weaving"). You can check this AspectJ example.

Even though AOP is normally used to modify existing methods (before, after or around "advices" = code pieces) you can also introduce new members and methods - check AspectJ's Inter-type declarations.

Of course there is the question whether AspectJ is supported at your limited platform.

Jakub Holý