MTI TEK
  • Home
  • About
  • LLMs
  • Docker
  • Kubernetes
  • Java
  • All Resources
Java Design Patterns | Adapter
  1. Overview and Definition
  2. Class Diagram
  3. Implementation Example
    • The Target Interface
    • The Adaptee
    • The Adapter
    • Testing the Adapter Pattern

  1. Overview and Definition
    The Adapter pattern is a structural design pattern that allows objects with incompatible interfaces to work together. It acts as a bridge between two incompatible interfaces by wrapping an existing class with a new interface that clients expect.

    Key Components:
    • Target Interface: The interface that the client expects to work with. This defines the domain-specific interface that the client uses.
    • Adaptee: An existing class with an incompatible interface that needs to be adapted. This class has useful functionality but cannot be used directly by the client.
    • Adapter: A class that implements the Target interface and wraps an instance of the Adaptee. It translates calls from the Target interface to the Adaptee's interface.
    • Client: The code that uses the Target interface to accomplish its goals, unaware that it's actually working with an adapted Adaptee.

    Benefits:
    • Interface Compatibility: Allows classes with incompatible interfaces to work together without modifying existing code.
    • Code Reusability: Enables reuse of existing classes even when they don't match the required interface exactly.
    • Separation of Concerns: Keeps interface adaptation logic separate from business logic, making code more maintainable.
  2. Class Diagram
    Adapter Pattern Components:
    • Target Interface: Operation interface - defines the interface the client expects to work with
    • Adaptee: CustomMathOperation class - existing class with incompatible interface that needs to be adapted
    • Adapter: MathOperation class - wraps the Adaptee and provides the expected interface to the client
    • Client: AdapterPatternTest - uses the adapter without knowing about the underlying Adaptee
    ┌─────────────────────────────┐
    │         Client              │
    └─────────────────────────────┘
                  │ uses
                  ▼
    ┌─────────────────────────────┐
    │        <<interface>>        │
    │         Operation           │  ← Target Interface
    ├─────────────────────────────┤
    │ + add(int, int): int        │
    └─────────────────────────────┘
                  △
                  │ implements
                  │
    ┌────────────────────────────────┐       ┌──────────────────────────────────┐
    │         MathOperation          │ ────→ │       CustomMathOperation        │  ← Adaptee
    ├────────────────────────────────┤       ├──────────────────────────────────┤
    │ - adaptee: CustomMathOperation │       │ + customAdd(String, String): int │
    │ + add(int, int): int           │       └──────────────────────────────────┘
    └────────────────────────────────┘
    
  3. Implementation Example
    • The Target Interface:
      The Target Interface defines the contract that the client expects to work with. The client expects to call an add method that takes two integers and returns an integer.
      public interface Operation {
          int add(int a, int b);
      }
      
    • The Adaptee:
      The Adaptee is an existing class with useful functionality but an incompatible interface. Here, CustomMathOperation performs addition but expects String parameters instead of integers, making it incompatible with the client's expectations.
      public class CustomMathOperation {
          public int customAdd(final String a, final String b) {
              return Integer.valueOf(a) + Integer.valueOf(b);
          }
      }
      
    • The Adapter:
      The Adapter class implements the Target Interface and wraps the Adaptee. It translates calls from the expected interface (integers) to the Adaptee's interface (strings), making the incompatible classes work together.
      public class MathOperation implements Operation {
          private CustomMathOperation adaptee;
      
          MathOperation(final CustomMathOperation adaptee) {
              this.adaptee = adaptee;
          }
      
          @Override
          public int add(final int a, final int b) {
              return adaptee.customAdd(String.valueOf(a), String.valueOf(b));
          }
      }
      
    • Testing the Adapter Pattern:
      The client code demonstrates how the Adapter pattern allows incompatible interfaces to work together. The client can use the expected interface while the adapter handles the translation to the underlying Adaptee.
      public class AdapterPatternTest {
          public static void main(String[] args) {
              // Create the adaptee with incompatible interface
              final CustomMathOperation adaptee = new CustomMathOperation();
              
              // Create the adapter that wraps the adaptee
              final Operation adapter = new MathOperation(adaptee);
              
              // Client uses the expected interface (int parameters)
              // Adapter translates to adaptee's interface (String parameters)
              final int result = adapter.add(2, 3);
              System.out.println("Result: " + result);
          }
      }
      
© 2025 mtitek