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

Kata goals and tests3:45

First, if you look over this code, this is provided as part of the kata. I didn't write it. But you'll see it's a little overwhelming. How many conditionals can we get there? So, step number one, clean up and refactor this code. Step number two is add that new item type. And if you switch over to the tests, if you're working along, you'll see those are currently commented out. So, once we complete the refactor, we can move on to this step. All right. Let's get started. Now, I'm going to scroll to the top and run all of the tests.

All right. Let's get started. Now, I'm going to scroll to the top and run all of the tests. And they currently pass. And again, that's because this code is provided for us. So, in situations like this, this represents real-life legacy code. And often, you don't even know where to begin. For example, where do I start? How do I know what can be pulled out? When you're dealing with this many conditionals, you simply, you can't follow the path. There's too many branches.

I really like this Idea. So, if we switch back, again, you'll see when we perform this tick call. Now, tick, remember, that is sort of like the command that fires every single night for the store. And that command for each item type will update the quality as well as the sell-in or sell-by date. So, if we take a look at the test, we would say, GildedRose of, this is a static constructor, and this is basic items, your standard normal items. Create a new item here. The quality is 10, and it has to be sold within 5 days. So, if we run that nightly command to tick all of the items, well, the next day, the quality decreases by 1, and the sell-in date decreases by 1.

Creating seams for refactor6:06

I'm going to create a new seam so that I can introduce brand new code. And the goal is, once I introduce all this brand new code, I will eventually be able to delete all of this without poking my fingers in it and definitely breaking something. I don't want to touch this code. So, let's say if the name is normal, or normal item types, then let's tick specifically for normal items, and we'll call it normalTick. And I will add that method right down here. Okay, so now, think about it. We have added a seam here. We're saying, all right, if we're dealing with normal item types, then I don't want to do anything down here.

Let's tackle these one by one. So we'll go to that test. It updates normal items after the sell date. Okay, so if we have an item with a quality of ten and a sell-by date of negative five, which means we're past zero, we're long past it, we'll remember what the rules are. It degrades twice as fast. Let's find that rule. Once the sell-by date has passed, quality degrades twice as fast. Okay, this is what we're checking.

Maybe. We could do something like this. Let's just have fun. Let's reduce quality by one. And then, again, if we're past that sell-by date, it goes down one more. So we're right back to where we were before, where we have a negative quality. So one option as well would be to fix this at the end. You could say, if the quality is less than zero, then reset it.

Handling Aged Brie rules9:52

So one option as well would be to fix this at the end. You could say, if the quality is less than zero, then reset it. So now, yeah, it's up to you. I think this will work, and it does. You can decide, did this clean up the code or not? Anyways, while you're thinking about that, let's move on to the next step. So next, we're going to handle that agedBrie. So I'm going to add another seam here. If it's agedBrie, then we will do a brieTick

You'll remember right here, the quality of an item can never be more than 50. All right, how about if the quality is less than 50, only in that condition should it increase. If it's above 50, we can skip this step. I run the code, and we're getting closer. Now only two failed tests. Let's look at this one. Update brie items after the sell date. If the quality is 10 and the sell date is long after,

All right, let's go back. It sounds like, well, if the sellIn is less than or equal to zero, then the quality should go up by one as well. However, we have that same thing, so I'm just going to add a bunch of code here because my main goal is to get us to green, and then we can refactor. I run the code again, and now it looks like all of them are passing. Now it's very similar to what we had up here. We can keep it like this where we constantly check for the quality,

Now it's very similar to what we had up here. We can keep it like this where we constantly check for the quality, or we can solve that at the end. Let's see what that looks like. By default, quality goes up by one, so I can now get rid of that. Next, we can get rid of that one, and we say if the sellIn date has passed, quality goes up by one again. Finally, one last check. If, as a result, the quality is now over 50,

