Goal
Make two incompatible things fit together.
Example
Imagine your application has a standard StorageService interface, but you now need to integrate an AWSS3Client. The AWS client has different method names and parameters. They don’t fit. You use an Adapter to wrap the AWS client so it structurally matches what your app expects.
- What your application expects
public interface StorageService {
void uploadFile(String fileName, byte[] data);
}
- The external AWS class you can’t change
public class AWSS3Client {
public void putObject(String bucket, String key, byte[] content) {
// AWS specific logic
}
}
- The STRUCTURAL Fix: The Adapter
public class S3StorageAdapter implements StorageService {
private final AWSS3Client s3Client;
private final String bucketName = "my-production-bucket";
public S3StorageAdapter(AWSS3Client s3Client) {
this.s3Client = s3Client; // Composing the object here
}
@Override
public void uploadFile(String fileName, byte[] data) {
// Adapting the method signature to fit the structure
s3Client.putObject(bucketName, fileName, data);
}
}
Why this is Structural
We are not changing the behavior of how AWS saves a file. We are purely focusing on composition—wrapping one class inside another so that the architectural pieces plug into each other correctly.