Search code examples
design-patternsapi-design

Which is the best way to implement client API


I'm trying to figure out which would be the best API to provide to the clients of my SDK. Basically, the typical use-case would be one session instance and one renderer in one application, however, this might change in the future.

Key points: is should be easy to use from the users prospective, stable and future-proof.

Method A:

 /**
 * The user have to create and maintain the module
 *
 * pros:
 *  -module explicitly added at construction time
 *  -uses an object that would be only available using the extension
 *
 * cons:
 *  -does not enforce one-o-one relation between renderer and session
 *  -the burden of maintaining the module leaved to the user
 *  -the burden of creating the module leaved to the user
 *  -fixed StreamingModule implementation forever
 * */
public void createSessionWithUserInstalledModule(VideoRenderer.Callbacks renderer) throws Exception {
    SessionFactory factory = SessionFactory.newInstance();
    StreamingModule module = new StreamingModule();
    module.useRenderer(renderer);
    factory.install(module);
    factory.create(context, sessionCreatedCallback);

}

Method B:

/**
 * A static field of the module holds the instance.
 * The module will be implicitly picked up, and instantiated
 * when it's on the classpath.
 * It will be injected into the session during construction time.
 *
 * pros:
 *  -module doesn't need to be maintained by user
 *  -trivial implementation from user side
 *
 * cons:
 *  -only one renderer is possible
 *  -only one renderer will be available to all session instances
 *  -possibility of leaking the renderer instance
 * */
public void createSessionWithStaticHolder(VideoRenderer.Callbacks renderer) throws Exception {
    SessionFactory factory = SessionFactory.newInstance();
    StreamingModule.setRenderer(renderer);
    factory.create(context, sessionCreatedCallback);
}

Method C:

/**
 * The module can be retrieved from the session instance, after the
 * session is created.
 * The module will be implicitly picked up, and instantiated
 * when it's on the classpath.
 * It will be injected into the session during construction time.
 *
 * pros:
 *  -StreamingModule implementation can be replaced in the future
 *  -session instances have their own module
 *  -only the session instance needed to be maintained (which is probably
 *  already done on the user side)
 *
 * cons:
 *  -less trivial implementation on user side
 * */
public void createSessionUsingServiceStyle(final VideoRenderer.Callbacks renderer) throws Exception {
    SessionFactory factory = SessionFactory.newInstance();
    factory.create(context, new SessionFactory.SessionCreationCallback() {
        @Override
        public void onSessionCreated(Session session) {
            StreamingModule module = session.getModule(StreamingModule.class);
            module.useRenderer(renderer);
        }
    });
}

I would choose the latter solution (C), as it I see it as a golden path between the ease of use and the future scalability. Please see my comments, and advise!


Solution

  • I almost picked A, because it's simpler to use and the middle name of "the burden" is "flexibility".

    Still, I'd go with the bastard child of A and C where there's no magic with the classpath to obtain the module.

    Thoughts/reasoning: Every time I hear the words 'JVM', 'implicit' and 'classpath' in the same sentence, I lose some hair and feel like I'm being hit by a bus.

    Some users may find it harder to deal with the async SessionCreationCallback compared to sequential code, but that's a really just a case of RTFM about computers.