تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Defining Method Dependencies0:00

All right, next let's move on to dependencies, and I'll start with an example. Imagine you have a Newsletter class. Yes, somewhere on your website you have a form that says, subscribe to our newsletter to stay up to date. You've seen it a million times, right? All right, so what happens? The User provides their email address. They submit the form. What happens? Well, again, they might hit a controller,

What happens? Well, again, they might hit a controller, and that controller might defer to a Newsletter class. All right, so you remember how in the last episode I mentioned speak out loud and listen for the verbs? Well, one verb I just heard myself say is subscribe. Subscribe to our newsletter. So newsletter is the noun, subscribe is the verb. Let's go with that. All right, subscribe, and now what are we subscribing?

Let's go with that. All right, subscribe, and now what are we subscribing? Well, we're subscribing a User in our system, right? So let's do this. Let's type user, and now think about it. What I'm saying here effectively is this subscribe method depends, keyword alert, by the way, depends upon a User in order to function properly. All right, well, let's go ahead and create that User right now, and, yeah, if we were to try this out, I might say, well, create a new newsletter,

and, yeah, if we were to try this out, I might say, well, create a new Newsletter, and then I can say newsletter, subscribe a User. In this case, it's a new User, but it could be from a registration form or you fetch a User from your database. It doesn't matter. Now, what I like about this is it's instantly readable, almost like how I would speak out loud, and we've been trying to get to that point. Give me a Newsletter, and we subscribe a new User in our system.

Introducing Provider Coupling1:42

and we've been trying to get to that point. Give me a newsletter, and we subscribe a new User in our system. This works great. Okay, but now let's move on to step two. In real life, you're probably using some kind of dedicated newsletter provider, maybe CampaignMonitor, maybe Postmark, maybe something else. So where does that code go? Hmm, I guess it has to go immediately here in the subscribe method, so interact with maybe CampaignMonitor in this case, and then we also need to maybe update the User,

so interact with maybe CampaignMonitor in this case, and then we also need to maybe update the User, update the User, and mark them as subscribed, stuff like that. All right, well, let's use pseudocode to represent this here. Maybe CampaignMonitor has an SDK that we can download, and as part of that, and I'll warn you, I don't know anything about CampaignMonitor specifically, but often these APIs are not the most readable, intuitive things in the world, but no judgment on CampaignMonitor here at all. This is all just made-up code.

but no judgment on campaign monitor here at all. This is all just made-up code. All right, so yeah, maybe you have a campaign monitor instance, and then you need to register an API key. So add API key for all of the calls it makes, and I'll just hard code it here, and then maybe to add a user's email address to your default list, you first need to say list find by some kind of identifier. I'll just say default here, and then I'll give you the list, and then maybe you have list,

I'll just say default here, and then I'll give you the list, and then maybe you have list, and then some duplicated addToList method. Again, notice list, addToList. That's just how it turns out many, many times, and then you will add the user's email address. Yeah, you get the idea. It's all pseudocode here. We're going to see squiggly lines, but it's not that dissimilar from what you see in the wild. All right, and then finally, maybe user has access to a row.

but it's not that dissimilar from what you see in the wild. All right, and then finally, maybe User has access to a row in your users database table, so maybe you could update them and say subscribed is true, or newsletterSubscribed is true, or something like that. Finally, we return true to indicate that this User has now been subscribed to the newsletter. All right, so now I want you to think about something here. Newsletter is now coupled to User, and couple is also a keyword.

Newsletter is now coupled to User, and couple is also a keyword. When I say couple, I want you to think of something just like this. They're linked together. You can't have one without the other. Newsletter depends upon User in order to function properly. All right, I think that's fine. I don't have a problem with that, but also Newsletter is coupled to CampaignMonitor. It's linked.

but also newsletter is coupled to campaign monitor. It's linked. I can't work with newsletter if I don't also have campaign monitor, so where one goes, the other goes, to say it two times. Is that okay? Now here's the answer. It's not yes, and it's not no. It depends upon your environment, what you're building, how big it is, how much you desire and potentially need flexibility in the future, and sometimes the answer is it just doesn't matter,

how much you desire and potentially need flexibility in the future, and sometimes the answer is it just doesn't matter, and sometimes the answer is it very much does matter. So let's talk about it. Are we okay with newsletter being coupled to campaign monitor? Well, let's imagine we decide, no, I don't like that. It just doesn't make sense to me. Why do I depend upon a specific newsletter provider in order to function? Why does newsletter care? Ideally, newsletter just says, hey, I need some kind of provider to work with.

