Sometimes we want to use some classes but unfortunately they don't always have the methods we need or they changed over time and became incompatible. In such cases Adapter pattern helps us by adapting incompatible interface into a compatible one for our class to use.


Example


Assume that TaxCalculator class below doesn't belong to our team and we have no ability to change it. All we do is just use it in our code.


class TaxCalculator
{
private $amount;
private $rate;

public function setAmountAndRate($amount, $rate)
{
$this->amount = $amount;
$this->rate = $rate;

return $this;
}

public function calculate()
{
return $this->amount * $this->rate;
}
}

This is how we would use it.


$taxCalculator = new TaxCalculator();
echo $taxCalculator->setAmountAndRate(100, 0.5)->calculate();

Assume that we used code above in many places and other team decided to change TaxCalculator class to make it look like class below.


class TaxCalculator
{
private $amount;
private $rate;

public function setAmount($amount)
{
$this->amount = $amount;

return $this;
}

public function getAmount()
{
return $this->amount;
}

public function setRate($rate)
{
$this->rate = $rate;

return $this;
}

public function getRate()
{
return $this->rate;
}

public function calculate()
{
return $this->amount * $this->rate;
}
}

As you can see above, our original code below will break because setAmountAndRate method has been split into two different methods.


$taxCalculator = new TaxCalculator();
echo $taxCalculator->setAmountAndRate(100, 0.5)->calculate();

Because of the changes, we now have to make our original code look like the one below.


$taxCalculator = new TaxCalculator();
echo $taxCalculator->setAmount(100)->setRate(0.5)->calculate();

This would be a daunting task if we used the same piece of code in many different places in our application. You never know, TaxCalculator class could be changed in future again and we would end up repeating ourselves as well. To avoid such issues, we can introduce class below.


interface AdapterInterface
{
public function calculate();
}

class TaxCalculatorAdapter implements AdapterInterface
{
public $taxCalculator;

public function __construct(TaxCalculator $taxCalculator)
{
$this->taxCalculator = $taxCalculator;
}

public function calculate()
{
return $this->taxCalculator->getAmount() * $this->taxCalculator->getRate();
}
}

$taxCalculator = new TaxCalculator();
$taxCalculator->setAmount(100)->setRate(0.5);

$taxCalculatorAdapter = new TaxCalculatorAdapter($taxCalculator);
echo $taxCalculatorAdapter->calculate();

If TaxCalculator class changes again, all we need to change is TaxCalculatorAdapter itself once and do nothing else.