State Pattern – Design Patterns (ep 17)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome back to another video in this series on design patterns for object oriented languages in this video we are going to talk about the state pattern so the state pattern is a way of managing state or rather the state pattern is a way of building a state machine in a sort of object-oriented fashion and if you're not familiar with state machine state machines are actually a well studied concept in computer science that is heavily studied theoretically and in some sense you could say that many of the state machines are memory less machines in other words machines that make decisions on the basis of where they are currently or in what state they are currently and not based on how they got there and that's how we will use the state pattern we will use the state pattern to say that you have some object that will behave differently depending on what state it is it doesn't matter how it got into that state but depending on what state it is it will do a bunch of different things so we're not gonna talk in depth about the sort of theoretical part of state machines but I'll suggest a few links in the description if you think that it sounds fascinating and if you have suggestions on interesting videos or playlists on the concept of state machines do share that in the comments I and I'm sure others would appreciate that massively and also if you want us to talk about state machine just ping me and then maybe we can talk about it at some other time but anyways here is how we can denote state machines so when we draw sate machines we say that there are states and then there are transitions between states so here's a state here's a state and here's a transition between these two states and then maybe we can have a transition back like this and then maybe a transition like this so if this is state a and this is state B then from state a you can move to B and from state B you can move to state a but from B you can also move back to state B and so forth and so forth and then we would have like a starting state and an ending State so let's look at a state machine for a very simple example imagine the subway a tram or a metro or something like when you get on to public transportation and you have to pass through a pay gate so just think of it like this like let's say there's a there's a fence here and a fan's here you are here and you want to pass through here or you want to pass through this fence and the only way to pass through this fence is through this opening and maybe there's this sort of suable thing here so so when you walk through in words you walk on this side and when you walk out words you walk on this side and then this thing spin sensor this direction right so when you come here to you push through that thing I didn't you can sort of swivel through it I am not sure what that's called like a rotating door kind of thing anyways I think you see the point as like when you when you grab a metro tear usually you would have many of these and so forth but whatever let's just think about mom and let's think about this as a machine this is sort of classical like when we talk about state machines we tend to talk about real-world machines that are really simple like a turnstile or a gumball machine or something that's sort of easy to conceptualize because you can think about the mechanics inside of it or parking machine or anything like this anyways so if you're in a subway then these turnstiles are there because they want to automate the fact that you need to pay you in order to ride the tram or the subway or the metro or whatever so so that's actually let's say that here next to it there's this sort of payment machine and maybe it has like a light here that's currently red to indicate that the turnstile is closed so what we do is that we take we take our subway card and then we swipe it or we place it let's not say swipe let's say we place it on top of this it beeps and then we walk through it right assuming we have funds on the card so let's model this kind of turnstile with a state diagram or as the state machine so which states do we have well the turnstile can be locked so at least there is a state called locked yeah I mean we could have called it closed but let's say let's call it locked it's locked as in we can't move it but then there's another state which is open so in other words what I mean is that if it's locked and then I try to pass through I can't pass through because it's locked it just it stops it doesn't spin and if it's open I can't spin it right but the problem is that we don't want wanted to indefinitely remain locked and we neither wanted to definitely remain open because if it's always open just everybody everybody can simply just pass through and nobody has to pay so then we have transitions so if it's locked you can somehow make it open and if it's open you should somehow be able to make it locked and then we have to ask ourselves what are the events or the actions that cause these transitions so when you go from locked to open that happens if you pay if you put your card and then you and then you pay and you happen to have sufficient funds on the card so let's say to keep it simple let's say pay okay so if the payment was okay then we transition from locked to open and then the user the person using the turnstile code passes through so let's call that pass or push or enter let's actually call it enter so if we enter then since we've now entered we've only paid for a single person that means since we've now entered we need to transition from having the turnstile open to now being looked actually let's call it closed this sounds strange if we say open closed so we go from open to closed but we said that when we pay we go from closed to open if we have the necessary funds if we don't have the necessary funds what happens is that we are when we're at closed we are trying to pay but we don't have the funds so let's here say pay fail ok failed maybe so if the payment failed then when when it's closed which and we try to pay then we simply stay in the closed state because the payment failed the payment it's not enough for me to just try to pay I have to actually the payment has actually go through and the payment has actually succeed had to be okay in order for me for the turnstile to go from the closed state to the open state and actually there's another interesting thing here that thing is that when we are in the open state you can also try to pay what I mean is this now this light here is red but as soon you pay and the payment is okay and the turnstile turns open then maybe this light turns green but what if you then take your card and place it on the reader again and let's say that you then still have sufficient funds so that means that in the open state you can also receive a pay okay message but that shouldn't matter if you if you try to pay again clearly your funds shouldn't be withdrawn like the payment shouldn't go through but that's something we can't really capture here or at least without adding more complexity so within this simple diagram we're not capturing that but at least what happens is that we stay in the open state it's not like if you pay once and it opens and then you decide for some reason to try to pay again it's not that it suddenly should turn closed you've already paid and nobody has passed through right that's the key point we haven't given we haven't run enter yet we haven't received the message we haven't executed the action we haven't received the event enter not until we receive the event enter should we actually move the closed so if you just stay there and you pay and pay and pay and pay and pay doesn't matter it stays open and again of course you shouldn't withdraw funds from the card so if we then receive pay okay it should still stay open now what's interesting about these sort of state diagrams is that if you think about it we have a number of events or actions and then we have a number of states and that means that we can draw this sort of table where we enumerate all of the different combinations so we can say that what we have is that we have a number of states and then we have a number of actions and let's count these we have one two three unique actions and then we have two States so let's draw these out we've got enter as an action pay okay as an action and pay failed as an action and then we've got the states closed and open and maybe I should put the headers this way to avoid any confusion actions and States so the question we ask ourselves now is that if you are in this state and you are supplied with the action in which state do you then end up or in which state do you then transition to and we can show that by simply looking at this chart that we drew so if you're in the closed state and you receive the action enter ah then actually we immediately realize that we didn't earn that before so we haven't actually drawn all of the all of the arrows necessary and if you just count that what we have is that we need one two three four five six arrows six transitions but here we actually only have one two three four so we're missing two transitions number one transition that we're missing is that if the gate is closed and somebody tries to enter what will happen I mean we talked about that before but we forgot to model it well what will happen is simply just this it's closed we try to push we try to enter we try to enter the through the turnstile but because we haven't paid and we know we haven't paid because we're in the closed state again remember there is no memory in this machine it's just that if I am currently right now in the closed state that means I have not been paid to allow somebody to enter which means I should stay in the closed state so I am in the closed state I receive the action and turn but I then transition back into the same state back into the closed state because I'm not allowed to allow someone to enter if they haven't paid I mean the closed state and I should remain in the closed state so then we know that if we are in closed and we receive the message enter we should stay in the closed state so let's let's here say that the result here is closed next one what if I mean open I mean the state open and I received the message enter I receive the event enter somebody tries to enter I mean open I received the message enter well I should transition to closed and again we're missing some pieces here like clearly what will also happen is that the user will actually enter like if this is a login system the user will actually be logged in or if this is a turnstile the user will actually will actually move to the other side of the turnstile so again we're not capturing all of this and maybe that maybe we should think about that as a state machine of the other thing or maybe we just shouldn't capture that here and worry about that in terms of code I mean we're drawing this now to try to understand how we can use the state pattern not necessarily with the intent of using state machines to describe a program to a hundred percent or - to describe a program completely but again if you are interested in that state machines are outrageously interesting so check out some of the links in the description moving on so what we said now is that if we are in the open state and we receive the message enter then we should move to the closed state so we are in open we receive enter and we move to closed and again something more should clearly happen which is that the user should be left through or the or logged in or whatever it is that we're actually modeling next one what if we are closed and we receive hey okay so if if the turnstile is closed and I receive the message the payment has now gone through which then happens if somebody puts the card and and the payment is successful well if we receive the message pay okay then as we see here in the diagram that we drew before we can see that if I'm in the closed state I receive payment okay then I should move to the open state clearly so then let's say the closed state with an okay payment moves us to the open state and let's just immediately continue what happens if I'm in the open state and I received a message pay okay so I mean the open state and I receive the message pay okay and that's what we talked about before as well if you pay the turn file opens but if you then pay again while it's open without passing through right I'm on this side the turnstile is here I pay it says green open I won't pass but instead of passing I'll just put my card again Boop right maybe it doesn't leap because it's like well stop trying to pay you've already paid right but I tried to pay and my payment is actually successful if that happens it should remain open you can also I mean it's a bit funny that we have these events that are pay okay okay and pay failed it helps in my mind and maybe it helps in your mind you can think about it this way maybe these are a synchronous events so maybe the thing is that payment initiating a payment is actually one event and then we get a response back and we'll add that complexity in just a moment but but for now think these as a synchronous events I mean the reason I'm saying that is that is that like the it feels that the wording is a bit odd that suddenly you would receive a message with just pay okay but again that happens if I'm on this side of the turnstile I've paid I haven't passed through but then I pay again and that payment is okay or again the payment wouldn't be okay because it wouldn't necessarily be processed but I can think about a synchronicity maybe so maybe I'm using some kind of third-party payment system payment processor that that calls me or sends me events and maybe for some Iran earnest reason like for an incorrect reason they send me one of these payment ok messages and then I have to think about okay how does my application handle this how will my application handle the fact that we get this message even though we were not actually expecting this message at this point in time right because we were now in an open state and we're not expecting to receive ah this payment was okay we're like what payment why did you send me this but if that happens if it happens then we shouldn't suddenly close the turnstile as we talked about before if somebody tries to double pay or if there's an error with them with a service that sends us payment okay in payments failed messages then we shouldn't suddenly punish the user for that the turnstile should remain open until somebody passes passes through so that means that if we are if the state is open and if we receive the message pay okay we should remain open so the result here is open similarly let's jump to this cell if we are open and we receive the message pay failed the same thing should happen again we are not expecting it to happen but depending on how we architect different pieces it hypothetically could happen so if you are in the open state again I've come up to the turnstile I take my card I blip my card on the blipper there's probably more correct term for that nevermind and it says okay good it turns green the turnstile is open but I'm not passing through what I do is I take my card again and then I blip it but this time I have no funds because I just paid for opening the turnstile I paid for my trip just now and those were my last funds let's say so now that I blip it the second time it will reject my payment because I no funds on the card but I still paid for one entering I still paid for one trip and I shouldn't be punished for just putting it again like maybe as a user maybe I do it by mistake so someone I do blip the second time the turnstile should still remain open again the key point is that we only move from open to closed from open to closed whenever somebody actually enters regardless of all of this other stuff and regardless again of the history if I'm in the open state unless somebody has entered the turnstile shall remain in the open state and as soon as someone enters Joop it just turns closed immediately you've paid for it you've walked somebody has walked through now it's closed so in this thing if we're in the open state and we receive the message pay failed even though it's a failed payment we should still remain an open because again if we are in the state open somebody has paid inevitably the only way to get to open is if we have received an OK payment so there is a payment and nobody has used up that payment yet and now that we added this pay failed we of course need to draw this arrow as well so let's add another arrow here this left one is pay okay and this round right one will now be pay failed by the way there are also different types of state machine diagrams so what I could have done with this okay and failed notion is that I could have had that a transition that was sort of conditional where where both of these are based on receiving the action pay but one is with the status okay and the other is where the status failed for example but I think it's just easier to stick to separate messages and now let's add this last pay failed arrow that we drew here on the right side to the table over here so if we're in the closed state and we receive the message pay failed then we stay in the open state and that's it so now we have that transition table and we essentially know that regardless of which state we are in and regardless of which action we receive we know exactly what to do and this is the power of using well firstly state machines but in object-oriented programming using the state pattern so it forces you to not wildly mute in your state by mutating different properties of some object that you have but instead mutating a single thing which is this state variable you have a state instance variable that says whether you are now closed or whether you are now open and this state variable will not contain an enum or a string or an int defining which state it is it is in it will contain its own state object and this state object will implement all of these different methods so maybe what you're seeing is that what we are doing is that we are replacing or conditional with polymorphism so if we didn't do the state pattern what we would do maybe we would have a boolean that is like is open and it's equal to either true or false and then if we receive the message enter let's say and I'm in the turnstile object so in the method enter in the turnstile object or in the turnstile class if my instance variable is open is equal to true then what I should do is that I should set is open to closed because again it was open I receive the message enter and it should now be closed so I would say something like if it is open then is open is now false because we've now entered and then of course here dot dot dot I need to do this that other stuff that I would have to do for making sure that the user is now and third or well whatever we were intending to do actually but there's a huge problem with this way of doing it but you can probably see and that is that if we have the methods enter pay okay and pay failed then we need to duplicate this conditional logic for all of these methods so we need to ask if it's open whenever the enter method is called whenever the pay okay method is called and whatever the pay failed method is called and what's worse is that now we only had closed and open but what if we also had pending so what if pay happens first as a state so what if there's closed there's open and there's pending and pending is essentially when the payment is being processed so actually let's call it that instead let's say that that state is processing so that means that closed takes us to processing and processing take us to open or may take us to closed but that also means that we need to handle the messages pay ok pay failed and enter in this third state which is processing so let me see if I get this right that should mean that we add the third state here as well I'll just write proc period as an abbreviation of processing and let's extend these lines like this and then another line here that means that the number of different implementations that we need is essentially three because of three states times three because of three messages or three methods three functions so what we're saying is that if we're not just thinking about the positive cases if we're not just thinking about the thing that we actually hope sort of hope will happen if we think about all of the cases that could happen what we could receive any of these three messages at any point in time and that means that we could receive any of those three messages in any of these three states and now clearly these states we made up so if we think about the problem we could have ended up with different states this depends on how we want to model it but if you just think about it the states that we have now have are quite intuitive like the notion of the card being processed having to wait for the card to be processed I guess it's kind of inevitable like unless you have some kind of cash solution where where you put cash inside the Machine but even then maybe there has to be some weighing of the cash or or laser checking of a bill or something like this like there's probably a delay and during that delay people can fiddle with the Machine what happens if i push the turnstile while the machine is processing a payment while the machine is in this sort of idle or in this sort of waiting state and again now we are talking about a physical device about the physical turnstile because it's just easier to think about them and probably everyone has seen such a thing but of course this could have been anything this could have been a network request so a network request is maybe unfired its fired and it has returned something or maybe if you think about promises you have some action that you want to perform and maybe initially it's unperformed then you ask it to perform the action and then you're in this sort of waiting state where the promise has not yet to resolve and then it can resolve or it can be rejected and so you can also think of this concept in in terms of states so there are many many things that we can if we think about it turn into states and then start drawing one of these transition diagrams that explicitly specify that whenever I have this particular state I want to handle this particular action in this particular way so in some sense it's a very safe way of approaching programming because suddenly you start to think about well ok this is again what I hope will happen but what if this other thing happens and then it's a way of making sure that you're not missing any cases like we did in the beginning so where I was going with this 3 times 3 is that 3 times 3 is 9 which is essentially the number of unique combinations of states and actions and thus the number of cells that we have in this table and even with state pattern we need a separate implementation for each of these 9 because that's the point the point is that we need to specify whatever happens in every combination of a state and a message but if we didn't use the state pattern either we would it's but it's actually possible that we might not have to write code for all of the states because we might bundle sum up and make them implicit rather than explicit but there's a high risk that we might miss some states and either way what we would have to do is that if you think back when we wrote this piece of code here we actually only had a single variable we had is open so then it was kind of easy because then every action had two paths it was kind of obvious if you if you call the method enter then you know that you that the turnstile is either closed or it's open and we have to do different things potentially depending on which one we're in that when we have the notion of only closed and open this is kind of easy to to model even without state pattern because we only have two states we essentially have a bool and we have two paths but if we suddenly also have processing well suddenly it's a bit difficult because what are we gonna do maybe we have a I can't remember what that's called but like a three value boon but that's probably not intended for usage like this so suddenly now we need something that holds three potential values so maybe now we start to go into craziness like having a state variable that contains one of three constants or one of three enums so one enum that says closed one enum that says open and one that says processing and then we if over that or maybe now we start to write the switch case so we say switch if the state is equal to open do this if it's equal to closed then do this if it's equal to processing then do this or we could even try to sort of wing it without a case statement and without the state variable so maybe we try to say something like there's the notion of closed or open that's one variable that's one bool and then there's the notion of processing or not processing and that's another Bowl but think about it that actually means that we have more states that actually means that we now have four states so let's draw one of these sort of quadrant diagrams or I'm not sure what they're called but you've probably seen these so so the combinations that we have is essentially that this variable can be true or false one of the variables let's say is open and then we have is processing and that can also be true or false so that means that we can have true true true false false true or false false so in other words this would be is open and is processing and then this would mean that it's open but it's not processing and this would mean that it's not open but it's processing and this would mean that it's not open and it's not processing and this is kind of a different thing right because suddenly we have this notion of that processing can happen when the turnstile is open or when it's not open but actually we don't even want the scenario that it's open and we're waiting for an answer so we don't want the the state that it's open and it's processing so that's actually a completely unnecessary state and now again this was with only two variables so you can probably see how if you would introduce more variables this would sort of explode clearly both of these scenarios explode in terms of complexity as you add more states or as you add more methods but not doing it using state pattern can quickly become difficult to reason about like suddenly you have to keep track of which variable combination you have to check and the really dangerous part is that you have to do this for every method so what we didn't say is that when we wrote up this if is open the dress so like we have this branching in every method when we have this checking of the current state or checking of the current variables to determine what kind of state we are currently in this logic this piece of the logic the checking the the branching has to go into every single method that we have so in all of these different methods we need to check we need to determine what's the current state that I'm in compute it and then we can determine what we need to do and again if you have many branches this can quickly become quite difficult to reason about and then I would say potentially quite dangerous because it's difficult to reason about so it's error-prone whereas if we use state pattern it's in some sense much simpler because we just devise a number of different states we give them names and then we can reason about it we say well if I'm in this state and I receive this action what's the logical thing to do what's the best thing I can do right because again we would hope that everything works but sometimes things are just messy so if we're in the processing state for example and we never receive a message back from the from the payment processor maybe then we have some kind of timeout so after some time out we automatically move from the processing stage ah sorry we didn't draw the processing state here but let's say we have a processing state we automatically move from the processing state back to the closed state because we say ok we're no longer processing we are now accepting another try from you because if we are in processing we should probably not accept more tries from the user putting their card or metro card on the reader because again that would be equivalent to how we would not do that in the open state because it just doesn't make any sense for them we're already processing something from for them so they simply have to wait so maybe then if we don't get a response back we simply do a timeout and move back to the state closed and when we're then in the state closed maybe then later suddenly we do receive a message back so maybe now the process the the the card processor instance or remote service or whatever that is manages to give us a response and says ah the payment succeeded that's actually a pretty interesting scenario because if we're using this state model without the processing where we only have closed and open then if we do receive that pay ok message then we would just say open right because we don't know that that came from a long time ago and there was a huge delay so then we were just oh it would randomly open for someone else not randomly but like it would open for no apparent reason from the outside but if we have this processing extra processing state then as soon as we've left the processing state we can say that when when the gate is closed and you receive an okay message don't open because if that happens that means that this happened for for an Iran and this reason for incorrect reason you should only open if you're in the processing state then you should move to open so so hopefully you can see how that becomes a lot easier to reason about let's actually add this processing state to make sure that we're all on the same page so let me remove this arrow that the payment okay from from closed to open that the payment okay takes us from close to open because as we've just said this should probably not happen now so let's say that we now have this processing state and again I'll write prog period to abbreviate processing and closed can take us to processing processing can take us to open but processing can also take us to closed and let's think about when these things happen so processing happens when we now we need another thing we need another action we don't just have pay okay and we have payment failed we have payment initiated so let's just call that pay so if we initiate the payment then we move from closed to processing if the payment failed let's say pay fail then we move from processing back to closed however if the payment was okay pay okay when we were in processing then we move from processing to open and those are three methods but we added one now we added pay and since we had three here before that means that we now have four so we're actually missing one and the one that we're missing is enter and then of course if you add processing try to enter what should happen well we should stay in processing enter we probably don't want to punish the user for example I mean clearly we don't want to move to open just because they're processing and payment that doesn't mean that they actually had the funds to pay for entering so we need to wait for the processing to finish but we can't just go back to closed because that wouldn't make any sense either because then we would the user for trying to push while they're waiting for a payment so we need to wait for the payment we need to stay in processing and then now I'm not modeling that but again if we had a time out maybe we would have a time out that takes us back to closed which again would then mean that if we do receive the payment okay message later when we were in closed we wouldn't actually enter because we've now removed this error from close to open and of course sorry since I removed that era we need to redraw it again so pay okay if pay okay happens when we're closed then we shouldn't actually open because the user is probably gone because we've had a timeout but also I mean now I just realized that this also means that we should maybe refund that we should maybe refund the user for this payment because we've just accepted a payment without actually opening the gate so I mean depends on your scenario you might model it differently maybe we would move from this payment okay into some kind of refund stage where we're trying to initiate a refund and so forth but anyways hopefully this feels kind of clear and then of course now that we added the state processing what we did here before is that we added processing here into this into this table of states and then since we then also added the method pay we need to add the the extra column here pay but because I'm running out of space I'm not actually going to do that but again since we changed the state diagram we now have to change the table as well so one example was that when we were in the closed state and we received the message pay okay we previously moved to open so we when we were in the closed state and we received a message pay okay we moved open but that's no longer the case because now we stay in the same place and we remain in closed but and so forth and so forth we would have to need to fill this in if it's not already clear let me just mention a tiny short example of why this is very useful so think about this light here right here we have this red light so let's say that we want this to be red when the turnstile is closed so what we're trying to avoid is users being angry and standing in front of the turnstile and pushing it even though it's closed I'm like wait for it to open or like whatever you're not and so forth or conversely maybe standing in front of it and they're assuming it's automatic or something either like well why are you not spinning something like that so maybe then this light has three states maybe it can be red it can be yellow and it can be green so it's green if it's open it's yellow if it's processing and it's red if it's closed so that's super simple in in the in using the state pattern so that just means that maybe we have another method which is get status or something like that and if we are in the close state we return red if we are in the open state we return green and if we're in the processing state we return orange or yellow sorry I'm and interestingly we talked about this thing with pay what we could actually do now is that if we wanted to we could for a short period of time move to another state or something like that maybe we could find another way but what I'm trying to point to is that maybe we would want to quickly flash red for example if the user tries to use the card to pay even though we're processing so the light is red I don't actually have a yellow or an orange pen so so blue will have to do the user puts the car down the night becomes blue to indicate that it's processing and maybe if we then place the card on the reader again it's trying to indicate to us that hold on don't do anything I'm still processing so maybe it just quickly flashes red and then goes back to blue and maybe we would do that by either introducing another state that takes us so when we're in processing we get into this other state of trying to tell the user that hey you should please stop putting your car down I'm actually processing and then we go back to processing if we're thinking about it as a simple state machine but if we think about anymore as a programmer we can actually dependency inject and so forth maybe we would do it by injecting the light to the state and then this processing state would do perform operations upon that light so we would make the light go red for a moment and then go back to blue and then again as soon as we move from processing to open the light suddenly shifts to green and then again we enter it turns closed and the light goes red and clearly as with all of these things you could of course solve that using these sort of if statements and switch statements and all stuff the only thing I'm saying is that with state pattern that's probably probably a lot easier and when I say easier I mean in terms of not getting confused about whether you have narrowed down which state you're actually in correctly or whether you have handled all of the different cases all of the different potential states and whether you have handled the state correctly and just realizing which combination of different variables of different checks equate to what state and of course the fact that we have to duplicate them I simply duplicate all of this code across all of the methods which means that if we suddenly introduced another state or another action we have to just make sure to do that check in all of the different places and if you think about it in this sense if you're then in a statically typed language that actually means that if you add another action or if you add another state then you can at compile time realize that you're lacking an implementation for a particular combination this is much more difficult of course the compiler can tell you if you're using this sort of switch logic so hopefully you're seeing the value let's now look at the definition so let's read the definition from this book design patterns elements of reusable object-oriented software by the way this book is written by what is commonly referred to as the Gang of Four so for authors and this is sort of the classic design patterns book that put the notion of not necessarily design patterns because the idea of design patterns was as far as I understand originally introduced by an architect but that took the concept of design patterns and applied it to the realm of software and essentially introduced this this massive collection of design patterns that actually still live today but I would assume that similarly to the book refactoring by Martin Fowler that part of the exercise was to put names on things that people were already doing which we can also see because in the book they give examples of real-world scenarios where the patterns are currently being used at that time I mean this is written some time ago but anyways what I wanted to say is that this is a great book if you're interested in design patterns get this book it's the classic book and as you can see by the thickness of the book there is clearly a lot more stuff than what I can to covering these videos even though we cover a lot of course not just from this book but in regards the design patterns in general but again there's a lot more stuff in this and if you want something which is a bit more pedagogical then I would suggest that you get this book headfirst design patterns this book simply doesn't just enumerate the patterns but also really goes in depth and try to explain them in easy-to-understand manners and in joke fall manners and I mean if you designed to get both I don't think you'll regret the decision great books and they do complement each other links are in the description moving on and by the way this is a playlist on design pattern so if you're not already subscribed to this channel now so super good time to subscribe to the channel but let's move on so I'll read the definition from this book design patterns elements of reusable object-oriented software the state pattern allows an object to alter its behavior when its internal state changes the object will appear to change its class so the state pattern allows an object to alter its behavior when its internal state changes the object will appear to change class so think about this we had the states here and we have behaviors hiding under these different messages that we can send it under the under these different methods and what we're saying is that whenever the state changes the internal state then the implementation the behavior of these different methods should change and in some sense then you could say that as they say the object will appear to change its class in other words if it's closed and I call pay okay it behaves in one way but if it's open and I call pay okay then it behaves in a different way so in some sense you could say that maybe that looks as if it changes its class at runtime but hopefully that sounds kind of familiar so let me remove all this stuff and let's draw up the diagram so we usually draw it something like this there is a context and this context is the thing that can have States so for us it was the turnstile so if we have the thing that can have States then we must also have States so that means that we have another thing which is called state but this state is an interface because we want to be able to have multiple different states and what we want is that we want the context to have States so the turnstile has many states but it has many different states it has the open state that has the closed state that has the processing state and again depending on your application these might be completely different but we want to be able to treat them uniformly because as we were drawing up here with the table we have all these different messages and all of the different states need to be able to answer to or need to be able to respond to all of these different messages need to need to implement all of these different methods so that means the state is an interface of which we have a number of implementations so let us call this concrete and let's just say concrete state a to denote that this is the first one and then we'll use this notation that we've been using before sort of leaves on leaves to they note that while we happen to show a single state here of course you could have multiple states and of course I'm I'm just doing this to avoid having to draw all of these separately because then they all need separate arrows so underneath here is another state class and underneath that is another state class and they don't have any relationship with each other I'm just drawing it this way to say that there are multiple concrete states that implement the interface State so up here we have concrete state a then we might have concrete state B and then we might have concrete state C but in our previous case these states might then be open closed and processing so probably you can start to see how we will replace conditionals with a polymorphism this is the polymorphic part these states are all of type state or behave as type state so the state class specifies that to be a state you need to have a method that we here because we don't actually know what we're modeling we're trying to describe the pattern generally that we here call handle and then these concrete state methods will have implementations for this handle method they would have specific implementations for this handle method but of course whoever is using this particular turnstile is not interacting directly with the states again as we were reading from the definition the definition said something like that the states are internal so what somebody would use is that they would use the context they would use the turnstile they would interact with the turnstile so here we have another mesh so here we have another method which for example we could call request and I assume the reason that people usually use a different name here than here is to emphasize that of course the interface of the context could be different than the interface of the state but oftentimes you'll probably find yourself having mapping the same interface or using the same interface in the context as in the state not as in that they would inherit from or implement the same interface but that the methods would potentially map one to one so the reason I say that is that let's transform this now from the sort of generic form to our specific form and hopefully you can see why I mean that they would probably map one to one but before we do that let me just mention that when we come across this diagram it's usually drawn with some notation kind of like this where we specify that what happens when the request method is called is that we call State DOT handle so the idea here is that you have a context and it has a state and whenever you ask it whenever you request it when have you request it to do something when you send a message to it it is not itself capable of handling that request what it will do is that it will it will pass down the message it will delegate down by calling this handle method so it will delegate down to the state and then because we don't have a general state or I should say since this is an interface the context can't have an instance of an interface but it can have is an instance of any of these concrete classes that happen to implement this interface so the context doesn't necessarily know exactly which state it has at runtime but it just delegates it just calls the handle method on that state and then this concrete state can do whatever it needs to do depending on the state that it's currently in these different concrete states will have different implementations of the method hand and now if we move to the scenario that we had before the context let me remove these texts we have context and state so the context becomes the turn style and actually I mean to make it more simple let's just call it the gate the context is the gate I mean the same thing as the turnstile I just figured that turnstile is a pretty strange word so that's the gate that can be open or closed so the context is the gate and then we had state and state we would maybe call gate state to emphasize that it's just not any old state it's a state corresponding to a gate so a gate can have a gate state and then these concrete states no longer makes any sense to just call them sort of generic concrete states we need to call them something specific so maybe this one would be the open gate state and just to emphasize I don't mean open here as in as an interjection I don't mean that as an open exclamation mark we simply mean that the state in which the gate is open the open gate state anyways and then the next one would maybe be closed gate state and then the last one would be processing gate state or maybe to be more explicit we should maybe call it processing payment gate state so I'm adding the gate here too to make it more explicit that it's an implementer of the gate state interface but maybe if that becomes messy we could just call it open state and so forth but then let's think about these methods request and handle well we had let's think about handle first let me remove these first and let me remove this sort of implementation thing here so the gate so the gate could receive a number of messages as we said the gate could receive enter it could receive pay if we think about the gate that can process and then it could receive pay okay and it could receive hey failed and those are the four different messages that we can send to a gate so if you think about the implementation that we had down here in this sort of dashed box before that implementation said that the gate essentially then agates whatever methods it receives to the gate state I mean previously we simply had requests here and handle here and the request method delegated to the handle method of but now we have four methods enter pay pay okay and pay failed and these methods somehow need to delegate down to the gate state and the elegant portion is that they simply blindly have to delegate down to the gate state because all of the logic will reside in the state because all of the logic depends on what state we are currently in of course depending on your scenario you might want to do some things here and then some things here so some things in the context and some things in the specific state but in this scenario we will assume that all of the stuff will happen in the state and what we will do is that we will simply map one to one so the enter method when the enter method is called on a gate instance that gate instance will simply delegate to the enter method of its state and when the pay method is called on a gate instance it will delegate to the pay method of its gate State so I'll just add these methods here as well so we have enter pay pay okay and pay failed and as we were saying before the interface declares the existence or the need for these methods to exist but then of course these specific concrete implementers of this interface the concrete gate states that actually implement the gate state interface they need to supply implementations for these methods which means that we repeat them here so enter hey hey okay and pay failed so it's essentially the same set of methods all over the place but an important point to remember is of course that the four methods in the gate does not have to be in the gate because the gate shares some common interface with the gate state these are completely independent completely separate while the four methods in the for example open gate state those are required because this class implements the interface gate state so because it behaves as a gate state it necessarily needs those methods the reason that we chose these the same names is simply that we want to be able to handle each combination of a method and a state separately so if so if enter from the gates perspective would delegate to the same method in the gate state as for example the pain method would then suddenly we are not able to handle all of the different combinations individually and when I say combinations think about the table that we drew before up in this end the different cells so we need to be able to handle each cell individually or we need to be able to have it separate implementation for each of the different cells so that means that enter will call enter in the gate State pay will call pay in the gate state pay okay will call pain okay in the gate state and page failed will call pay failed in the gate State and then we decide not up here in the interface but down here in any of the concrete states what the implementation should be for each of these different methods again depending on which state were in and that's really it for the UML there's nothing strange to it and of course then the gate needs to hold the reference to the gate state and then somehow we can change these states so there are a few different ways of going about how to model the changing of states and we're going to choose a way in which any particular gate state chooses which new gate state to transition to and for us to be able to do that the gate States will need to have a reference back to the gate so the gate state needs to be able to talk to the gate in order to tell the gate to change its state now if you've seen my other videos you know how I rant about avoiding mutation in this video I'm avoiding the discussion of avoiding mutation in order to keep it simple so while I'm building methods that mutate state here if you think about it you could probably devise a way where we return instead of mutate so we call a method on the gate and this method needs to return a new gate which has the new state so it delegates down to a gate state which happens to be one of these concrete gate States and instead of that gate state talking to the gate and telling the gate to change its state what it could do is that it could simply return new state right it would say well if you are in this state you would now be in this state and then it returns that state which comes back to the gate and then the gate maybe says hi okay so that's the new state that I should be in and then it wraps that in a new gate and returns that new gate but that's if you want to avoid mutation and we will skip that discussion now so instead we will say that the gate states have a reference to the gate and we will add should have done this first we will add a method to the gate which is called change state and it takes a gate state as a parameter sorry for running out of space so any of the gate states whenever they were called whenever a method or of them is called they may if they want to so they can but can choose not to change the state of the gate by calling change state and passing a new state so they would produce a new state and then pass that to the gate who would then set that as its current state so the next time we call another method we would then end up in one of these methods of that new concrete state that it produced but again there are different ways of doing this and this is one but check out the books mention for more examples and I'm sure you can find plenty of different examples on the Internet's now let's super quickly look at some example code let me remove this stuff so let's get going well we need we know that we need a class that's called the gate and let's build out all the pieces first and then we know that we need an interface which is called gate state let's open that up as well and then we know that we need implementers of the gate state let me just build one so we'll build again the open gate state so let me say and that's a class that's called open gate state and that implements the interface gate state bit crammed there gate state let me open that up and these are the three parts we need and of course again we would have more classes that would implement the gate state if we were to build the full scenario that we modeled before where if we were to build the full state machine that we drew up before the full turnstile but let's start with the gate what would the implementation for the gate be well we know that we have these four methods so we have the method enter we have the method pay we have the method pay okay and we have the method pay failed and these are all public methods that don't return anything so we'll specified void public void public void and public void and I'm realizing now the indentation got a bit messed up because I'm indenting backwards this of course should be indented within the class but I was trying to save space apologies for that hopefully you can see that this is within the class and let's say that these take no arguments none of them and then we open up the different methods and we need to write some kind of implementation for them and one of the implementations well the point is as we said before the D simply delegate so the enter method should delegate to a state that it should have we haven't written this yet but let's just draw it up what would happen is that we would say this dot state dot enter we delegate to the enter method of the state and then for pay we would say this dot state dot pay we delegate and for pay okay this dot state dot pay okay and then for the pay failed this dot state dot hey failed and so forth and so forth for all of the different methods that we need but we are now talking about this this dot state and what is this this top state so we need to define a so then let's say that there is an instance variable let me follow this indentations that are the class indentation again apologies about that so we need an instance variable of type gate state and let's call it state so it's off type gate state which is this interface over here and we call it state which is the name that we used here in these different methods when we delegated and then let's specify a constructor so we have a constructor so public gate and in that constructor we pass a gate state and this will be the initial State let's call it in a show let's open up the constructor and then in the constructor we say this dot state equals initial initial State in other words I'm gonna close the constructor so this means that when we build a gate when we in Spanish the gate this gate will be given again state and that gate state will be used as the initial state of that gate because we need to have a state right if if we just said gate state a state then the state variable would be null and we don't have a state and then we can't delegate we can't say when enter is called on the gate we can't say this not stated enter it will blow up because enter does not exist on null so we need to set it to something and we need to decide an initial state and again this varies depending on who you ask or what variation of the state pattern you're using but I decided to inject this initial gate state through the constructor so that so that we could instantiate gates with different initial states with different starting States but maybe most probably you would initialize it with you would instantiate it with the closed state so the closed gate state because probably the turnstile starts as closed and then you have to pay well I mean you could start it open doesn't matter than me one for free anyways let's now look at the interface for the gate state the interface with the gate state will contain four methods and these four methods are enter pay pay okay and pay fail but not for the reason that we've specified them here again because these are two separate hierarchies here we don't actually have a hierarchy but because the gate is a concrete class but hypothetically we couldn't have an hierarchy of here of course but states have a separate hierarchy but we've just chosen the same names to make our lives easy because we want behavior to vary on the basis of every separate action we want to be able to handle every separate action and state combination separately so let's specify that we have these methods so the interface present specifies there that there needs to be four void methods and these are called enter pay pay okay and pay failed and then we need to supply implementations oh sorry let me close this interface and then if that's the interface then we need to specify these methods in all of the concrete classes and if we are here looking at the open gate state then this class because it says or claims that it implements the interface gate state then this needs to have implementations for all of these four methods let me also just add these parenthesis show that these methods did not take any arguments so be rude enough to actually only implement one of the methods because I'm guessing that by looking at one of them you can figure out how to implement the other ones because we simply have to follow the transition diagram that we drew before but let's look at what happens if we are in the open gate state and we receive the message hey okay so here we would then have a message we would then have a function that's public and returns nothing so it's void and it's called pay okay takes no arguments so we're implementing this function and what this what this would do is that we don't need any ifs or any of that when we are here we know that a the gate is open and B we just learned that the payment was okay that's a very specific scenario right we don't have to think about okay but what if the payment is processing and it's not actually okay or what if the gate is not actually open but it's closed or any of these other things we know these two things these are two facts right this is when we are here those two things are true because otherwise we wouldn't be here and this is really the power of replacing a conditional with polymorphism when you were in that place you know a few things about reality so what we need to do is that we need to let the user in let user in I'll just add that as a comment because again that depends on what we're actually modeling and depends on your scenario but here you put the logic that describes what happens when the user moves through the turnstile but after that we also need to follow the transition diagram that we do up here before or sorry I should say the transition table that we do up here before when the payment is okay and the user has been let in what we also need to do is that we need to shift the state from open to closed so what we do is that we say and in here we now notice that we are missing a few things so we would say this dot gate referring back to an instance of this in other words referring back to the instance that has this state this dot gate don't change state and to this change state method let me open that up and break a line so I'm I'm on the same line but right a new line here and to that change state method we pass what we pass a new state which is not of type open gate state but which is of type closed gate state so we say new closed gate state and what we pass to that constructor here you can see the missing piece to that constructor we of course need to pass the gate this dolt gate closed the constructor and closed the method call and then let's close this method because that's all it does so we can now see that we're missing two pieces we said that we have a reference to a gate here in this class which we don't and we said that we have a changed state method on the gate which we don't so let's make sure that we build those two but before we add those let's add some dividers to make this a bit more clear so one here and one here right just to emphasize that these are three different things and then that let's add the missing piece here in the gate state or in one of these concrete gate States so the point was that this gate state somehow needs to have access to a gate because here we're saying this stop gate don't change state so what's this this gate well as usual dependency injection what we need is that we need to inject a gate into this class so we need a constructor here so public open gate state because that's the name of the class and then this takes something of type gate so gate do the lack of space let me just call it G I'll close the parentheses here and then open the constructor close the constructor here and then in between I'll write this dot gate equals G so our instance variable which we haven't declared yet but our instance variable called gate should be equal to this G that we were passed in which is of type gate so then it's the responsibility of the gate to pass itself into the open gate state when when it constructs it and then of course we need to declare this instance variable of type gate that's called gate so let me just duplicate this line over here so that we can create some more space so let's say class open gate state which implements the interface skate state then we open up right it's the same thing as this line here so that I can remove this line here which gives us a bit more space which means that we here can have this instance variable of type gate that we simply call gate and it doesn't have an initial value but we set this third gate immediately when we run the constructor because in order to instantiate this open gate state we need to pass it a gate so that's so that was the missing piece in the open gate state and of course let me just mention again that now we just implemented the pay okay method but of course this class needs to implement all of these four methods all of the four methods from the interface gate state so it also needs to implement enter pay and pay failed and then all that stuff we also have to do for each of the different states we have to do that also for the closed gate state and we have to do that for the payment processing gate state or whatever we decided to call that and that might sound like duplication but it's not duplication what is duplicated is essentially the method calls but in some sense that's very good because then static typing can help us or the compiler can help us to enforce whether we have indeed implementations for all of the methods or whether we don't so in other words if we would start to build the closed gate state for example and we forgot to add the method pay failed we wouldn't even be able to compile because pay failed is required by something which is of type gate state and if we try to avoid having it implement the interface gate state then we suddenly can treat that state uniformly as the other states so whenever we want to change state to that closed state then we will get a compiler error there because it's not of type gate state so we're sort of locked in in a very good way in the sense that the compiler can help us catch lots of errors and semantically it's very very easy to now reason about the different implementations because if you think about it here we have one of these sort of key methods this is the thing that we're really after like we're saying what happens if you receive the message pay okay when the gate is open and then we look at all of these different pairs what happens when we're in the when we have the state closed and we receive the message they failed and so forth and so forth so semantically it's very easy to reason about the the scenario at hand but anyways the missing gate here upon which we call change state that was one of the missing pieces the second missing piece is the fact that we here assume that gates have a method called change state which actually it doesn't so let's add that and this is going to be really crammed I'm not sure how to fit that in but let's let's do this if we move the divider here and then I'll just just do this Toto Toto both here to emphasize that when I write here it's not a continuation of these lines I simply mean that this comes after here it's just this is just I totally ran out of space but what happens here is that we need to have another method which is this method called change state so public and it's also a void method so public void and it's called change state this was really crammed change state and what are the arguments to that method well so sorry I'm continuing on another line here well the type of that argument has to be type gate state because if we're saying change state then we need to change to another gate state so it needs to be of type gate state gate state and to save space let me just call it s as short for state we close the parentheses and open this method now what does this method do well gate States those are the states that a gate can have and when we're saying change state then we want the gate to change its current state to this new state so we already have this gate state variable this variable this instance variable called state which is of type gate state so what we do is we simply say this don't state equals s and s was this gate state that was passed to the change state method and that's it for that implementation so that's that method it simply accepts a state and changes the state of this gate but that's actually not everything but because there's one thing that we're missing and that is that in these concrete States we said that whenever we create an open gate state it needs to accept a in other words the states need to have a reference to the context so the context has a state but it's dual so so when the context has a state it needs to give itself to the state so that the state can tell the context when we need to change state and again there are other ways of doing it but we're just doing we're just doing it this way now and I think you can see the point that the point is that under different state and message combinations we want to change to different states or transition to different states so in other words what I mean is that when this open gate state changes state it instantiates a new state here so and then we can see that we here actually pass this dot gate so news day it's created by this particular gate state will be fine they will have a reference to the gate but the question is the first one the first open gate state how did it receive a reference here to the gate who instantiate to that and the problem here is that we here previously made the assumption that the class gate will have an initial gate state passed into it rather than it instantiating itself so the problem here is that we can't really dependency inject the gate state the initial gate state if this initial gate state is supposed to have a reference to the thing that we are dependency injecting it to right we are instantiating a gate and the state of this gate needs to have a reference to this gate that we are instantiating so we can't create we can't build the gate State before if we are supposed to dependency inject the gate into the gate state we could if we mutate in the gate State if let's say we either say set gate on the gate on the gate state I think generally that's a pretty bad idea so try to avoid doing that but we could do that and the other alternative would be that we simply pass the gate to the gate state whenever we call one of these methods from the gate state interface so whenever we call enter pei-pei kaor pay failed we would also supply the gate so if you think about it that's actually not a crazy idea because then we can actually specify on the interface level that these methods necessarily needs a reference to a gate but then of course maybe that isn't the case for all of the gate states because maybe some of the states don't change the state and then don't actually need a reference to the gate because again the point of having a reference to the gate is that we want to be able to call change state on that gate and if we don't need to change the state then we don't need a reference to that gate and then we would simply for no good reason I have to pass in an argument to that method even though we're not using it but again I I think you can experiment with this and see that there are a lot of different ways we could do it now we'll just do it in a very simple manner instead of dependency injecting here instead of passing the gate state in that we called initial here instead of passing that in through the constructor we'll just have an empty constructor open that up and instead of saying then that this dot state is equal to this thing that we were passed in we can't do that right because we said we can't do that because it needs a reference to this instance that we are now in the process of constructing so we need to first construct the instance and then we can give this instance to the state that needs to have a reference to this gate so instead of saying that it equals this initial dependency injected state we will simply build a new state new and then let's say and then we're back into the question of what is the default state so maybe the default state then we specify here is a new closed gate state and to this closed gate state let me move this divider a bit to this closed gate state we pass this so when constructing this new closed gate state we give it a reference to ourselves we give it a reference to this gate so the gate ends up here and we set it to the instance variable which means that we can then call change State on this gate for clarity let me just add the dotted lines here to show that these are two separate pieces or this is the continuation of this class and if you've been watching my other videos you know how much I like dependency injection so I'm not super satisfied with the solution that we're instantiating the state here but feel free to experiment with the others that we alluded to and feel absolutely free to pull something in the comments if you think one of these particular solutions is better or if you find a new solution let's quickly recap before we wrap up let me mention one more thing when we inject the gate here to the open gate state that's when I really felt the feeling that maybe gates should actually have their own inheritance hierarchy so just remember the saying couple two interfaces not two classes a couple two abstractions not two implementations two abstractions not the concretions so here we are coming to a conclusion we are coupling to a concrete class but in order to stay a bit more flexible it would be very simple for us to just say that gate is actually a concrete in is actually a concretions it's actually a concrete class that implements an interface which is gate Ness which is like or something which is something that is like enterable and payable and maybe that would actually be like maybe we would actually call the interface gate but I think would make sense to just add that interface and make sure that the gate then says that it implements that interface so that here in the states we don't have to accept gates we could accept the more general type we could accept I gates or in other words the the interface for gates whatever we call that just a side note but now let's quickly recap before we wrap this up so we've got three things on the board we've got the class gate we've got the interface gate state and we've got a concrete class called open gate state which implements the interface gate state so gate is the turnstile it's the thing that we want to move through it's the thing that can have states and a gate state is the definition of what it means to be a state of what it means to be a state that gates will have that turnstiles will have and then open gate state is one example concretion you remember we had the two in the beginning and three in the end open closed and then open closed and processing and here we just have one example which is the open gate state and this again implements the interface gate state and whenever we produce a gate state we run this constructor and there is only one constructor in this constructor that's a gate so whenever you produce a gate state you need to give this gate state a reference to the gate it is a state off and again there are some slight nuances between different versions of the state pattern so you may or you may not do that but in this case we're doing that and then we assign this gate that we were passed in to an instance variable so we say this top gate equals the G that we were passed in and then this gate state has a number of methods in this blue box here a number of methods and here we're only showing one so let me just say don't don't here to emphasize it this is not just like you might have other responsibilities for this open gate state but I'm specifically trying to say that we would also implement enter pay and pay failed now we're only showing the implementation for pay okay but because it is a gate state or because it behaves as a gate state we need to implement all of these four methods and the point is then that every combination of a state and one of these messages one of these methods every combination of one state and one method one pair that makes up or can have a separate implementation so we ask ourselves what happens if we receive the message that the payment failed if the gate is closed or if the gate is processing the payment and then we have a specific location in which we can put that specific hold and that specific code is essentially here so in this particular case we were looking at the combination what happens if the gate is open and we receive the message pay okay and hope so now I realize sorry my mistake this would hold then for the first state scenario we drew when we had closed and open and you could go from close to open and from open to closed so let me just put C here to denote closed and oh here to denote open because then we were saying that if you receive that the payment is okay when it's closed you move to open sorry I forgot about this but then we made it a bit more complex and we added the processing state so if we also have the processing state then we said that well you can't open if you receive the pay okay message when you're in closed you need to first be in this processing so that the system knows that it's actually a waiting or waiting for a payment okay message it's actually waiting for the payment processor acknowledging that the payment actually went through so sorry this was a bit inconsistent so this holds in this simplified example when we go from close to open and from open to closed and of course we can stay in close then we can stay in open but sorry about that so the implementation would be different if we are also considering the processing state that we had before because then if you receive a pay okay in open gate state we would simply not change the state which then probably would equate to us doing absolutely nothing here this method would just be empty because we would say that well if you receive the pay okay message when the gate is open and we only really want that message when it's in the processing state then here we do nothing unless you are building that other architecture that we talked about before where we're trying to avoid mutation you're building that architecture where states are returning new states and gates are returning new gates then this gate would still have to return something because it can't just return nothing because then we have nothing to wrap when we get back here but then we would simply return a new instance of an open gate State so then it's really like this sort of recursing arrow so staying is also an action so it's not like we would do nothing which we do now in the mutation case but if we would try to build this sort of immutable gate then we would here simply return a new state which is also an open gate State but anyways that that's if you're trying to follow that kind of architecture but that's it for the open gate State and then again we would have a closed gate State and a processing gate State and then here over here we have the gate and the gate is again the turnstile the thing that we are actually interacting with from the outside and we can ask it enter pay pay okay and pay failed so we can try to enter it we can try to initiate the payment and probably would we would take a card here or something like that as an argument to this method I mean we're glancing over lots of details because of course we're not thinking about how this payment would actually happen but again those are details depending on your scenario so we have the pay method and we can call pay okay we can call pay fail and these are actually a bit more like event so maybe these should actually be called on payment okay and on pay failed so as in like these are things that can happen and these would probably not be called by by us from the outside when we're sort of directly interacting with the gate but probably be called by the payment processor so pay probably initiates the payment processor and then the payment processor would call either pay or Kay or pay failed whenever it receives an answer as to whether the payment was actually paid or failed or okay or failed essentially and these four methods enter pay pay or camp a failed essentially have the same quotation marks implementation because what they do is that they say this don't state the state is the state and this dot state don't some particular method and the method we call is essentially the method with the same name as the method that was called here so we call enter on the gate the gate calls enter on the state when we call pay on the gate the gate calls pay on the state and so forth so we're just blindly delegating downwards and again depending on your scenario you might have more logic here or you might have methods that don't have exactly the same name so maybe enter call something which is like open in the gate or something like this I'm just emphasizing that again this is a different hierarchy than this over here so the names could be different but in a very simple scenario it's probably one to one so one method in the gate is one method in the gate state and then we just blindly delegate uh and of course the last piece is that we have this method change state in the gate and this change staint method accepts something of type gate state we here called s so that we can take this s and put it inside the instance variable distil state so what i didn't mention before is that the constructor of this gate simply takes no arguments but sets the initial state itself so it instantiates a new closed gate state so it says well whenever you instantiate the gate it will necessarily start in the closed gate State so let me instantiate that pass myself to that gate state and then set this to this dot States I'll set it to the instance variable or I'll put it inside the instance variable of type gate State which is called gate within this gates and the gate has a reference to its own state so whenever we were saying here that we delegate enter delegated paid pay okay and pay failed that happens on the state polymorphically so the state from the context of gate is of type gate state of this general type gate state of this interface but of course we can't instantiate interfaces so on so when we say this dot state the state will happen to be any of these concrete States and we've said or we know that initially it will be the closed gate state because we manually instantiated that but what happens after that we don't know at this point and that's an effect of the implementation of these different methods in the concrete stains because they can call change state and change the state to some other state which also of course implements the interface gate state and here's the poem orphism so that the next time we call one of these methods in some sense we're not sure which one concrete state we will call them in but it will be a concrete one but again which one it is is determined by which state we were in before and that's one at least I find it helpful to think in terms of these state machine diagrams so we draw up the different states and then we draw arrows between them we say okay from every state I can receive all of any of these possible messages firstly what are my states and what are my messages and then we just draw them up we say here's my state these are the messages where do these arrows arrows take me sometimes you just stay in the same state sometimes you actually move to another state and when you then move to another state this is when we instantiate another state another gate state and pass that to the method change data so that we actually change the state of this gate that's how we're sort of traversing around in this state machine and so forth so that's all I had to say hopefully you now feel that you have some grasp of the state pattern if you have any questions or comments or want to discuss something shoot that in the comments beyond that links to both of these books are in the description remember to subscribe if you want more videos like this and if you appreciate any of these videos feel absolutely free to share them in any of your friends beyond that thank you super much for watching and I will see you in the next one
Info
Channel: Christopher Okhravi
Views: 94,970
Rating: undefined out of 5
Keywords: state pattern, state design pattern, design pattern, design patterns, elements of reusable object oriented design, head first design patterns, state machine, state machines, static typing, c#, java
Id: N12L5D78MAA
Channel Id: undefined
Length: 80min 30sec (4830 seconds)
Published: Tue Dec 19 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.