Why does newsletter care? Ideally, newsletter just says, hey, I need some kind of provider to work with. I don't care who it is. It could be campaign monitor. It could be postmark. It could be something we build on our own in the future. I don't care. All I care about is there's some way to add a user's email address to a list. How would we allow for that? I just don't know.

How would we allow for that? I just don't know. Once you hit pause, like you never do, but this time you're actually going to hit pause, and I want you to think about this. How would you make it a little more abstract so that we're not specifically referencing campaign monitor here? All right, have a think. All right, let's work through it together. One thing we might do is take any code that is unique to campaign monitor

Extracting Provider Wrapper5:49

All right, let's work through it together. One thing we might do is take any code that is unique to CampaignMonitor and extract it from the Newsletter class. Okay, so why don't we do this? Right at the bottom here, I'm going to add another class. How about this? class, and let's create our own CampaignMonitor class. All right. Next, we're going to add to list. Maybe that's the name of the method.

Next, we're going to add to list. Maybe that's the name of the method. We will need the name of the list as well as either an email address or a User. It just depends on what we want to send through here. Why don't we assume that all it cares about is an email address? In that case, we don't have to depend upon an entire User, but that can be adjusted if you want. All right, cool. Now I have a dedicated CampaignMonitor class with a method called addToList that abstracts a slightly more complex code

Now I have a dedicated CampaignMonitor class with a method called addToList that abstracts a slightly more complex code that we don't need to see every time we visit our newsletter. All right, so now if we scroll up, we're going to take all of this code here, all of the code that is unique to CampaignMonitor, and I'm going to move it into this addToList method. All right, so now I'm sort of like isolating it. I'm taking everything unique to CampaignMonitor, and I'm isolating it within its own bucket, so to speak. All right, so now, yeah, we're doubling up here.

and I'm isolating it within its own bucket, so to speak. All right, so now, yeah, we're doubling up here. Let's imagine the class they provide is like CampaignMonitorAPI or SDK or CMAPI. It doesn't matter. All right. So you instantiate it here. You add your API key. We will find the given list that we pass here, and then we add the emailAddress to that list.

We will find the given list that we pass here, and then we add the email address to that list. So all of this kind of yucky code that I don't love to see is now isolated within this single class. All right, so now if we scroll up, what do we do here? Well, I'm going to show you in two steps. Once again, we could instantiate CampaignMonitor like this, and I could say addToList, and I could say default, and then I could send through the user's email address. All right, so it's true that we still have a link

and then I could send through the user's email address. All right, so it's true that we still have a link to CampaignMonitor specifically, but we're making progress, aren't we? Now I just have this abstraction. CampaignMonitor, there's a method called addToList, and when I call it, it does a bunch of complex stuff that I don't want to see. If I scroll down there, then I can see, all right, it uses an SDK, there's an API, I reference an API key,

If I scroll down there, then I can see, all right, it uses an SDK, there's an API, I reference an API key, I track down a list, and I add an email address to that list. But again, I don't need to see it. I can tuck that away and just use this nice API I have here. All right, so that was step one. Step two is how do we get rid of Campaign Monitor specifically if that's a problem? Well, the answer is to reach for a new concept, and that concept is an interface.

Creating a Provider Interface8:39

Well, the answer is to reach for a new concept, and that concept is an interface. Now, an interface is sort of like a handshake or a contract or an agreement. It's an agreement that says, hey, if you want me to recognize you, you have to adhere to these terms and conditions. So I'll show you an example here. Let's go down, and we're going to declare an interface called NewsletterProvider, something like this.

Let's go down, and we're going to declare an interface called NewsletterProvider, something like this. Now, this is our contract. Think of it kind of like law. We're declaring terms and conditions for a contract, right? And that contract says, well, whether you are Postmark or whether you are, excuse me, be quiet, whether you are Postmark or whether you are CampaignMonitor, you have to adhere to this particular API, and we've decided that the API is a method called addToList.

you have to adhere to this particular API, and we've decided that the API is a method called addToList. All right, so here's how I define that term or that rule. I create it like a function, but I don't create a body because the interface is not the implementation. The interface is the contract. It's the agreement, but it's not the implementation. All right, so in this case, we have an interface called NewsletterProvider, and at least to start, we have one method, addToList.

