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

Problem: Plan conditionals0:00

Today's question comes from Diaz, who asks, how can I translate a switch statement into polymorphism? And how does it work? What does it look like? Okay, let's review an example here. I have a RegistrationController. And when we submit a form, possibly, we accept a $plan. And that can be one of three options. A free plan, and that would be like your guest account. A monthly plan would subscribe you and then create your account. In this case, I'm deferring to a method.

A monthly plan would subscribe you and then create your account. In this case, I'm deferring to a method. But yeah, in your project, it could be like a billing gateway class or dependency. It doesn't matter. And then finally, if the plan type they select is lifetime, well, we're not going to subscribe them. We're just going to charge them one time and then create their account. Okay, so very simple, very basic. Lots of pseudocode here so that we can stay on task. Now, already, this is starting to feel gross.

Lots of pseudocode here so that we can stay on task. Now, already, this is starting to feel gross. And we're even using pseudocode. In real life, each one of these conditionals is going to be more complicated. You're going to be checking the request. You're going to do custom validation. You're going to be doing lots of stuff. You know how it is. So we want to refactor this. So often, your first step is, well, I keep checking the plans type.

Refactor to switch1:03

So we want to refactor this. So often, your first step is, well, I keep checking the plans type. So maybe this is an indication that I should use a switch statement. So we're going to copy the whole thing and create our second pass. Okay, so now up here, we're going to use a switch statement on the plans type. And we'll say, well, if the plan is free, well, then we will create the user. Next, if the case is monthly, then we're going to set up a subscription for the user. So we can get rid of that. And then we'll do these two, like so. And then finally, if we have a case of a lifetime plan, then in that case,

And then we'll do these two, like so. And then finally, if we have a case of a lifetime plan, then in that case, let's see what we have to do. We need to charge them one time and create the user. So this is your second pass at it. And we can get rid of all of this here. Okay, so let's take a look at it now. We do some validation, then I'm leaping off. But we check the plans type. And yeah, I mean, it's different.

Model plans as classes3:18

But they do share a common interface. All right. So let's break this down. Because we had a switch statement, it's almost like we could have three different classes here. And what would separate them? Well, let's think about it. We had that free account, right? So we could even call that Guest. So we have a concept of a Guest account. We have a concept of a regular account, which is a SubscribedAccount.

So we have a concept of a GuestAccount. We have a concept of a regular account, which is a SubscribedAccount. And then we have a final concept of a LifetimeAccount. Now, these could be their own classes. Or if it helps you, we could use inheritance. So a LifetimeAccount could extend Account. A GuestAccount could extend Account. It just depends upon how you've constructed things. All right. So now we have these three concepts here.

All right. So now we have these three concepts here. Let's go ahead and turn them into classes. And each of those will now have a register method. So if you need to register for a guest account, that logic will now live here. A subscribed account's logic will live here. And then finally, a lifetime account's logic will live here. All right. So now, yeah, you can just take this logic here. In this case, createUser.

So now, yeah, you can just take this logic here. In this case, createUser. Yeah, it could be an Eloquent call. Once again, it just doesn't really matter in this particular case. Maybe you have createUser here. Or again, maybe you're extending Account. And that logic will live on Account. It's entirely up to you. All right. So let's go back up.

All right. So let's go back up. This is now done. For monthly accounts, we once again defer to some kind of Gateway class. So I will grab all of that, paste it in. And again, subscribe to, that very well could be something like this. Gateway subscribe. And then account could inject that through the constructor. OK. Finally, if we scroll up, we can get rid of that one.

OK. Finally, if we scroll up, we can get rid of that one. LifetimeAccount just charges the User. It doesn't subscribe them. And then it defers to createUser. So we could place that here. And yeah, maybe each of these returns the generated User. Whatever is appropriate there. OK. So now, immediately, all three of these classes are much easier to understand.

Choosing strategy instances5:11

OK. So now, immediately, all three of these classes are much easier to understand. There's no conditionals. They're easy to test. This is great. So now if we come back up, we've removed the switch statement entirely. But now we just have this plan. And we need to associate it with a class. And you can do this in a number of ways. You could use what we call a factory class.

