Command Pattern – Design Patterns (ep 7)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
all right welcome back it's finally time to talk about the command pattern so command pattern is one of the patterns mentioned in this book had first misaligned patterns so let's start off by just reading the definition the command pattern encapsulate a request as an object thereby letting you parameterize other objects with different requests queue or log request and support undoable operations well let's try and figure out what they mean so they're saying the command pattern encapsulate a request okay so you've got an object and somebody sends a request to that object for something or to do something and the point here is that that request right we have an object somebody sends it a request that request is what we're trying to encapsulate so we're not allowed to encapsulate the receiver the object receiving the request and we're not allowed to encapsulate the the object sending the request we're about to encapsulate the actual request going between these two turn about true but that actually sounds kind of interesting and that should resonate with the name of the pattern if you think about it the name of the pattern is command the pattern so we're about to encapsulate a command we're not about to encapsulate somebody receiving a command nor somebody sending a command but rather the actual command itself okay next portion thereby letting you parameterize other objects with different requests queue or log requests what does that mean so I think they mean that we can then take a bunch of these encapsulated commands and compose them into some kind of context so again we have we have the receiver and we have the sender and we encapsulate the command into some kind of object and if you have multiple commands as objects you can suddenly pass these objects around you can suddenly pass these commands around and I think that's what they're referring to here so they're saying we can parameterize other objects with these command will be so you can now have things that are sets of command so you can have a list of commands that you're about to execute or you can have a collection of commands that you execute when you press different buttons so this is kind of what we'll talk about later and when they talk about queue here I assume that then they mean this thing about a list so you take a bunch of commands and you put them in a list and then you invoke the commands one by one by one by one right so then you have a queue of commands that you execute or we haven't talked about composite pattern yet but with composite time you could even make like a batch command so you can have a command that contains multiple commands such that when you execute this sort of batch command or this macro command that macro command simply executes a bunch of different smaller commands so you have a mini command that's owned by a larger macro command and when you when you say execute on a macro command that macro command executes all of the smaller commands but we're getting totally ahead of ourselves the last portion of this definition was and support undoable operations so if you think about it if you have a command that does something the inverse of that command the enticing of that command is an undo right so if I say I have a command that adds one then the inverse of that has to be that the undo definition of that command is that you subtract one so if I have then a command that can't that does something and it also supports an undo which is the inverse of itself then I can very simply call the command and then undo the operation by calling undo on that command right I added one and then I subtract back and if you have a bunch of different commands that have encapsulated different actions and all of them follow this logic that they all of them have these undo operations that it's very simple to implement very complex undo operations because all of the different actions all of the different commands are responsible for undoing themselves so even if you have a queue of actions even if you have a queue of commands and you execute in series you cannot undo backwards because if you if you undo them in the opposite order of which of the order in which you executed them then you would end up at the start right so you have this a series of commands you list of commands that you're executing one by one by one by one so like let's think about math right let's say that you have something which is like okay add one at 10 at 20 at 40 etc and then you have undo versions of that right so every command has its own implementation of what it means to undo itself so then would be like subtract 40 subtract 30 I can't remember what I said about the other numbers but like the inverse of that but again we're getting super ahead of ourselves so let's stop here and let's dig into it and then let's get back to these points now if you're new to this channel or playlist I just want to say that what we're doing in this playlist is that we're walking through all of the patterns in this book headfirst design patterns one by one by one by one so if you're not already subscribed now it's a super good time to subscribe to that you won't miss the next pattern beyond that this book headfirst is a super good book if you're new to design patterns so I highly recommend that you get it if you're studying design patterns it has tons of images and silly examples and all of that so it's not just like a dictionary it actually tries to help you understand these patterns by giving you some context and rationale and like narrative so highly recommend it however if you're not new to design patterns and you're more looking for like a reference book or like fiction area of design pattern I wouldn't recommend this book instead I'd recommend this book design pattern elements of reusable object-oriented software by gang of four so this is like the de facto classic design patterns book so if nothing else this is something that's really good to put on your bookshelf for the future so you can go back and refer to this super-good I use this as a reference book but if you're like me I mean get both but now let's get into the command pattern so if you've seen my other videos you know that I've got some varying opinions about the examples from this book some of them are superb and some of them mirror and not so much the example for command pattern I actually find extremely suitable and kind of logical I mean it kind of makes sense and actually I mean I don't know when this book was written like probably more than a few years ago but I would actually say that this this example kind of becomes more and more relevant maybe the pictures are a bit outdated but the example is super relevant so what they talk about is they talk outsmart homes they talk about home automation so think about like you have Wi-Fi connected light bulbs and the Wi-Fi connected coffee machine and your thermostat is connected and like all this stuff right more and more of the appliances in your home become smart devices that you can control from your smartphone or from some other device essentially you put them all on your network and you can control them remotely either from your home via your own Wi-Fi or via the internet back to your home so they've got this example of this remote control that looks I mean completely like 1999 t-80s I know like super old right but but anyways I mean I oh let's follow the same example let's try to modernize so in my home I've got a Philips hue lights you're probably already familiar with Philips hue or some some equivalent but but it's essentially Wi-Fi connected light bulbs where I don't know if it's Wi-Fi but they're they connect to your router somehow so one of the things I've got in my home is this controller and usually it's on wall but I think if this makes a very good example so if you check this out you can see that you've got we've got four different buttons on this so we've got on them up them down and turn off the thing about this controller is that via the Philips hue app a program these different buttons to be connected to different lights let me let me just show you how it works so most of the lights are on now and I'm not sure this is going to be visible on camera but if I press off on ya it's hardly visible let me do this weight off on dim down I think you can get the point so here's the scenario slightly adapted from the book let's say you're running a company and you are tasked with building a smartphone app that users like me use to program this device in other words when I press on here I might want a different thing to happen then when you press on on your device by the way let me just mention that fits you totally awesome this is not at all the paid endorsement but if you've got the money to spend it's totally awesome that's completely out of context with this video so let's move on you can think about it this way for example so I have lots of different Philips hue bulbs in my home and some of them are live strips some of them are in different rooms some of them have colors some of them don't have color and if I buy multiple of these controllers and then put them in different rooms one way of thinking about this would be that I want the one button to turn on lights per the room that they're in turn on the lights of the room in which this particular control is in but it could also be that I have like two sections in one rooms I would want I want to have one controller for half of the room and another controller for the other half of the room or now I'm going beyond what's actually supported by this particular control but I'm just thinking like if we would design this application from scratch these kind of things would probably make sense or potentially I would want it this way I want like I have two controllers the only button of one controller controls half of the room the on button of the other controller controls the other half of the room but the also button controls turns off the lights in the whole room right that scenario also makes a lot of sense right it's like wherever you are in the room you want to be able to turn off the lights because you're leaving but they're there to physical portions and you want to be able to control them separately let's say like one in the office part and one is the leisure part or something like that so when you're building this kind of application the word dependency injection should really come to mind right because we're saying that the actions of any particular button here can't be hard-coded into this particular into the class representing this control or I should start to say invoker because this is the terminology that they're using in the book so this is being evoked it invokes command right so this invoker we can't hard cold commands on to these particular buttons because we want users to be able to design that themselves so this is what we want to have the notion of a command we want to have a set of commands right let's say one command is turn a particular light on and then you can attach a light to to an instance of that turn light on command and then you put that command on this particular location maybe another command is turn Ramon right turn all lights in Ramon and then that to that command you pass a room ID and then you attach that command to a particular button so on and so forth for these other buttons so this would be a dim up command for example and this would be like a turn off command where this turn off command main is either maybe a turn off or light in room command or turn off collection of lights or turn off light for example right we're just thinking about a bunch of different applications potentially I mean you have to try to think a bit outside the box like maybe Mike maybe my example is too simple because since the all of this is focused on lights maybe you would have a single on command on a single off command where the single own command would take an array of lights for example where is that array on the contains a single light well then it's a single light turn on a single light command and if it contains multiple lights well then it's a multiple light command that would kind of make sense architectural II but if you think about it if this controller is not only a Phillips hue controller but like a universal controller a smart home controller where I can attach lights from different manufacturers I think there's another brand called life xor lithics or something like that so you would be able to connect those lights onto this controller as well or maybe have a nest thermostat or like there may be some Semenko Wemo the on and off switches anyways like you have a bunch of other smart things in your home and you want to be able to control those with the same controller and if you think about it that way you can see that i'll like the same architecture can actually be used regardless of which thing I'm plugging in right because the one to think about it so one thing that's that's the same across all the things that we're talking about is that we want to press a button want to send the command to a particular device that does a particular and this whole notion about attaching the command to the button and then sending the command whenever you press the button that's completely the same thing across the board we construct the command we inject that command into the invoker and whenever the invoker is pressed then we send that command off or we execute sort we execute that command and that command might do something to something else in the book they call this this something else they call it a receiver so the light here that's a receiver so invoker we attach a command to the invoker and the command when it's executed actually does something to a receiver probably you can realize how massively powerful this is you can have tons of invoker's that just coupled to command any command can do anything at once to any particular receiver at once and if you're sharing interfaces with receivers maybe you could even use the same receiver for multiple commands but that's a different story so let's now actually look at some UML okay so here's what we've got we've got as we were saying before on invoker this is as discussed before this thing the remote control and the invoker has let me put zero too many command and this is an interface so let me put I here to say I command so the invoker has there too many commands but not concrete commands it couples to the interface I command the interface I command then of course has a number of implementations and these we call command and any particular command acts upon I have a receiver read and the receiver is the lamp so the invoker the control the remote control is loaded with its buttons are loaded with command I command we define it as I commands and because the I command is interface it needs to be implemented by something and it's implemented by any particular concrete command and this command could be like a turn on light command or turn on all lights in room command or set color of light command and that command acts upon some particular receiver in this case since we're talking about lights a receiver would be something like this light so when they had first book they've got another portion which is the the client which is essentially the thing using this pattern but I think this is really the main portion of the pattern so that stick to this portion and we'll talk about how to use it so let's now add the methods as well so the methods they add is that the invoker has a set command method that takes an I command server the lack of space but the set command method takes an I command as an argument the I'd command the interface command has two methods one is execute and one is uh NEX acute so remember this is what we talked about the inverse like execute does the thing and uh NEX acute undos the thing write execute perform some action and uh NEX acute unrolls that action right so it's like do an undo and actually in the book they call it undo but I just think it makes sense kind of like as in this book to actually talk about it as uh NEX acute because it's the UH NEX accusin of the execution anyways and then of course any concrete command needs to implement these two so it needs to implement execute and um execute and the receiver we completely don't know right because the receiver could be absolutely anything in our case it happens to be alive but there's no shared interface here so you can think about it as like here is like an artificial boundary where this would be the same for everything like you how you have a pattern you have a system that makes use of the command pattern so all commands follow this particular interface but any concrete command can have any particular concrete implementation and that concrete implementation can sort of cross this boundary of the generalizable all that stuff that's the same in this very specific hard-coded land where you have any particular receivers such as this particular light so in the book they just put action here just to show that the execute method of the command would probably invoke a method which performs some action on the receiver but this completely depends on your scenario so maybe here we would have our receiver would be a light that has a on and off method for example and this is really this is the gist of the pattern so let's walk through how this works so you construct a bunch of concrete commands let's say turn on light and the turn off light these two have methods that are execute and uh NEX acute so execute of turn on the light would probably be the call on on a particular light execute on the turn off light would probably be turn off on the particular light and uh NEX acute of turn on would probably be turn off an unexcused probably be turn on so remember the direction of this arrow we're saying that the invoker has many eye commands any particular eye command is a command and any particular command can act upon a receiver so by proxy right if you unroll the statement this means that the invoker acts on receivers right at the end go we have this thing and we want this thing to act upon these things but because we want to do it in a general manner we just don't we don't want to hard-code we don't want to say that when I press this button find this particular lamp and turn it on right we want to do it by proxy we want to say that this invoker is loaded with a bunch of different commands we refer to them as I commands the type is I command so we load any of these buttons with any particular concrete implementation of an I command and that concrete implementation is a command which follow the interface of I command and whenever that command is executed it performs some particular action on some particular receiver which is completely specific to that plant probably you can now also see how undo comes into play so you have if any command has an unexcused that means that the invoker if it keeps track of its commands then it can actually unex acute a whole series of commands so this kind of makes no sense in this particular use case but let's say that we would load one of these buttons as a undo button that unrolls every action it means like let's say for 24 hours I keep track of every command that's run and when I press the undo button I sort of unroll all of those commands in sequence again like that doesn't make any sense but in this particular scenario we'll talk about it scenario where it makes sense later on but that would mean that I sort of play back a sequence of commands in the reverse order and with their inverse of their actions so the opposite of their action so if I had a turn on command it will act as a turn off command because unex acute of own is to turn off but before we talk more about undo let's first super shortly look at some code so I won't drop the whole thing but I want to draw two key portions two key pieces let's let's look at a particular command and it's corresponding interface I command and let's look at the invoker so what would the interface I command look like so let's start on that end so I command would be an interface called I command and the only thing it specifies is that it says I have two methods both return void because they perform actions if you think about command query separation they are commands they are not queries but that's a totally different discussion they return void the first one is called execute and the second one is called uh NEX acute and they take no arguments importantly because the command has itself encapsulated all of the things that need to perform its duties the command is going back to this idea that we talked about before is encapsulated right there's an action encapsulated in a command the command doesn't require you to pass anything to it when it wants to be executed you've already passed all of its dependencies to it upon instantiation so the command so the command already has access to the receiver that it needs to have access to in this particular case the light cells I command let's now look at any particular command so let's say that we're building the command for this right so then we would have a class called command that implements the interface I command so I'm probably going to run short on space here but what we need is that we need a constructor so public command and as I'm saying before this command needs to immediately get to know about what the dependence is it needs to perform its job so this command needs access to the light immediately so in the constructor we pass a light to save space let me just call it L so we pass the light and then we store that internally so we say this dot light equals the L that we passed in and then here okay sorry about the space we have a light so there's an instance variable called light so we save away this light that's passed in into the instance variable which we do here that's the constructor then then what then we have a method called execute so it's a public method public void method called execute takes no arguments because it's following this particular interface and what it does is that it acts upon the light it acts upon its receiver and let's pretend that this light this receiver has an only method so then we would say this dot line dot own simply that's it it's not complex that's not the point it's not a it's not that we're wrapping a complex action it could be exactly this simple the point is not that we're encapsulating something that complex the point is that we're encapsulating something that's potentially trivial so that we can pass it around if you think about functional programming functions are first class citizens so it's trivial to take some procedure and wrap that in a function and then pass that function around command pattern kind of gives us this flexibility in object-oriented programming so we ramp some action that we want to be able to perform which is actually just this this dot light dot all right light up on we have any particular instance of an item you know to call on so you wrap that into a class and then appoint if you instantiate that class then you can certainly pass around this object you can suddenly pass it around as if it was a function contained in a variable and as the execute method then we would have uh necks acute which is essentially the inverse of this so we would have public void uh necks acute and we would say the implementation would be that we would say this dot light dot off for example for this particular command but I'll just put dot here because I think you can figure that out and then we'll close the class and actually of course I call this command but probably the name here should have been light on command because then we would have another command which is light off command which has the inverse of this so the light off command upon execute would say the spotlight off off and upon uh NEX acute would say this dot light dot own so that's the light command that's actually add the life here so we'll say light on command and it's a class sorry about the mess and that's that so that's the concrete command and key point we might have multiple concrete commands we might also not have multiple concrete plans again we might do this even if we have a single concrete command just so that we were able to sort of batch the execution of this command and this is why in the book they were talking about queues for example like you might construct commands and put the commands in a queue so that you can execute them one by one or in batches right like let's say this was an expensive operation you want to batch them so you want to say I have a series of commands and every 30 seconds I execute ten of them right so like you throttle even if you are pushing more commands into the queue you're sort of only taking ten at a time every 30 seconds or something like that lastly let's look at the invoker so what would be invoker look like so the invoker is a class and what it does is that it somehow keeps track of commands remember now that this is not necessarily a part of be of the pattern actually we could probably extend this line and say that this stuff this is really the key portion of this pattern which might look a lot like strategy pattern which might make you wonder what what's actually the difference between this and strategy pattern and I would guess that probably the only difference is really intent like here we're treating the strategies as commands but if you have more questions about that please raise that of the question and I will dig into that some other time so in other words the invoker just like the receiver is specific to the scenario in which you're operating it's specific to your context here we have lights that were receivers right and invoker for us was listing but the invoker in your scenario could be any particular thing so actually even in your scenario you might have multiple invoker's that have multiple different interfaces so like if you have this invoker and you'd have this invoker and then they have completely different interfaces and in regards to this pattern they don't necessarily need to share an ancestor these can be concrete classes that don't share a common ancestor they can be different classes with different interfaces because in regards to command pattern the only thing that they need to do is that they need to support the adding of I command of course depending on your scenario it might make sense to share a common ancestor between these so that you could share these so you could treat them the same way but again that that completely depends on your scenario if you just think about it I mean this control has four buttons and actually like semantically it's like these buttons have some kind of meaning so like from the users perspective you'd expect that these different buttons behave in sort of different ways and this control has 1 2 3 4 5 6 7 buttons so this one necessarily needs seven commands to function properly unless we're sort of loading one with a no command command this one necessarily needs four commands to operate sensibly again unless we load one of the buttons with a no command command and and this particular control if you would try to load it with more than four commands that wouldn't really make any sense similarly for this one if you go beyond what what it supports so like they're actually completely different things that we want to interact with in completely different ways but the key point is that the notion of a command we make the same so we load these things with commands and then the commands can be shared across these different invoker's even though the invoker's have completed different interfaces hopefully now you can actually see that that makes a lot of sense because I mean it would be kind of sweet if this would also function as you're a home automation control and this would function as your home automation controls and you could use the same software in your phone to program both of these devices or a multitude of other devices again command pattern is actually massively powerful so back here this is why we're saying that the invoker is a class and not because so far we haven't really had a need to make the invoker an interface it's not something that needs to be shared so let's say that the invoker concretely is this particular device and we have four buttons and I would actually rather than put these commands in a list I would probably make these separate I would probably say that this is the on button off button dim up and dim down right so let's add those instance variables so like we have an eye command and actually let me just use a shorter name I command own and we have I command off and we have I command let me just say up and I command down and these are instance variables so I should have expressed this in the same order as the buttons on this device for simplicity but we now express them this way so we have the instance variable own which represents the on the bottom the instance variable off which are presenting off the bottom and the instance variable up which represents the dim upper button and the instance variable down which represents the beaming down button and as you probably noticed the type of these instance variables is I command super importantly they the claims I command because these represent what we want to do whenever that button is pressed so in the book they use this set command method so the invoker class has the set command method which takes a command and then puts it in one of these places I actually think that that's a really bad idea from this perspective if you can avoid mutation always try to avoid mutation I see no reason yet for why the invoker should have to have a set command method I would rather pass the commands through the constructor the invoker necessarily needs four commands so an invoker with three commands doesn't make any sense in our case so the invoker should be instantiated an opponent initiation we pass it four commands now of course I mean you could argue that when you're building a cube for example you would probably want set command because then you have your invoker is add the two cube right you add the command to the cube and then you actually need to mutate the cube unless you have a queue that when you say add you get a new tube back which contains all of the old commands plus the new command but this is a long and completely different story and if you're interested in that discussion I would recommend you to check out Gary Bernards pork boundaries but that has nothing to do with what we're doing here but the point here is that we can avoid the mutation we can avoid changing the contents of the invoker as the program is running we could rather just create new in focus whenever we need an invoker which I would argue makes more sense which is why we remove the step commander method and instead we just say that the invoker needs to have a constructor so let's say public invoker I'm just going to use two lines here and it will take four arguments it will take all of these four as arguments so we'll take in order to save space let me just not express the types here but it would take an on and off an up and a down I'm not expressing the types that this should say I command on I command off I command up I command down so the invoker takes one of each of these different commands that it means and then the implementation of this method is simply that we say this dot on equals the on that I was passed this dot off equals the off that I was passed and so forth four up and four down and then we close the constructor so whenever we instantiate the invoker it now has access to in this instance variable a command that represents the own action so whenever we say new that actually does a new invoker we pass it a bunch of commands and for the on button we probably want an own command like a light on command so let's then we would say we would use this one the light on twenty it's a new invoker and then we pass a new light on command and to that we would have to pass the light this light and now we don't have that but let's assume that we have a light called a light with a lowercase L in in the scope where we're at when we're calling this particular when we're executing this particular line then close that so the new light on command gets passed a light because in order to be a proper command this command is light only command needs to have access to a light that is operating on it that light is a receiver so we're passing that light to the light on command and then taking that like own command and we're passing it to the invoker to the invoker as its first argument because its first argument is the own command so then when the invoker will call execute code execute on the own command we will execute the light run command which we'll call own on the receiver which will turn the light on so again by proxy the invoker has the capability of turning this light on and then of course up here in when we instantiate the invoker we would have to pass the next command and the next command and the next command one two three four which is on off up and down and then we can close that because then you have a complete invoker now we haven't constructed commands for often up and down but I think you can see sort of how we would do that but again that's that's also the point of moving this set command removing this set command method and making it part of the constructor instead because that means that it's now impossible to create an info core which doesn't have all the commands it needs so I know to finish this invoker code let me just remove this the interface code because I think you can remember it nor you can see it here I mean this is this code just represents this interface so let's remove that and then let's think about this what is missing here well of course the invoker needs to be able to actually have a button that are pressed so probably it needs an OL method public void and to be super explicit unto to make sure that we don't confuse these with the instance variables but let's call them click on and click off right so if we click on that would be a method that takes no argument have some implementation and we have another method called that's also a public method returning void and it is called click off should probably a call this pressed but whatever and then what's the implementation here and what's the implementation here and etc because now we just created the two methods click on and click off but we also need to have click up and click down but click on super simple would essentially just say this don't own dog execute in other words in this instance variable own we have stored a command in our example here we have to store the new light on command which has passed the light so whenever we call execute on this particular own command we will do whatever is in this execute method of that right one command in in our case it happened to be that the body-aline method says that we will do this dot light dot own in other words that the light one command calls the method own on the light that it has in its scope and that light happened to be this light and that's all for free click on and then the same thing we do for click off we would say this dot off dot execute and exactly the same thing happen happens but instead of that we call execute on the on command we now call execute on the off command so we also have an instance variable which is called off in our scope and that off command we then call execute on that off command which would be this command that we passed here but we haven't actually specify what this command is but that would be the second argument that we've passed to be invoked because the second argument of the constructor was the off command that's the thing that we here saves off into the instance variable called off so we would then call execute on that and again that would mean that we call execute on that particular command which then would act upon some particular receiver by for example calling some particular action so if we imagine it would be a light of command and we would also pass a light and we would pass this light then the action would probably be to call off on this particular light and that's it now just keep on going like this we just keep on creating in Volkers and stacking commands and a key point is that of course at runtime you can vary in these commands so if you're building an application if you're actually building the app then users use to say that when I press this particular button I want this particular series of commands to be executed you can then give the user a bunch of different commands and then let the user choose which commands should be coupled to which button or which commands should be put on to which button so that when the user presses that button you actually execute that command and then two-point-one undoing becomes super easy because every command now has a nun execute method and two you can now construct macro commands you can now have commands that contain multiple commands so if the command when you call execute if it doesn't immediately act and receivers but rather it has multiple commands that it calls execute upon then that command would be like a macro command that can do multiple things and this is one way in which you could implement the whole notion about turning on or off multiple lights instead of a single light but before we wrap up let's talk about this whole undo notion so this really clicked for me when I started to think about Photoshop think about the the image editing application Photoshop in Photoshop you have a long series of undo history so you can actually go you can roll backwards a super long way and if you just think about how you would build that programmatically we probably not to be super easy but if you think about it this way what if every action that you perform upon your picture every action that you perform upon your document is a command but if everything is a command and when if all of these commands are rolled back up all right what if all of these commands have execute and uh necks acute what if you can do the commands and then you can undo the command and one if you then just stack all of the commands that the user performs to to a document into a list and then whenever a user wants to undo you just do unex acute on the last command and pop it off the list or if you if you don't pop it off the list you would just call execute again to read right so you say unto you uh next acute the last command and then undo again you uh NEX acute the command after that you undo again you aren't executed command after that then you renew then you execute that that last command that was unexcused and so for that you can go back and forth in history kind of trivially I'm not saying at all it would be trivial to build Photoshop because the the more difficult parts is of course to figure out what would actually happen in that execution but the whole notion about doing and undoing would then be kind of trivial and I would actually say that this is kind of an elegant way of structuring your programs so instead of just performing some action you wrap the action that you want to perform in some particular command and you make sure that that particular action is undoable so this was the command pattern I hope that helps please make sure to ask in the comments if you have any sort of questions or comments or just share your thoughts and ideas if you have something to share be massively appreciated beyond that again if you're new to design patterns get this book and if you want a reference book for design patterns instead get this book Daniel for super classic book both links are in the description thank you super much for watching remember to subscribe and I'll see you in the next one
Info
Channel: Christopher Okhravi
Views: 172,740
Rating: 4.9391842 out of 5
Keywords: command pattern, command design pattern, design pattern, design patterns, head first, head first design patterns, head first: design patterns, christopher, chrokh
Id: 9qA5kw8dcSU
Channel Id: undefined
Length: 39min 12sec (2352 seconds)
Published: Fri Jul 14 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.