Service Provider Framework Pattern Example
This example is created based on the explanation found in the “Effective Java, Second Edition, Chapter 2: Creating and destroying objects”. This pattern about the framework which provide multiple implementations with the compact API. Complete decoupling of implementations made this pattern interesting to me always . There are three main components: Service, provider, registration and Service Access API.
In this example, there can be number of traveling implementations, for example, using bus, train, aircraft, car and so on. They are service providers. All these service implementations need be hide behind the registration. User doesn’t worry about the service implementation an only stick to the Service API.
Let’s see the important TravelService interface which is the client completely rely on. I would like to keep this very simple with one service.
package com.ojitha.travel.service; public interface TravelService { String getVehical(); }
The particular service must be provided by the service provider. That provider is not visible to the user when the user is not register the provider. However, in some cases such as JDBC, user need to have access to the provider to register the provider.
package com.ojitha.travel.provider; import com.ojitha.travel.service.TravelService; //provider interface. public interface Provider { TravelService createService(); }
However, in this example, Provider is hide.
package com.ojitha.travel.provider.train; import com.ojitha.travel.provider.Provider; import com.ojitha.travel.service.TravelService; public class TrainProvider implements Provider { @Override public TravelService createService() { // provide train service return new TrainService(); } }
Other important component is provider registration. Which is a self initiate instance and follow the static factory method to provide singleton. All the service are registered.
package com.ojitha.travel.service.registration; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import com.ojitha.travel.provider.Provider; import com.ojitha.travel.provider.train.TrainProvider; import com.ojitha.travel.service.TravelService; public class TravelServices { //make the class non-instantiable private TravelServices(){ providers.put("train", new TrainProvider()); } private static final Map<String, Provider> providers = new ConcurrentHashMap<String, Provider>(); //register the provider public static void registerProvider(String name, Provider provider){ providers.put(name, provider); } //service access API public static TravelService newInstance(String name){ Provider provider = providers.get(name); if (provider == null){ throw new IllegalArgumentException("Provider not found"); } return provider.createService(); } }
In this registration class, all the provider implementations are encapsulated. User can refer to the particular implementation using only pre-defined values such as “train”.
package com.ojitha.travel.client; import com.ojitha.travel.service.TravelService; import com.ojitha.travel.service.registration.TravelServices; public class TravelClient { /** * @param args */ public static void main(String[] args) { // the service access API is accessed TravelService travelSerivce = TravelServices.newInstance("train"); //Service API is accessed System.out.println("traveled by "+ travelSerivce.getVehical()); } }
Typical registered Service implementation as follows which is not directly access by the above client.
package com.ojitha.travel.provider.train; import com.ojitha.travel.service.TravelService; public class TrainService implements TravelService { @Override public String getVehical() { return "Train"; } }
Comments
Post a Comment
commented your blog