With the rise of service-oriented architecture (SOA), more and more organizations are using third-party services for their enterprise systems. These companies need to keep up with a rapidly changing business environment, which can mean abandoning the services of one service provider for another.

In such cases, a business’ existing architecture might be incompatible with that of a new provider. Instead of wasting months rewriting enterprise code to make it compatible with new software, a business can use the adapter design pattern.

What Is the Adapter Design Pattern?

The adapter pattern allows classes that have incompatible interfaces to work together. It does this by converting the interface of an existing class (or software) into one that a client (or service) expects. There are two types of adapters: object adapters and class adapters.

The object adapter uses composition to wrap the adaptee with the adapter, effectively producing the interface that the client expects. So, if the client expects a string the adapter will take an integer (the adaptee) and give it the characteristics of a string.

Object adapter

The class diagram above represents the object adapter. The adapter class implements the target interface, effectively gaining access to all the interface's methods. Then it adapts an adaptee and wraps that adaptee with the target interface methods.

The class adapter uses multiple inheritance, where the adapter class is the subclass of both the adaptee and the target class. The class diagram below represents the class adapter, which you are free to use in programming languages that support multiple inheritance.

Class adapter

Implementing the Adapter Design Pattern in Java

This application will implement the object adapter. This sample application will simulate a financial organization transitioning from the use and processing of charge cards to credit cards. This organization originally used the following charge card interface:

        public interface ChargeCard {
  public void monthlyBalance();
  public void lateFee();
  public void Annualfee();
}

A popular type of charge card that this organization’s system processes is the plum card:

        public class PlumCard implements ChargeCard {
  private int cardNo;
  private String customerName;
  private double balance;

  // primary constructor
  public PlumCard(int cardNo, String customerName, double balance) {
    this.cardNo = cardNo;
    this.customerName = customerName;
    this.balance = balance;
  }

  // getters and setters
  public int getCardNo() {
    return cardNo;
  }

  public void setCardNo(int cardNo) {
    this.cardNo = cardNo;
  }

  public String getCustomerName() {
    return customerName;
  }

  public void setCustomerName(String customerName) {
    this.customerName = customerName;
  }

  public double getBalance() {
    return balance;
  }

  public void setBalance(double balance) {
    this.balance = balance;
  }
   
  @Override
  public void monthlyBalance() {
    System.out.println("In January " + this.customerName + " spent " + this.balance);
  }

  @Override
  public void lateFee() {
    System.out.println(this.customerName + " monthly latefee is $80.00");
  }

  @Override
  public void Annualfee() {
    System.out.println(this.customerName + " annual fee is $200.00");
  }
}

This financial institution is transitioning to credit cards and phasing out the charge cards, so some of their customers now have credit cards:

        public interface CreditCard {
  public void monthlyMinPayment();
  public void interest();
  public void Annualfee();
}

The financial institution enterprise system now only processes credit cards, as it is looking to discontinue the use of charge cards in the coming year. But most of their customers still use charge cards. So, the engineers decided it was best to implement an adapter until all their customers transitioned to a credit card.

        public class ChargeCardAdapter implements CreditCard {
  ChargeCard chargeCard;

  public ChargeCardAdapter(ChargeCard chargeCard) {
    this.chargeCard = chargeCard;
  }

  @Override
  public void monthlyMinPayment() {
    this.chargeCard.monthlyBalance();
  }

  @Override
  public void interest() {
    this.chargeCard.lateFee();
  }

  @Override
  public void Annualfee() {
    this.chargeCard.Annualfee();
  }
}

This ChargeCardAdapter Java class implements the CreditCard Java interface. It adapts ChargeCard (the adaptee), giving it the characteristics of a credit card. For example, the system will process the interest fee of a credit card, which is the late fee of a charge card customer that has not converted yet.

Advantages of Using the Adapter Pattern

The major advantage of using the adapter pattern is that it allows clients to use new services, libraries, and features without changing their code. This promotes application scalability.

Another advantage is that this pattern is also flexible. The adapter pattern provides two implementation methods: object adapters and class adapters.