called NewsletterProvider, and at least to start, we have one method, addToList. That's it. Cool. So now, do we want CampaignMonitor? And let's do this. Let's call it provider. That way, NewsletterProvider has one implementation called CampaignMonitorProvider. I like that.

called campaign monitor provider. I like that. All right, so is campaign monitor going to sign on the dotted line? Is it going to make the agreement to honor the terms and rules that newsletter provider has set? Yes, it is going to sign that. So it does it by saying implements the contract, and the contract is declared here. I am implementing this contract. All right, so notice immediately when I did that, though,

I am implementing this contract. All right, so notice immediately when I did that, though, I see these squiggly lines here. Missing function. Ignore that part. But right here, declaration must be compatible with NewsletterProvider. All right, so what's going on here? Well, take a look at this. If I deleted it entirely, now the entire class definition

Well, take a look at this. If I deleted it entirely, now the entire class definition has a squiggly line. So what's going on here is it's saying, hey, you signed on the dotted line. You agreed to the terms that were defined here, but then you didn't follow through. The terms were you would offer a method addToList, but there is no method addToList here. So you are not abiding by your end of the agreement.

but there is no method addToList here. So you are not abiding by your end of the agreement. All right, if we bring that back, now it's still complaining because it's saying, hey, you're supposed to offer a method called addToList with no parameters, but you have parameters here, and that's going to create issues here. So you can't do that. All right, well, obviously the answer is no, that's okay. You can provide a list because almost all newsletter providers

All right, well, obviously the answer is no, that's okay. You can provide a list because almost all newsletter providers have some concept of a list that an email address is being appended to. And then next, it would make sense to send through an email address. So this is our definition here. And once I update that, this now conforms to it. All right, so now we can even extend this to what is returned.

All right, so now we can even extend this to what is returned. So for example, maybe we decide when you call addToList, nothing should be returned. All right, in that case, we could add a return type of void like this, colon void. Nothing should be returned when you call this method. And this should avoid situations where maybe one implementation returns a Boolean that indicates if it was successful or not.

one implementation returns a Boolean that indicates if it was successful or not. Another implementation returns an object, and then you end up with inconsistencies, which we don't want to allow. So now, we declare nothing can be returned here. But at this point, we're not conforming to the contract anymore, so once again, we get a red squiggly line. Let's update this.

we get a red squiggly line. Let's update this. Nothing is going to be returned from this method, and we enforce that. Cool. All right, so now, what do we do here when we scroll up? We still have this reference to CampaignMonitor. All right, so now check this part out. We're going to update our Newsletter class now. I want to suggest that Newsletter depends

We're going to update our Newsletter class now. I want to suggest that Newsletter depends upon some kind of Provider in order to do its job. Now, the key thing here is it doesn't care whether that Provider uses Postmark or CampaignMonitor. It's irrelevant. That's the entire point. All it cares about is that you give it some kind of Provider that it can communicate with and send messages to.

some kind of provider that it can communicate with and send messages to. All right, so now, your next thought is, well, how do we specify what that thing is, what that thing is that newsletter can send messages to? Well, we do that through the interface. This is the agreement. This is the entire point for the interface existing. Check this out. I'm going to show you it in two stages.

Injecting the Provider Dependency13:37

Check this out. I'm going to show you it in two stages. First up, we could use methodInjection. MethodInjection just refers to injecting a dependency into a method. See? It's not complicated at all. Let's do it now. I'm going to ask for not CampaignMonitor but NewsletterProvider.

I'm going to ask for not Campaign Monitor but Newsletter Provider. I will type it here. Now, I can get rid of this, and I can instead say Provider Add to List. Okay, so I'm going to give you a minute because this is confusing initially. If you feel like you don't understand what's going on, I get it. I was there.

I get it. I was there. Give it a couple minutes. Subscribe depends on User and NewsletterProvider. But I just said NewsletterProvider isn't a class, but now we're interacting with it as if it were a class. No, we're not. We're just adding a type. We're saying give us some class that conforms to this contract, that adheres to the terms that are set forth here.

We're saying give us some class that conforms to this contract, that adheres to the terms that are set forth here. Now, that means you can give us either CampaignMonitorProvider or if you build up a new one in the future, maybe one for Postmark like we talked about, PostmarkProvider. Now, you would use the Postmark API, and maybe their API is completely different. Maybe in this case, you pass through the API key in the constructor, and then maybe they have some kind of addToDefaultList method.

