The adapter pattern converts the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.
This pattern allows us to use a client with an incompatible interface by creating an Adapter that does the conversion. This acts to decouple the client from the implemented interface, and if we expect the interface to change over time, the adapter encapsulates that change so that the client doesn’t have to be modified each time it needs to operate against a different interface.
Lets take an example i have been working on a project where we were only interacting with the oracle database and we had an interface which we were consistently using it across the application . Later we had a requirement where we had to also start interacting with the HSQLDB a in memory database for optimization purpose . We had a proprietary framework which we had to use across organization to interact with the HSQLDB and the interface that the framework had was not compatible with the interface we had so we decided to write a adapter for the same so that we can have consistency across application for db layer.
Below is the existing interface we had and for simplicity purpose i have added only two methods in the interface
public interface DbType { public <T extends Model> List<T> query(String query, String[] parametrs, RowMapper<T> rowMapper); public int update(String query, String[] parameters); }
The new hsql interface
public interface HsqlAccessor { public ResultSet select(String query, List<String> parametrs); public int update(String query, List<String> parameters); }
So to make our DbType interface compatible with the HsqlAccessor interface we wrote an adapter as below
public class HsqlAdapter implements DbType { private HsqlAccessor hsqlAccessor; public HsqlAccessor getHsqlAccessor() { return hsqlAccessor; } public void setHsqlAccessor(HsqlAccessor hsqlAccessor) { this.hsqlAccessor = hsqlAccessor; } @Override public int update(String query, String[] parameters) { return this.getHsqlAccessor().update(query, Arrays.asList(parameters)); } @Override public <T extends Model> List<T> query(String query, String[] parameters, RowMapper<T> rowMapper) { ResultSet resultSet = this.getHsqlAccessor().select(query, Arrays.asList(parameters)); return convertResultSet(resultSet, rowMapper); } public <T extends Model> List<T> convertResultSet(ResultSet rs, RowMapper<T> rowMapper) { // Method to convert the resultset into the list of Model using the rowmapper } }
Some Domain classes used are below
public class MetricMetadata implements Model { private static final long serialVersionUID = 123343; private int id; private String metricName; private String metricValueType; public MetricMetadata(int id, String metricName, String metricValueType) { super(); this.id = id; this.metricName = metricName; this.metricValueType = metricValueType; } public MetricMetadata(int id) { super(); this.id = id; } public MetricMetadata() { super(); // TODO Auto-generated constructor stub } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getMetricName() { return metricName; } public void setMetricName(String metricName) { this.metricName = metricName; } public String getMetricValueType() { return metricValueType; } public void setMetricValueType(String metricValueType) { this.metricValueType = metricValueType; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + id; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; MetricMetadata other = (MetricMetadata) obj; if (id != other.id) return false; return true; } }
public class MetricMetadataMapper implements RowMapper<MetricMetadata>{ @Override public MetricMetadata mapRow(ResultSet rs, int rowNum) { MetricMetadata metricMetadata = new MetricMetadata(); metricMetadata.setId(rs.getInt("METRIC_METADATA_ID")); metricMetadata.setMetricName(rs.getString("METRIC_NAME")); metricMetadata.setMetricValueType(rs.getString("METRIC_VALUE_TYPE")); return metricMetadata; } }
public interface Model extends Serializable { //Marker interface for all model classes. }
Driver class shows how we can use the adapter class
public class Test { public static void main(String[] args) { DbType hsql=new HsqlAdapter(); List<MetricMetadata> data=hsql.query("sql query", new String[]{"param1", "param2"},new MetricMetadataMapper()); } }