The new class a.k.a. the problem
It is all fine and dandy, but now for some reason we need to use another payment provider. The reason might be the need to support another payment platform (Alipay vs. Paypal),
or because we can no longer work with the same payment service provider. Whatever the reason may be, we face an issue that might cause us to want to re-write everything in our code
that consumes the payment library. Or maybe there's a better way?
Take for example, the PayKal class. This code is used for another payment platform, and functions (almost) exactly like PayWithPayzilla,
but the names that the developers of PayKal
chose for their methods' names are different, and they also added a new method that doesn't exist in the PayWithPayzilla class.
That's the Paykal class:
class PayKal {
function addOneItem($name)
{
var_dump("1 item added: " . $name);
}
function addPriceToTotal($price)
{
var_dump("1 item added to total with the price of: " . $price);
}
// Unique method
addItemAndPrice($name,$price)
{
$this -> addOneItem($name);
$this -> addPriceToTotal($price);
}
}
The addOneItem method adds the name of the item in the PayKal class,
in the same way that addItem do for the PayZilla class. And addPriceToTotal
adds the item's price to the total, just as the addPrice does in the old class.
But if we try to pass a PayKal object to the Customer class, instead of a PayZilla object,
we are going to face a fatal error.
Let's give it a try:
$pay = new PayKal();
$customer = new Customer($pay);
$customer -> buy("lollipop", 2);
And the result is, not surprisingly, a fatal error:
Fatal error: Call to undefined method PayKal::addItem()
While the classes do essentially the same task, we cannot replace between the two classes because they have different names for their methods.
The adapter pattern suggests that we solve the incompatibility problem by translating the new class interface to the old class interface.
In our example, we need to translate the new PayKal class's methods to the old terminology
which is used for the PayWithPayzilla class's methods names.
In order to translate the new interface to the old interface, the adapter pattern suggests writing an adapter class with the following two main features:
- The adapter class needs to implement the interface of the original class.
- The adapter class needs to hold a reference to the new class.
In order to write an adapter class we need the old class to have an interface, and since PayWithPayzilla doesn't have any, we first need to extract one.