Strategy Pattern – Design Patterns (ep 1)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome to the series on design patterns in this series we're going to talk about the design patterns in this book head the first design patterns one by one so at least we're going to look at thirteen patterns before we get started if you're getting started with the design patterns I highly recommend this book if you already know a lot about design patterns and you're looking for maybe a reference book this is not really it this is more of a very talking Illustrated super pedagogical book for learning design patterns right it's there's tons of super silly jokes in this book so if you're just looking for the definitions and the UML diagrams like that don't get this book but if you want to learn design patterns and the rationale behind them get this book check the description but so let's get into it pattern number one strategy pattern strategy pattern is a super sensible way to start if you're just learning design patterns it's actually probably the simplest pattern if I were to think of it in only a few words I would say that it's about using composition rather than inheritance it's about understanding that inheritance is not intended for code reuse but let's check out the official definition from this book so they're saying the strategy pattern defines a family of algorithms encapsulate s' each one and makes them interchangeable strategy let's the algorithm vary independently from clients that use it at all so let's think about this strategy pattern defines a family of algorithms okay when you're using strategy pattern you have a family of algorithms yeah set of algorithms that you want to use it encapsulates each one of them and makes them interchangeable okay so you have this bunch of algorithms and each of them are interchangeable right so you have algorithm a you have algorithm B you have algorithm C and there they're claiming that the strategy pattern you can plug and play you can sometimes use algorithm a sometimes use algorithm B sometimes use algorithm C and so forth and then the second line I guess it's more like the rationale right then they're saying strategy let's the algorithm vary independently from the clients that use it so think about the word decoupling we've decoupled the algorithm from the one using the algorithm so we said that we can vary between algorithm a and algorithm B and algorithm C for example so whoever is using algorithm a or algorithm B your algorithm C that thing will usually refer to these things as clients in this book that client does not have to vary if one of the algorithms varies in other words when we say vary we mean if you want to change one of the algorithms the contents of the algorithms what the algorithm actually does then you don't necessarily have to change the client at the same time so whoever is using that algorithm is not forced to change when you are changing at one of the algorithms and that's super good this will make more sense in the end but if you think about an implementation of a collection for example an implementation of a list if the list had a sorting algorithm built into it you can never change the sorting algorithm but if you using strategy pattern inject a sorting strategy then the sorting strategy can vary independently from the list so you have the implementation of the list and that's stable but then you inject different sorting algorithms but that's far beyond let's now get into this so generally in this series I'll make heavy use of the examples from this book but I won't just give them one to one I'm slightly adapting them because I think some of them are just overly complicated and I'll try to go a bit faster but here's the gist of their example so in the example there's a duck class the duck class is a superclass so the intention is that other classes should inherit from the duck class so they have something like a mallard duck and some other duck and that's just confusing because I don't even know what a mallard duck is and I don't think it's relevant example so let's just say that we have a wild duck and a city duck so wild duck would be a duck out in the forest or wherever ducks hang out and a city duck would be a duck in the city now that hangs out in the palms in the city makes no sense but it doesn't really matter the point is that we have two types of ducks and notice how I make use of this kind of arrow and this kind of arrow so in in UML this is is a-- and and this is has a-- so composition is this one inheritance is this one so in other words a wild duck is a duck ah city duck is a duck so this would mean that a duck has a wild duck right this would mean that a wild duck has a duck but now we're saying a wild duck is a duck because of this movie so the point in the example is that the sub classing ducks the subclasses are responsible for implementing their own version of the display method so while duck has its own display method city duck has its own display method and thus wild ducks can be displayed differently than city ducks and so forth if we would add another class this would have its own another duck type this would have its own display method so that could be displayed in a manner appropriate for that duck and then of course the kwok method the behavior of quark is shared amongst all of these subclasses and this is how they're using inheritance for code reviews now this seems fine and dandy right what's the problem the problem is of course that has oftentimes when we talk about design patterns it's change its that chain when requirements change when our system will have to change over time our current design may not necessarily be appropriate for the income requirements the example that they take is that let's say that we have another method which is fly right so ducks fly which makes sense because ducks do fly thus we've suddenly given city duck the ability to fly and we've given wild duck the ability to fly this example is of course completely fixtures then kind of silly but then they're saying that okay then some new requirements come in and they somebody some programmer forgets that they're doing this and we have another subclass which is a rubber duck sort rubber duck is a fake duck right you know these yellow plastic ducks rubber plants whatever it's a fake duck it's one of these yellow ducks and rubber dog has its own display method but the argument is that or the problem is that they're saying it well rubber ducks shouldn't be flying okay so so rubber ducks shouldn't be flying so that means we can't just blindly inherit that behavior so what if we then now I'm sort of trading off from where they're going but I think we're going to serve the same place so what if then we're saying that let's implement fly as well here let's implement fly here so we have some rubber duck has its own behavior and that behavior is essentially nothing right it's non flying so you could argue that not being able to fly is a kind of flying behavior we'll get more into that and this too actually works fine but you can maybe start to get this feeling that we're sort of heading down a slippery slope so let's say that we have another duck I'll just make up silly name so you know never mind the name is just thing we had lots of ducks so let's say that we have a mountain duck right names make no sense whatever and the mountain duck of course can be displayed but the point here is that that this duck also wants to have its own flying behavior so we override fly here but let's say that this flying behavior isn't necessarily not being able to fly let's say that it is a flying behavior but it's just some kind of different flying behavior and then let's say say that we have another duck so it's a cloud duck it's it it's another duck that has its own flying behavior but what's interesting is that this duck has this guy's flying behavior these two Ducks have the same flying behavior so we here also override and implement the fly behavior but because this fly behavior is the base class fly behavior right that's different from these two these two have their own right so the code here the copy in this fly game actually is the same as this one 100% duplicated we just go copy paste so these have the same and then you could start to say okay well I need another class I need another flying like flying with style a and both of these inherit from flying with stylette but hopefully you're feeling that now really treading down a dangerous path right because yes okay that works for fly I'm running out of space here but what if we also have eat for example right so we have an eat method and this duck has a base classes eat method but this duck has its own eat method and then there's another duck let's say the rubber duck has the same eat method as the mountain duck you can start to feel however sort of it's getting kind of crazy so like let's let's try and draw this it works as long as the behavior is shared downwards so this is an inheritance hierarchy right as soon as you want to show me havior horizontally here there is no way unless you get into multiple inheritance but like I think Sammy met says it nicely when she says that the solution to problems with inheritance is not more inheritance but that's a topic for another discussion but I think this and now by analogy kind of makes sense you choose of course there are many ways of building these hierarchies there are many ways of building up this inheritance chain but essentially the point is that no matter how you do it there are some scenarios where you can't build it hierarchically because you will end up in a situation where some behavior here also once we wants to be used here so you either have to duplicate code or find another solution by the way Sandi Metz has a really great talk on amongst other things the null object pattern where she talks a bit about this I'll link that in the description it's super valuable and that gives more insight into why composition should often be favored over inheritance but let's move on I think you're seeing the problem so let me get rid of this stuff and let's just directly jump into the solution never mind all of those intermediate steps so what I'll do is that I'll remove everything and just keep the wild duck and a city duck but please generalize in your head and remember that there could be more ducks so the point with strategy let's think about the definition again the strategy pattern defines a family of algorithms encapsulate each one and makes them interchangeable strategy let's the algorithm vary independently from the clients that use it that's exactly our problem here we have an algorithm fork working we have an algorithm for flying and what we're realizing is that we can't create a hierarchical solution in order to share code between these different uses of the different algorithms so we have to extract the algorithms and say that these are clients right a duck is a client a city wild duck is a client a sticky duck is a client was that air duck cloud dark cloud duck is a client and they make use of different algorithms for flying and fork walking and these must be able to vary independently from from other aspects of the clients so what do we do well we say that ok or create strategies for quacking and strategies for flying so we'll create an interface i kwok behavior and what it does is that it says you need to have a kwok method and there are many ways of solving this that would still adhere to the strategy pattern but this is one way of approaching it and then we do the same for flying so I fly behavior the interface are flying i kwok behavior the interface for quacking sorry we need to have my method yourself and you'll probably see later that we could probably generalize so I'm not going to do that in this video but you could probably generalize as well as that instead of making these two separate interfaces you could probably make them to say one same one so you could have maybe a duck behavior and this would be something more generic such as executes but just bear that in mind as we go forward so notice that we're making use of has a rather than isn't so that means that every duck must have a quack behavior and every duck must have a fly behavior what are them flag behaviors ok let's start to think about them as algorithms previously we said that wild ducks and sticky ducks they have the same quoc behavior and they have the same fly behavior so these are the same here in terms of flying and in terms of quacking and previously we achieve that through inheritance but now we're saying okay if this is an interface an interface for quacking and every duck has a quat behavior has a concrete quoc behavior at remember this is an interface so it's not instantiate able so something needs to implement again this is inherits or implements in terms of an interface some kind of quoc behavior and if these previously were in the base class let's call them something like simple or default all right so that's a simple simple walk I should probably put simple quack behavior to increase semantics and make it easier for other developers and to indicate to them that we're making use of something like strategy pattern we want to be super clear look at the name is something like simple quacks strategy and this would be quark strategy for example these are naming discussions but never underestimate the power of naming your things in a way that makes it understandable for your code developers never underestimate so let's say that we have a simple quote behavior that that implements the interface I I quote behavior and then let's say that this quantum ESSID previously had an implementation we had implementation of quark in here let's now say that instead one of the method delegates to the quark behavior that this duck the instance of the duck happens to have so if this particular duck happens to have a simple kwok behavior then when we call Kwok we will run whatever is in here sorry of course this should be walk so we run the contents of this method if we've composed an instance if we create an instance of a duck that has the simple kwok behavior this is possible because this Kwok man this duck has an IKE walk behavior or I mean we could trivially we could of course do this it has a simple Kwok behavior but that's this is significantly less flexible this creates class explosions so what we're doing is that we're saying that all we need to know is that it has something which is quotable why because remember we have the rubber duck the rubber duck had no quacking behavior so then we simply implement another concrete class a no Kwok behavior that also of course implements the interface I quark behavior so we have now no Kwok behaviors and we have simple Kwok behaviors and suddenly we can take these two different algorithms these two different strategies these two in this case different behaviors and put them in places and use them to compose new things that behave differently depending on which one they have so a duck can now we can now say that the duck class it doesn't need to care about quacking its subclasses that doesn't need to don't need to care about quacking the duck class only needs to ensure that whenever it is an instance it has a Kwok behavior if it happens to have an O Kwok behavior it won't go on if it happens to have a simple walk behavior it will quacks simply whatever that simple quacking means and then we do exactly the same thing for fly behavior so we say let's let's use the same terminology let's say that we have simple fly behavior here as well so we have simple flying as a method fly and implements the interface flag behavior so those two other ducks that we talked about before the Mountain duck and the was that the cloud the duck silly name sorry the mounted like the clown duck these two if I remember correctly wasn't it so that we said they share the same flying behavior but the flying behavior that they share that flying behavior that both of them share is not the same as the flying behavior that we previously had in the base class which is now the simple flying behavior here because we've moved we've done exactly the same thing with fly that we did with kwok we said that okay actually ducks any duck must have a concrete fly behavior it has anything that is that implements I fly behavior right it must have a concrete fly behavior but instead of saying that we it has a concrete flying behavior any particular one we're saying anything that has that implements the interface fly behavior will suffice just as we move the logic here away from the quack behavior away from the kwok method into concrete quark behaviors here and here right in the same way and we did that have we taken a fly behavior we've taken a fly behavior from here and moved it into here which now means that in our previous example where we had the mountain duck and the cloud duck that both shared a fly behavior that was different from this particular fly behavior we can now trivially solve that problem by introducing another fly behavior that is I don't know what their fly behavior would be called but let's jet fly behavior right so so jet fly behavior ah again semantics link that's at least named them according to the same convention so jet flying I have some engine supported flying whatever and it has the fly method so again the names are silly but I think you can see sort of how we're stringing together the pieces so let's let's draw the same thing again so here the code that's in here is not what was previously in here but what was previously in when we had let's let's reintroduce let's say that we had the cloud duck we have the cloud duck before so there we had a fly method there we had a fly method and it had some logic and we've taken that logic and we've moved it here into the jet flying behavior and into the fly method of a jet flying class and sorry I forgot to draw this arrow we should of course had a jet flying implements fly behavior so simple flying implements fly behavior and jet flying implements fly behavior and a duck has a fly behavior which means that a duck can have jet flying behavior or it can have simple flying behavior if you start to think about this I've talked about this is in a previous video I really think that this is one of those four critical moments where you start to realize that we need inheritance much much less than some people make us believe it's I think very common to sort of go through schooling or or go through a common object-oriented examples and then think that inheritance is very very powerful and that it applies to very many scenarios but actually in this case where we have a very flexible system looking at these parts and we suddenly realize that we don't actually need these middle parts assuming of course that displaying would be the same in this in this in this example that they have I actually think the display the point is the display method is different so what we could do is of course we can do the same thing for display we could inject the display behavior or we could we could extract the display behavior to an interface and then saying that a duck has a display behavior let's actually do it just for the sake of X before the air for the sake of the example but let me just first remove this so we want to get rid of this display behavior and this display behavior so we do exactly the same thing I don't even know what this is what they do in the book but I mean it makes perfect sense and it's that strategy pattern so just hang high display actually I just realized that I was super inconsistent with the naming I mean the interface is our neighbor mmm-hmm behavior but on this side we've got simple quark and a simple quacking and here we've got simple flying and not simple fly so that was totally inconsistent apologies in order to save your time I won't change that but I would never check in I would never commit source code like this I would absolutely change it so that the naming is consistent to another developer this is super confusing right it would indicate if I would read code that was written like this I would it would indicate to me that this is a completely different concept that this concept because the grammar is different but the words are suffix differently so I would think that they are they're different concepts but yeah in order to save our time let's just now you know let's move on so let's say that we have an I display I display behavior so I display behavior same thing we have a display method display and now we can then say that okay if the city ducks display strategy is different from the display strategy of the wild duck then we at least need two concrete classes so now since we don't know what what these would be right I mean if if we I would if we would now end up in a scenario where we would say that okay I want the most sensible thing I can think of to name the display behavior would be city duck display and while the duck display then I mean then there's probably zero need for strategy pattern because as the name implies there is zero reuse in that code there is there's no intention of reusing that is display behavior for city ducks because we've renamed its safety duck display behavior but for the sake of the example and just to sort of show you this in absurdum let's say that we are intending some reuse of the display behavior so let's say that this would be I mean I am very hard time coming up with examples for well what the different display behaviors would be but let's just do something silly so let's say that this would be display graphically that's one display behavior and the other display behavior as you might guess is display just say as a string or as text as tanks so we have this place text behavior and we have displayed graphically behavior behind again naming I'm so sloppy so maybe this should be display as graphics and displays text and both these of course implement the eye display so a display display as graphics is an I display behavior and display as text is an I display behavior or rather they both implement I display behavior what does this mean okay if you start to now look at what we have that means that our specific overriding are are are the thing that was previously city ducks were responsible for displaying they were responsible for that's the only logic they're adding they are by definition because of inheritance they are ducks so they get all all the stuff that ducks have but they were saying that actually city ducks have special displaying behavior and that displaying behavior we put here but let's say that that displaying behavior most displays graphics and I'm trying to see the digger example makes no sense but I mean bear with me so assume that what does what was special about that once that we wanted to display its graphics if we now have the I display behavior and we say that the duck has an I display behavior so that's that's this is getting messy let's just reiterate the duck has a quack behavior a doc hasn't display behavior a duck has a flying behavior but that's on abstract level that's on a class level and then when you create instances you need to make sure that that duck has something that implements these three different interfaces so that could be a duck that has a simple quark behavior and a jet flying behavior or it could be a duck that has an O quark behavior and a jet flying behavior so if it had a simple flying behavior and it had no quack behavior I was going to say that that would have been the the rubber duck but maybe it wasn't bad maybe it was that the rubber duck couldn't fly but could quacks oh I've messed that up but I think you see what I'm saying by creating these classes you can create another one no flying behavior fly does nothing this one also implements the fly behavior which means that we can now have no flying behavior which means that we gotta duck there's no fly we a turn no quark behavior that would definitely be a rubber duck but back to the display behaviors so if the doc now also has display behaviors we have the display method here suddenly now the display method makes use of a display behavior so when we call the display method we invoke the display method in whichever display method which are a concrete display meant that we happen to have and we can do that because we know that we have something that is and I display behavior let me just as parenthesis also say that it seems like with this example that I'm somehow arguing that interfaces would be more appropriate than the subclass this whole thing with the behaviors could of course have be done using sub classing we could have said that I quad behavior is a class and so you can give ducks the kwok behavior but you can also give it something that inherits from the quark behavior entirely possible and but that mainly depends on your scenario and again as soon as you get into inheritance you you can have this problem that we started with so it's kind of interesting but I mean the problem that we started with could be exhibited within a single behavior hierarchy so you start to introduce quark behaviors and then you experience the same problem that we had in the beginning the same problem of wanting to reuse code horizontally within the behaviors so then maybe you would have strategies that make use of strategies so you know you can dig far into this but everything of course entirely depends on the requirements in your scenario that's more let's finish up this thing with the display behaviors where I wanted to go regarding introducing display behavior as well as a strategy right again remember these are strategies we call them behaviors but they are strategies in the strategy pattern sense for the there are abstract strategies whereas these are concrete these are concrete strategies now that we have these we realize that even displaying in these ducts is completely unnecessary there's no need to override display in these subclasses because we can simply give a duck a particular display behavior and thus compose a duck that behaves as a city duck so actually we remove these now and suddenly there's no need for any sunglasses we have cloud ducks and mouse ducks and the city ducks and wild ducks and rubber duck and all these ducks right now suddenly these are no longer named classes in the system they are a particular configuration of instances of behaviors so given a combination of different strategies given a combination of different algorithms we happen to call some of these combinations different things so if it flies in a particular when it quacks in a particular way and it's displayed in a particular way that we call that a wild duck if it flies in the same way and the quarks in a different way we call it some other documents so forth and so forth what I haven't talked about I sort of glanced over this is dependency injection right that is only possible if these behaviors are somehow injected into an instance of a duck and not hard-coded in the class if if the class actually hard holds these things then we can't do that anymore so let's just very very quickly look at what that would look like let me remove all of this stuff and we'll look at some cold very very very quickly okay sort of pseudo coding yeah a class it's called a duck as we sent this duck has fly behavior quat behavior and display behavior so let's let's make these members by the way I put eyes in the beginning just to denote that their interface is by convention it has no other meaning so we put these as properties in the class and I could of course say that this member equals a new some particular fly behavior but if I did that it wouldn't be as flexible we need to somehow inject the behavior right this would hard-code the dependency and put me back in a state where i need multiple classes to represent all of these different types of ducks and it's just think about it it's significantly less impossible so instead let me just say that i have that member and the key here is if we use constructor injection we look at the constructor so we say we constructor public duck and it takes some arguments the question is what arguments well we need a flying behavior we need a quant behavior and we need a display behavior so let's just take those so well take something off time fly behavior and let me just call it FB to save space and we'll take a quack behavior and again just QB to save space and a display behavior calling it DB and that's it that's the constructor the signature of the constructor so let's open this up and we'll close it here and what are the contents of the constructor right in the constructor we set these all those extremely silly I forgot the variable names here I'm sorry so just to save space again that's the same thing that's say that the flying behavior is called FB the coop behavior is called QB and the display behavior is called DB again please bear in mind never underestimate the power of semantics and underestimate the power of good naming so I'm just doing this here because I managed it in space in your program make use of proper variable names okay so then end the constructor we just take these arguments that we've been passed in and set these other variables we take the variables we get passed in through the constructor and set the values of them to our instance variables so we just say this not f b this.f b is to be super clear I should do this so here we have F b QB for kwok behavior DB for display behavior and then here we have F B for Kwok for fly behavior QB for quad behavior and DB for display behavior and then we set these variables so this don't FB for flag behavior is equal to the fly behavior that passing this dog Kwok behavior the instance variable quark behavior is the kwok behavior that we passed in as an argument to the constructor and finally the display behavior on an instance level is a display behavior that we passed in that's it right sorry of course that's not it fly behaviors for example of course have the fly method so when we when we call fly on a class duck we need to invoke the fly behavior here I don't really have space for that here but let's just say that let me put bolt here and then you just continue that over here wha again just continue that over here sorry public void fly takes no arguments and has some implementation what is that implementation what that implementation is just to invoke so what we do is we say this dot FB this fly behavior the instance level fly behavior that will have there will be a concrete instance I was passed in in the constructor this flag behavior adult fly because that was the the name of the method when we were designing a class diagram and then we do exactly the same thing so I won't do it here because I think you can Cesar the pattern we do exactly the same thing for a quat behavior and for display behavior so you pass in a behavior and then you execute that behavior within the class so now ducks very independently or how any particular concrete quark behaviors of fly behaviors actually vary and that's the key point before we wrap up let's quickly look at the generalized UML diagram for strategy pattern let me just clean this up so we would simply be something like this you have a client in our case a duck and that client has some eye behavior and that eye behavior can be implemented by it's an interface or an abstract class or class but it's an interface that it can be implemented by many concrete behaviors so complete behavior a common baby and so forth and of course this I was kind of sloppy with before but of course the client needs to have a reference to I behavior so it has an instance of an AI behavior I didn't draw this in the previous diagrams but I think you can figure out how that's drawn so that we can say execute for execute behavior and then the AI behavior has an execute method actually there my name is run to emphasize that this method is entirely different from this so the execute would execute the run method of the behavior I execute it takes the behavior that we have here and runs the run method here and these concrete behaviors have specialized run methods and that's it that's strategy pattern the only thing that made it complex before is that we had multiple kinds of strategies we have fly strategies and quark strategies and display strategies but if you only have one it's it's it's this simple so now if we read this again I'm sure it makes a lot of more sense so the strategy pattern defines a family of algorithms right encapsulate each one write it capsule it's the whole algorithm here the whole algorithm here and makes them interchangeable right because they are both eye behaviors I should of course have said strategy or to make it more sensible in terms of strategy pattern but makes them interchangeable because since they act as the same type whenever you have an ID havior you can take any of the concrete algorithms so it makes them interchangeable and thus strategy lets the algorithm vary independently from the clients that use it so these algorithm this can vary just as much as it wants this can vary just as much as it wants without having to change the code here that's the power of strategy pattern I highly recommend this book if you want to get a good introduction to design patterns that's it remember to subscribe so that you won't miss the next video on the next design pattern from this book remember we're going through 13 of them thanks for watching I hope that's useful and I'll see you in the next one
Info
Channel: Christopher Okhravi
Views: 1,257,816
Rating: undefined out of 5
Keywords: strategy pattern, design patterns, strategy design pattern, head first design patterns, head first strategy pattern, strategy pattern example, chrokh, strategy pattern examples
Id: v9ejT8FO-7I
Channel Id: undefined
Length: 35min 11sec (2111 seconds)
Published: Wed Dec 28 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.