Maybe in this case, you pass through the API key in the constructor, and then maybe they have some kind of addToDefaultList method like this. The entire point is each surface has its own way of doing things. But now we have isolated all of that interaction within their own designated classes. So if we scroll up to Newsletter now, we're just saying, hey, give me some kind of provider. If you want to use Campaign Monitor, great. I don't care.

If you want to use Campaign Monitor, great. I don't care. If you instead want to use Postmark, great. I don't care. And now this is going to work exactly the way it did before, but there is not a single reference to a specific newsletter service, and that's the entire point of this workflow. All right, so if we scroll down to the bottom, let's give it a shot. We instantiate newsletter. We call subscribe.

We instantiate newsletter. We call subscribe. And now which service do we want to use? Let's use Postmark. Now the user will be added to Postmark's default list. Let's switch out to Campaign Monitor. Campaign Monitor provider, and now they get added to Campaign Monitor. That's the way it works. All right, so now let's move on to the last puzzle piece. If I scroll up, this was an example of method injection.

Switching to Constructor Injection16:17

All right, so now let's move on to the last puzzle piece. If I scroll up, this was an example of method injection. And to say it again, that is injecting a dependency into the method. But now, as you can imagine, in real life, our Newsletter class probably has multiple methods, right? And each of those methods may need to communicate with your provider object. The only problem is it's only available within the subscribe method, which isn't ideal. So yeah, instead, I'm going to graduate this to constructor injection. And again, that's what you think it is.

So yeah, instead, I'm going to graduate this to constructor injection. And again, that's what you think it is. That is injecting a dependency into not the method as we did here, but instead the constructor for the class. Let's do that now. I want a newsletter provider like so, and let's make it available as a property. Now I'm going to use public here, but in real life I would probably use protected. Just remember, we haven't talked about visibility and encapsulation just yet.

but in real life I would probably use protected. Just remember, we haven't talked about visibility and encapsulation just yet, so everything is public for the time being. But in the future, we'll talk about it a little more. All right, cool. All right, so now newsletter depends upon a provider in order to do its job. I can now get rid of this entirely. So now our method signature is a little simpler, which I like. And now I can defer to the provider that's registered as a prop like this. This provider addToList.

And now I can defer to the provider that's registered as a prop like this. This provider add to list. All right, so now if we scroll down, we can update this code and be on our way. Now, in order for newsletter to be instantiated, we also have to send through which provider we want to use. Let's start with postmark, and I'll send that through. Now I can say newsletter subscribe, and let's send through just some generic user, and that will do the job. So now in the future, if we decide to switch over to campaign monitor,

and that will do the job. So now in the future, if we decide to switch over to CampaignMonitor, all I have to do is create a new CampaignMonitor implementation or provider, and then I can swap it out right here. CampaignMonitor provider, and that's it. Notice with this change, we didn't have to touch our Newsletter class because the Newsletter class never knew whether we were using Postmark or CampaignMonitor. All it knew was that we provided some kind of class, some kind of object that conformed to this interface. All right, so that's going to do it.

some kind of object that conformed to this interface. All right, so that's going to do it. Now, I want to warn you, if you watch this whole video and you very much felt overwhelmed by everything here, I mean, there's a lot of concepts, injection, classes, dependencies, interfaces, implementations, contracts, agreements, terms. There's a lot going on there. So yeah, watch the video a second time. Watch it a third time. And most importantly, put your fingers to the test.

Watch it a third time. And most importantly, put your fingers to the test. Write some code. So if you're subscribed to Lyricast, below the video is an exam. Go through the exam, and then on your own, open your editor and play around. Create interfaces, create classes, create implementations, pass one dependency to another. Here's an example you might play around with, maybe something like a billingGateway. There's various services we can use to charge a user. Braintree, Stripe, PayPal, and maybe they all need to offer a method like charge. So maybe you could create an interface called BillingGateway,

, , , and maybe they all need to offer a method like charge. So maybe you could create an interface called BillingGateway, and then you could create implementations like your PayPalGateway, your BraintreeGateway, your StripeGateway. And again, you're going to throw all of this code away when you're done. The only goal is just to play around and get comfortable with the general idea. And when you're done and you feel comfortable, I'll see you in the next episode.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