Finally, one last check. If, as a result, the quality is now over 50, let's reset it to 50 because that is the max. Now if I run the code, it's green as well, and it more closely resembles this, which is good. Okay, I'm ready for another one. We go back to our tick method. We've handled normal items. We've handled brie. What about that's sulfurous?

Implementing Backstage Passes13:33

We can move on. I like that. So let's do one last check, and then we can move this over to a switch statement. So we finish up by checking for this string that represents a backstage pass. If that's the name of the item, then we'll say backstagePasses tick, and we'll add that method. All right, so that will fail a bunch of tests,

and we'll add that method. All right, so that will fail a bunch of tests, again, all of them related to backstage passes. We've added a new seam. All right, let's see what the rules are there. It's similar to brie. It increases in quality as the sell in value approaches. Okay, so let's add those two there. So let's see, how many tests are currently failing? Nine failed.

the price goes up. So right here, we'll say if the sellIn date is less than or equal to 10, price goes up. So quality goes up by 1. All right, but now if there are 5 days or less, it goes up one more. All right, so let's try that. If it's less than or equal to 5, quality goes up again. Finally, if the sellIn date is in the past,

quality goes up again. Finally, if the sellIn date is in the past, it drops to zero. So we could say if the sellIn date is less than or equal to zero, well, the quality is now zero as a result. All right, run the code, fingers crossed, it still fails. But now we're down to five failing tests. Let's go over these one by one. It updates backstagePass items close to the sellIn date.

Let's go over these one by one. It updates backstage pass items close to the sell date at maximum quality. Ah, yeah, we're in that situation again where the quality went above 50, and we can't allow that. So let's just do one here. If the quality is greater than 50, then it's 50. It can't go above that.

then it's 50. It can't go above that. We run the code again. Now we're down to three failing tests. What about this one? It updates backstage pass items long before the sell date. So if the quality is at 10, and the sellIn date is 11, well, that means quality goes up by one, and the sellIn date goes down by one.

So is there any final cleanup here? And maybe we could tweak a couple of things, but you know what? Let's leave it like that. Okay, so now we come to the fun part. Think about it. We've added four seams for the four different item types, which means, have a look, I can get rid of all of that, run the code, it still passes.

then we will return that one. If it is this one, paste that in, and we call that method. And then finally, if it is, what's the final one? Yeah, this weird one. Finally, we return a call to backstagePassesTick. Okay, so now I can get rid of all of that, and we switched over to a switch statement.

Refactor to polymorphic items18:14

So why don't we think in a more object-oriented way? If all of these represent an item, let's go ahead and create an Item class. And then, because we'll have different types of items, each one of those can be an extension of that Item class, like this. One will be called Brie. One will be called BackstagePasses. One will be called, what was it? Sulfurous.

One will be called, what was it? Sulfurous. And then finally, do we want to do the normal item type, or can that be contained here? Let's do either one, I think. So this could either be an abstract class, or this could represent your standard normal item. But then when we need to change that, we have these extensions.

But then when we need to change that, we have these extensions. Let's try that, and then if we need to tweak things, we will. Okay, so now check it out. Every item, we'll keep these public for now, will have the sellIn, it will have the quality, and it should have a name as well. Okay, so let's create a constructor that accepts all three of those.

Okay, so let's create a constructor that accepts all three of those. Like so. Now, if I switch back to GildedRose, and remember, at this point, everything's still passing. So we're going to play around for a little bit. Now, this GildedRose class is no longer going to store any of that. Alright, so it sounds like now, when we say GildedRose of,

Alright, so it sounds like now, when we say GildedRose, that should not return a new instance of GildedRose, because really, this is starting to become something more like this. It's going to return a new instance of our desired item. So now maybe our switch statement should go up there. We switch on the name itself, and dependent on what you give us, we will instantiate the associated item. So this would be a standard item.

And that. And that. And now if I switch back, I don't need to work with those. That's only needed for the Factory class. Okay, so now you'll see that these are squawking, and that's because you have your Item class. However, none of these yet extended. Item, Item,

