2013-10-30

Designing OO APIs

I'm trying to find a good pattern to designing an API/Framework that let's clients subclass to inherit convenient behavior.
These are my requirements:

The framework owns the collection of "Things". Like this:
class Framework {
  void addAThing(Thing t)...
}

A "Thing" is probably a composition of other stuffs. So it must have a Stuff getStuff() method. The framework uses a Things Stuff sometimes.

interface Thing {
   Stuff getStuff() ;
}

So one implementation of Thing is the simple version that gets stuff from the outside.
class Thing1 implements Thing {
   private final Stuff myStuff ;
   public Thing(final Stuff myStuff) { this.myStuff = checkNotNull(myStuff) ; }
   public Stuff getStuff() { return this.myStuff }
}

The problem I have is that there can be many different Things, and the actual creation of Stuff is something that I want the subclasses to be able to implement. So I'll help them along with this:

abstract class ParentThing implements Thing {
   private final Stuff myStuff ;
   public ParentThing() { 
        this.myStuff = checkNotNull(createStuff()); 
   }
   public Stuff getStuff() { return this.myStuff }
   protected abstract Stuff createStuff() ;
}

The problem with that is that I'm relying on subclasses to be very nice about the implementation of createStuff() since the method is called in the constructor. It shouldn't for example register "this" as a callback to some other thread in createStuff since "this"-instance might not have left the constructor when the callback occurs.

So maybe this then:

interface Thing {
    void initialize() ;
    Stuff getStuff() ;
}

and then I'll fix it so that framework calls initialize before it uses the Thing, like so
 
class Framework {
  void addAThing(Thing t){ t.initialize(); ... }
}

But then I can't use final in the ParentThing class anymore, leaving me with another state of Things, "created but not initialized yet". 

So maybe I actually should have 

interface ThingBuilder {
   Thing createAThing() ;
}

and then

class Framework {
  void addAThing(ThingBuilder t)...
}

Might not be so bad with closures, but without closures/lambda it gets a bit messy on the client side.

Ideas are welcome. How to design an OO API? 

5 comments:

  1. The ThingBuilder isn't going to help you, I think. What you have is one class that wants to assign to a final member, i.e. it wants to take an action which must complete before the constructor has finished. And then you have another class which you want to take an action, but you do not want to require that that action should work even when the instance of the second class has finished its constructor. And then you want the second class to be a subclass of the first. That is: you want to take an action after construction has completed, and use the result before construction has completed.
    You need to remove at least one of those three restrictions. How about the third: don't subclass?

    ReplyDelete
    Replies
    1. "And then you have another class which you want to take an action, but you do not want to require that that action should work even when the instance of the second class has finished its constructor."

      Should be

      And then you have another class which you want to take an action, and that action should be able to assume that the constructor has finished.

      Delete
  2. "but you do not want to require that that action should work even when the instance of the second class has finished its constructor." - typo? I most certainly want the subclass to work once the constructor has finished. The problem with calling protected methods in the constructor is that they can have bad side effects during construction of an instance. Which is what I would like to prevent.
    I want all instances to have a final not-null member, I would also like to help subclasses in achieving that by providing them some recipe to get to that state. I just don't know how to do that. It doesn't have to be through inheritance but that seemed the OO-way :)

    ReplyDelete
    Replies
    1. Sort-of typo. Thinko =) You could do it via inheritance if you did it the other way around - the subclass has the final and the superclass knows how to build it. If the subclass implements an interface, then you can still use polymorphism. But you'd need a subclass per class, so you don't really gain anything unless you have some way of generating those subclasses automatically.
      Not sure subclassing is more OO than delegation, though.
      Anyway, as always, this is solved by Sather's split between subtyping and code inclusion. I really wish that had caught on.

      Delete