Adapter¶
The Adapter
pattern is used to adapt a certain object to the target interface. It requires introducing an intermediate layer that acts as a link between these objects. This connector should also implement the target interface.
We can use this pattern when:
- we adjust the application that uses the old API to the new one.
- we are integrating a new library which assumes that our objects implement a certain interface (which they do not, and we do not want or cannot rewrite the implementation of these objects).
- we integrate many systems into one and we want certain groups of objects with a slightly different representation to use the same abstraction.
Example¶
The following example shows a simple adapter implementation. In this example, we can see:
- the
Student
interface, which is our target interface (i.e. the one we want to work with) - the
Pupil
class, which is an object that does not match theStudent
interface - the
PupilAdapter
class, which is an adapter, i.e. a connector, between theStudent
andPupil
objects
Note that the object that has to be adapted comes as a constructor argument to the class representing the adapter. In the adapter, for the methods implementing the target interface, the programmer's task is to come up with a way to adjust the data structure to the expected format.
import java.util.Collection;
public interface Student {
String getFullName();
String getContactDetails();
boolean isAdult();
Collection<Integer> getResults();
}
import java.util.List;
public class Pupil {
private final String firstName;
private final String lastName;
private final String email;
private final Integer age;
private final List<Integer> grades;
public Pupil(final String firstName, final String lastName, final String email, final Integer age, final List<Integer> grades) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.age = age;
this.grades = grades;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getEmail() {
return email;
}
public Integer getAge() {
return age;
}
public List<Integer> getGrades() {
return grades;
}
}
import java.util.Collection;
public class PupilAdapter implements Student {
private final Pupil pupil;
public PupilAdapter(final Pupil pupil) {
this.pupil = pupil;
}
@Override
public String getFullName() {
return pupil.getFirstName() + " " + pupil.getLastName();
}
@Override
public String getContactDetails() {
return pupil.getEmail();
}
@Override
public boolean isAdult() {
return pupil.getAge() >= 18;
}
@Override
public Collection<Integer> getResults() {
return pupil.getGrades();
}
}
import java.util.ArrayList;
import java.util.List;
public class AdapterUsage {
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new PupilAdapter(new Pupil("Andrzej", "Nowak", "anowak@sda.pl", 19, List.of(3, 4, 5))));
for (final var student : students) {
System.out.println(student.getFullName()); // Andrzej Nowak
System.out.println(student.getContactDetails()); // anowak@sda.pl
System.out.println(student.getResults()); // [3, 4, 5]
System.out.println(student.isAdult()); // true
}
}
}