Create Book class1:19
So why don't we do this? I'm going to give you a code demonstration, and then we will review some actual real-world implementations of this pattern. Here we have mostly an empty directory. The only thing I've done is set up autoloading. No other classes have been created. So let's imagine that we have a Book. This is my favorite illustration of the adapter pattern, so I think it'll help. Let's go ahead and create that class, Book, and the namespace will be Acme. Okay, so to consume a Book, we need to open it first, and I will just represent that with
Let's go ahead and create that class, Book, and the namespace will be Acme. Okay, so to consume a book, we need to open it first, and I will just represent that with a var_dump, so opening the paper book. And then next, you need to turn the page. So we will add a method, turnPage, turning the page of the paper book. Alright, and for our purposes, that's great. So now I just want to consume this class. So let's create a new file, and why don't we call it just index.php. And maybe within here, we'll have something like a Person class, and a Person needs to be able to read.
Consume Book with Person2:16
And maybe within here, we'll have something like a Person class, and a Person needs to be able to read. So we will give the Person a Book, and they will simply open it, and then turn the page. And that'll do it. So now, let's try it out. I will new up the Person, and tell them to read a new Book, which we will import at the top, use Book, and then also we need to pull in the autoloader. So require, vendor/autoload.php. So if I switch over, sure enough, we got this down, no problem whatsoever. So everything's going great, but now we're starting to see more and more people using
Extract Book interface3:29
And once again, to give you the definition, an adapter allows us to translate, or wrap, one interface for use with another. So let's see what that might look like. However, the first thing I'm going to do is extract an interface here. So I will call this BookInterface, and that looks good. So now, back in index.php, rather than just hoping that the Book adheres to our contract, and also rather than locking it to a specific concrete implementation, instead I'm just going to say, I need some kind of implementation of this contract. So I will type hint, the interface. And now, we've decoupled our code.
So I will type hint, the interface. And now, we've decoupled our code. However, if we switch back and refresh, it's still going to work just as it did before. Okay, good deal. So now, let's set up our new class. This one will be a Kindle. And remember, imagine that this class right here is not owned by you. Maybe it's from some package that you're pulling in. So the interfaces don't match. Remember that.
Build Kindle adapter5:26
interface that we're using here does not match the interface that we wish to use. So really, what we want to do now is find a way to wrap this up by creating an adapter so that we can still reference the methods that were defined in our BookInterface. However, behind the scenes, those will translate over nicely to the eReader interface. So once again, we're creating a class to allow two different interfaces to communicate. Let's see how that might work. I'm going to create a new class here, and I will call this KindleAdapter. Now, here's the key thing here. We want to make sure that this implements the interface that we're trying to adhere to. So implements BookInterface.
We want to make sure that this implements the interface that we're trying to adhere to. So implements BookInterface. So let's go ahead and add these method stubs, and now we just want to translate these methods over to what we use in this version. So it sounds like we need to inject our actual Kindle here. So Kindle, initialize the fields, and we'll get rid of the doc blocks for now. All right, so now to map open over to turnOn, all I have to do is say, return this kindle turnOn. And that's it. Our adapter is in place. Next, to turn the page, once again, I will call pressNextButton. So now, essentially, we've normalized the interfaces.
So let's go ahead and try this out. Remember, let's go back and say we're going to read a new book. So if we try that, give it a refresh. We're reading the book. But now I want them to read a Kindle. So we will new up the KindleAdapter and then pass into it our Kindle object. And that's it. So I switch back to the browser and give it a refresh. And just like that, our person is now able to consume a format that wasn't originally supported.
Generalize for e-readers8:02
I hope it does. And remember, in this case, we're just assuming that we have a Kindle. But maybe you have multiple e-readers. Well, if that's the case, then it would make good sense to change this out from KindleAdapter to any kind of e-reader that supports this interface. And we'll assume that all of them do. So I will rename this to eReaderAdapter. And then, rather than expecting a Kindle specifically, I just want anything that supports the e-reader interface. And then we can update all of these Kindle references like so.
the e-reader interface. And then we can update all of these Kindle references like so. Now, with this method, it's a lot more flexible. For example, we have our Kindle, but now let's create a new one. And this will be, how about a Nook? And I'll just update some of this, turn the Nook on. And hopefully, you get the basic idea. Now, back within index.php, we want our person to read the Nook. And very quickly, we'll switch back to make sure that works. Refresh.
Laravel adapter example8:59
And very quickly, we'll switch back to make sure that works. Refresh. And there we go. Now our person is reading a Nook. All right. So that does it for this example. Next, I'd like to show you an example from the wild. So to do that, I'm going to switch out from this simple project and over to the Laravel framework. Let's take a look at a class called FileSystemAdapter.
framework. Let's take a look at a class called FileSystemAdapter. Now, this is actually new to Laravel 5.0. What it's doing is it's wrapping the popular FlySystem API into an interface that Laravel users will be familiar with. So let me show you. Notice these methods that you've probably used if you've ever used the file facade in Laravel. So things like exists, or get, or put, or delete, or append. All of these methods that you've likely been using for a long time in your Laravel
So things like exists, or get, or put, or delete, or append. All of these methods that you've likely been using for a long time in your Laravel projects. However, now we have an option to, by using FlySystem, leverage multiple file systems, like with Dropbox or Amazon. Now, if we want the API to be as similar as possible, meaning that you continue to use these methods you're already familiar with, however, have them wrap a different interface that doesn't belong to us, in this case the FlySystem API, well, an adapter allows us to do that. And that's specifically what this class is.
to do that. And that's specifically what this class is. So as an example, let's see get. So if we want to fetch a file, whether it's on Amazon or Dropbox or something else, well, we continue to use the API we know, get. However, within here, notice that it's actually mapping that to the read method. And the same would be true, how about, for the exists method. So if you want to see if a file on S3 exists, then you call this method. However, once again, that's going to be mapped to a has method on the driver. And this file system interface, that's actually part of FlySystem.
However, once again, that's going to be mapped to a has method on the driver. And this file system interface, that's actually part of FlySystem. We don't own it. So we don't have the luxury of just updating all of those methods to fit what we need. So instead, and in conclusion, we create an adapter to wrap it and translate that interface over to one that we are using.