Item, Item, and then one more. Okay, so now if we switch back to our Factory, that's working. So now, think about it. Let's pick any of these. When we say GildedRose, we now know we're calling a Factory class that will return to us a new instance.

we now know we're calling a Factory class that will return to us a new instance of the associated item. So in our case, we want a normal item, which means we will get a new instance of Item when we call this static method. Now, we call tick, not on GildedRose, but on the Item class, which means every one of these,

but on the Item class, which means every one of these, let's clean that up, every one of these needs a method called tick. Now again, if we decide to extract a normal class, then this should become an abstract class, and that's our way of saying any child that extends from Item has to implement this method. But at least for now,

has to implement this method. But at least for now, we're assuming there's some default behavior, which is the normal Item behavior. All right, so let's run our tests, and of course, 22 tests are passing. No big deal. We can make this work. Let's start with a single one, UpdateNormalItemsBeforeTheSellByDate.

Let's start with a single one, UpdateNormalItemsBeforeTheSellByDate. All right, let's do it. So for a standard item, we know that this maps to a normal tick, so let's grab all of this, and we're going to move it into this method here. Run it again. Oh, I did not expect that. Hmm, that should work.

Okay, so now if you think about it, at this point, get rid of this unused code, get rid of that one, and slowly map each item type. So Brie will have a tick method. So this is basic polymorphism at play. Switch back. Sulfurus does nothing. So here, when it ticks,

Sulfurus does nothing. So here, when it ticks, it handles it by doing nothing at all. Let's go back, and then finally backstage passes will tick like this. All right. Run the code. Fingers crossed, and everything still passes, which means our GildedRose class, again,

and everything still passes, which means our GildedRose class, again, is now just a factory that returns an object. And in fact, if we want to tweak this a little bit more, if you think about it, this is basically a lookup table. It associates a string with a class name. Once it has the class name, it instantiates it and passes through the quality

Once it has the class name, it instantiates it and passes through the quality and the cell in. So why don't we quickly do a lookup here, and we'll say normal corresponds to our Item class. AgedBrie corresponds to our Brie class. Sulfuras, this one here, maps to this class. And then finally, the BackstagePasses maps to this.

And then finally, the backstage passes maps to this. Okay, so now we have our lookup table. Think about it. Let's figure out what class we need. So we could say lookup and then provide the name. Now, we do have to be careful that we provide a valid key name, so we'll check for that in a minute. But I can get rid of all of this now.

so we'll check for that in a minute. But I can get rid of all of this now and just say create a new class, pass through the quality, pass through the cell, and then return that. So run the code again, and everything is still passing. So again, yeah, it's effectively a lookup table. The final step would be,

So again, yeah, it's effectively a lookup table. The final step would be, and we could add a test for this, but I won't. We'll say if ! isset $lookup, or actually maybe we should say if ! array_key_exists, we're going to look for the key here inside the lookup table. If that doesn't exist, then we will throw an InvalidArgumentException.

If that doesn't exist, then we will throw an InvalidArgumentException. Item type does not exist. And that's effectively it. Last little thing maybe you'll consider. We'll have our private lookups here. Why don't we make this more specific? These are the item types. Now, we can just update this to this. Oh, we're in a static method.

Now, we can just update this to this. Oh, we're in a static method. That'll fail, won't it? Yes. Let's make this, this can be static. That's fine. And then update these to self. There we go. That's what we're looking for.

Adding new item type25:42

There we go. That's what we're looking for. All right, so I'll let you take a look at that. All right, so now as a result of this refactor, the second portion of this kata where we have to add the new item type, don't worry, this is going to be really easy. Uncomment all of those. Run the code. They all fail,

All right? Think how easy this is now. We go to our factory. We add our new item type. And what was it? ConjuredMannaCake. Okay, whatever that is. That's going to map to a new Conjured class that we will create. All right?

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