tags:

views:

47

answers:

2

Not sure how to describe this for sure, but I think I've boiled down what I want to do in the title. To elaborate, I'm looking for a design pattern that would let me have a implementation of a service that would in one situation return the result of a call synchronously but in another case return details on how to complete the call asynchronously (say a job ID).

Maybe just by defining the problem like that it's clear that what I'm trying to do breaks the idea of designing an interface contract. Could be headed in the wrong direction entirely.

What I was thinking of was possibly something like this:

public class Data {
  private int id;
  /* getter/setter */
}

public class QueuedData extends Data {
  private int jobId;
  /* getter/setter */
}

public interface MyService {
  public Data fetchData(int id);
}

public class SyncedMyService implements MyService {
  private SyncDao syncDao;
  public Data fetchData(int id) {
    return syncDao.getData(id);
  }
}

public class QueuedMyService implements MyService {
  private JobQueue queue;
  public QueuedData fetchData(int id) {
    int jobId = queue.startGetData(id);
    QueuedData queuedData = createQueuedDate(jobId);
    return queuedData;
  }
}

Is this a sensible way to go about this task? Thanks for any advice. (there's probably a design-pattern book I should be reading)

+1  A: 

This is very similar to the Future pattern used in the java.util.concurrent package. A Future represents a result that will be available in the future after the computation is completed in a separate thread. If the computation is already complete before the result is required, the computed value is returned. Else the call to get the result blocks till the computation is over.

So I think this pattern is the right way to go about having both synchronous and asynchronous services.

This is how you can implement the solution using Future:

public class Data {
  private int id;
  private final String name;

  Data(String name) { this.name = name; }
  public String getName() { return name; }  
}

public class FutureData extends Data {
  private int id;
  private final Future<String> nameFuture;

  FutureData(Future<String> nameFuture) { this.nameFuture = nameFuture; }
  @Override public String getName() { return nameFuture.get(); }  
}

public interface MyService {
  public Data fetchData(int id);
}

public class SyncMyService implements MyService {
  private SyncDao syncDao;
  public Data fetchData(int id) {
    return syncDao.getData(id);
  }
}

public class AsyncMyService implements MyService {
  private static final ExecutorService executor = 
    Executors.newFixedThreadPool(10);

  public FutureData fetchData(final int id) {
    Future<String> future = executor.submit(new Callable<String>() {
      public String call() {
        String name;
        //some long computation that computes the name using the id given
        return name;
      }
    });
    FutureData futureData = new FutureData(future);
    return futureData;
  }
}

For Quartz just replace the ExecutorService with the JobQueue and use Quartz's equivalent of Future.

abhin4v
Neat, hadn't heard of that package, I'll have to look into it. I'm not sure that it would be useful in my scenario, since I'll probably be using Quartz for the 'background' tasks.
Nick Spacek
+1  A: 

This is a fine use of Inheritance. Your SynchedMyService and QueuedMyService are following the contract/rules designated by MyService.

Also by having the fetchData() method return a type Data, you are allowing yourself the ability to build on top of the Data object and return more complex objects (like QueuedData)

If you don't want to have the logic of which of the classes to instantiate each time. Look at the Factory design pattern to assist you as you continue to grow your application

Sean