And you can do this in a number of ways. You could use what we call a factory class. Now, a factory, it would be a class whose sole purpose is to construct an object. So you could have something like AccountFactory. I often think this is overkill. Many people swear by them. You never create a new instance of a class without a factory. I think that's very stupid, honestly. But nonetheless, when the logic for how you create and construct that object is complex, then creating a dedicated factory class can be useful.

But nonetheless, when the logic for how you create and construct that object is complex, then creating a dedicated factory class can be useful. So maybe here you have a method called make. It accepts the plan. And then here is where you figure out, well, how do we turn, for example, free into GuestAccount? And then we would new up that class. So return new GuestAccount. Or if the plan is monthly, how do we turn monthly into just a regular account? And then finally, if the plan is lifetime, how can we create a LifetimeAccount instance?

Or if the plan is monthly, how do we turn monthly into just a regular account? And then finally, if the plan is lifetime, how can we create a lifetime account instance out of that and pass in any dependencies it needs? That's what a factory class could do. So yes, that very much is an option. Another option is just keep it simple, stupid, and always do it inline. So maybe I'll show you two options. We could do it dynamically if you want. So if the plan is lifetime, then you could always do something like ucwords(plan). That will create lifetime.

So if the plan is lifetime, then you could always do something like ucwords plan. That will create lifetime. And then we just want to append account. And now you have that. And you could save that to class and then new up the class. And then call a register method. Yeah, that's sort of a dynamic approach. And of course, you could do some error detection. If not class exists this, then throw an Exception. But yeah, that could be a dynamic approach.

If no class exists this, then throw an exception. But yeah, that could be a dynamic approach. Another approach is a simple lookup table. I love lookup tables. So we could say plans equals this. And we'll just say if the plan is monthly, then that corresponds to an account. If it is free, then that would correspond to a guest account. And then finally, if the plan is lifetime, that corresponds to a lifetime account. All right, so now you have your lookup table. You could simply say class equals new plans plan.

All right, so now you have your lookup table. You could simply say $class equals new PlansPlan. So if $plan is equal to monthly, that would return Account. And we would new up an Account class. Now, once again, you'd probably want to do some validation, of course, up top. But maybe even a second pass where you say if not array_key_exists. So we're going to look for the $plan within the $plans array. If that's not there, then we don't know what kind of account you want. So we're going to throw an exception. Could not create an Account.

So we're going to throw an exception. Could not create an account. Otherwise, yep, we figure out the name of the class. We instantiate it. And then, you know, however you want to do this, we call a register method. So now you can see the usefulness of a factory, whether it's a dedicated class or even extracting a method. We have a lot of logic here that just figures out how do we construct this class. So like I said, you could put that within an AccountFactory if you want. You can even just put it into a method.

So like I said, you could put that within an AccountFactory if you want. You can even just put it into a method. Something like this. SignUpStrategy even. Because you'll find a lot of overtones with the strategy pattern here, which I encourage you to research. I have a number of lessons at Laracasts specifically on the strategy pattern. I use it all the time. So definitely take a look at that. So yeah, we could do something like this.

So definitely take a look at that. So yeah, we could do something like this. And then we could say this. signUpStrategy. register. Now you'll see, other than a little guarding here, we no longer have any conditionals. Which means these, by the way, can disappear entirely. And this is what we're left with. A little factory method that we call.

And this is what we're left with. A little factory method that we call. Or like I said, you extract a dedicated factory class. And then you could say RegistrationFactory. I hate using that term factory, but it helps get the point across. And then make. And that would be, I guess, your strategy. We're just doing this on the fly. At which point you could say strategyRegister. Once again, strategy isn't a good variable name.

At which point you could say strategy register. Once again, strategy isn't a good variable name. But it helps to get the point across that by using a switch statement, you establish that you have different strategies for how you register a User. And those strategies are this. So it ultimately comes down to figuring out how to calculate what that strategy is. And then triggering that logic. So that does it. But in closing, let's do point out the obvious here. You shouldn't automatically just reach for polymorphism.

When polymorphism fits9:54

But in closing, let's do point out the obvious here. You shouldn't automatically just reach for polymorphism just because it's a cool word that you've learned. Many times, a few conditionals or a simple switch statement is perfect. And don't let anyone tell you otherwise. But as always, I like this concept of ick-driven development. I keep using it more and more. So you let the grossness that you might feel when you look at a class or when you look at a method, you let that drive your refactoring process. So if you have two or three conditionals,

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