JDBC – Java Data Base Connectivity API – is a Service Provider Framework.

Class of the object returned by the static factory method not even need to be existed when that factory method is written. This kind of flexibility generates the basis of a Service Provider Framework (like JDBC – Java Data Base Connectivity API).

In a Service Provider Framework, multiple Service Providers implement services. And there are clients that is willing to use it. Service Provider Framework make this Service Provider’s implementation available to the clients decoupling the implementation from them.

There are three essential components of a service provider framework.

  1. Service Interface – which providers implement
  2. Provider Registration API – which the system provides to register the implemenetations and clients to access to them.
  3. Service Access API – which the clients use to obtain an instance of the service.
    When the clients don’t specify the criteria to choose a provider, Service Access API returns a default implementation. Here, the service access API plays as a “flexible static factory”.

There’s an optional fourth component also. It is Service Provide Interface which providers implement to create the instance of their service implementation. In the absence of the service provider interface implementations are registered by the class names and instantiated reflectively.

In the case of JDBC,

  • Connection plays the part of the Service Interface,
  • DriverManager.registerDriver is the Provider Registration API,
  • DriverManager.getConnection is the Service Access API, and
  • Driver is the Service Provider Interface.

There are numerous variants of the Service Provider Framework Pattern. For example, the Service Access API can return a richer service interface than the one required of the provider, using the Adapter Pattern.

//Service provider framework sketch
//Service interface
public interface Service {
	... // Service-specific methods go here
}

//Service provider interface
public interface Provider {
	Service newService();
}

//Noninstantiable class for service registration and access
public class Services {
	
	private Services() { } // Prevents instantiation (Item 4)
	
	//Maps service names to services
	private static final Map<String, Provider> providers =
			new ConcurrentHashMap<String, Provider>();
	
	public static final String DEFAULT_PROVIDER_NAME = "<def>";
	
	//Provider registration API
	public static void registerDefaultProvider(Provider p) {
		registerProvider(DEFAULT_PROVIDER_NAME, p);
	}
	
	public static void registerProvider(String name, Provider p){
		providers.put(name, p);
	}
	
	//Service access API
	public static Service newInstance() {
		return newInstance(DEFAULT_PROVIDER_NAME);
	}
	
	public static Service newInstance(String name) {
		Provider p = providers.get(name);
		if (p == null)
			throw new IllegalArgumentException(
					"No provider registered with name: " + name);
		return p.newService();
	}
	
}
}


Reference :

  • Effective Java TM – Second Edition by Joshua Bloch
Advertisements