1

I'm looking to see if there is a design pattern that can solve the following problem. The example is fairly specific but the goal is a public + internal API. I need specific information for my underlying library but I want to present the API generically. If my question is vague or terrible I'll try and spruce it up with your comments.

As an example, let's say I am creating a public API and I want it to be agnostic to the implementation. Continuing the example, I am creating a job handler API using the Quartz (can be any library) library in the current implementation.

I want people to be able to type:

Job job = jobManager.getJob("my.job.name");
String otherInformation = job.getOtherInformation();
job.setSchedule(new IntervalSchedule(repeatInterval, intervalUnit));
job.setSchedule(new CronSchedule(cronExpression));

The Quartz API has builders for schedules (used in Trigger):

CronScheduleBuilder.cronSchedule(cronExpression);
CalendarIntervalBuilder.calendarIntervalSchedule()
                       .withInterval(repeatInterval, 
                           DateBuilder.IntervalUnit.DAY);

In my current example I would have a base interface or class Schedule. With this structure how would it be possible to get the specific information I need for the schedule builders without revealing an implementation specific object in my interface while keeping it extensible. My goal is to prevent implementation classes from leaking in to the public API. If in the future Quartz falls out of favor, the public API doesn't need to change and deprecate the Quartz specific classes. What design pattern or code reorganization am I missing?

1 Answer 1

1

A good solution here would be the abstract factory pattern. Essentially, there is an abstract base factory with a series of abstract methods for building certain abstract classes. Then, you would provide a concrete subclass of this factory implementing the methods for a certain library. Take this example:

public class ScheduleCreator {
    public abstract AbstractSchedule makeSchedule();
}

Then you would have a specific implementation for every library you need:

public class QuartzScheduleCreator extends ScheduleCreator {
    @Override
    public AbstractSchedule makeSchedule() {
        return new QuartzSchedule(); // where QuartzSchedule extends AbstractSchedule
    }
}

Then the client, using an abstract ScheduleCreator, wouldn't need to know the library supplying the implementation behind the scenes:

public void scheduleEvent(ScheduleCreator creator) {
    AbstractSchedule schedule = creator.makeSchedule();
    schedule.schedule(new Event());
}

Later, if you decide to change your implementation from Quartz to a different library (let's call it Foo), you would simply create a new FooScheduleCreator that returns an instance of FooSchedule when call makeSchedule(). Then you could supply that ScheduleCreator to the method without the Client having to bother with what library is working under the hood:

scheduleEvent(new FooScheduleCreator()); // if you want the client to use Foo
scheduleEvent(new QuartzScheduleCreator()); // if you want the client to use Quartz

Of course, each ScheduleCreator can have many more methods for whatever you need.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.