- Overview
- Transcript
4.8 Strategy
The strategy pattern is another very useful and powerful pattern. The idea behind this pattern is to abstract the functionality of a class into small strategy classes so your base classes can use that functionality flexibly.
1.Introduction2 lessons, 04:27
1.1Introduction01:39
1.2Prerequisites02:48
2.Creational Patterns5 lessons, 52:47
2.1Factory10:16
2.2Abstract Factory12:24
2.3Singleton09:09
2.4Prototype09:18
2.5Builder11:40
3.Structural Patterns7 lessons, 1:05:54
3.1Adapter10:07
3.2Flyweight10:33
3.3Proxy05:53
3.4Bridge10:35
3.5Decorator11:44
3.6Composite09:43
3.7Facade07:19
4.Behavioral Patterns9 lessons, 1:25:42
4.1Iterator09:32
4.2Command07:48
4.3Chain of Responsibility13:47
4.4Mediator08:16
4.5Memento08:53
4.6Interpreter14:31
4.7Observer08:58
4.8Strategy07:36
4.9State06:21
5.Conclusion1 lesson, 02:42
5.1Conclusion02:42
4.8 Strategy
The next pattern that we're going to talk about is one that is incredibly powerful, and very important. And allows you to create some very flexible applications if done properly. And this one is called the strategy pattern. And the basic concept behind the strategy pattern is wanting to abstract the actual operations that can be done on a particular object, by swapping out their implementations. And by swapping out their implementations, I'm talking about swapping out the functions and the functionality that they can perform. So let's go ahead and start by going through an example. So we have the StrategyPattern playground. And now what we wanna do, is we wanna take a simple scenario. So let's say we're writing some software that is going to allow us to translate some strings. So I wanna be able to maybe pass in a string, and translate it to Spanish, or maybe German, or some other language. So typically what we might think about doing at that point is creating some translators. So I can do something like class, maybe create a SpanishTranslator that is going to just have one single translate function. And it's gonna take in maybe a string, that is going to be a string. And it's going to be some sort of text that I want to translatle, so I can say print. And then I'll just say Spanish, because I'm not really a translator. But I'm going to stick in here the actual string, so that I know that it is actually being translated to another language. So as you can see it's going to be Spanish here. So let's go ahead and copy this maybe, because we want to do another language as well. We could say German, maybe we're gonna have a GermanTranslator like this. And this will now say German down here. And so then typically what we would do is we would create some translators. So I could say let German = GermanTranslator, and let Spanish = SpanishTranslator. And then I can start to translate things. So I could say german.translate "Hello there!". And then I could do Spanish as well. I can say spanish.translate "How are you?". Okay, so obviously these things are not actually translating, but I think you get the idea. So whatever logic is contained within these classes in the translate functions is what's firing right here. But if now we start to take a closer look at our classes and our implementations. We can start to see that the only thing that differs from the SpanishTranslator to the GermanTranslator is the implementation of the translate functions. Now anytime you see something like that, this is a prime candidate for the strategy pattern. Because what the strategy pattern will allow us to do is to treat these as a very generic translator class. And just swap in and out the individual implementations of their functions. So let's go ahead and switch this up a little bit. So let's clear this out, and let's rethink this using the strategy pattern. So what we're gonna do here is we're going to create a protocol. And we're gonna call this the TranslationStrategy protocol. And within here, we simply have a single function, and that's going to be translate. So we're abstracting out the idea of this operation. And it's going to take in a string, and it's going to process that string. So every sort of strategy that we create is going to abide by this protocol. Now we can start to create different implementations of that. I can now say I can create a SpanishTranslation. Which is going to use the TanslationStrategy and we're simply going to translate it. And like I did before, I'm going to say "Spanish". And it's simply going to print out the message that we had passed in, or the string that we had passed in. Okay there's one translation, now let's go ahead and copy this to another one. So now this is the GermanTranslation, and we're simply going to do German. Okay, so this looks basically the same. But now the power of this is in using these strategies in a very generic wrapper class. So now I can create a single class called Translator. And this class at any given time can deal with a strategy. So we're gonna store that strategy as a private variable called strategy, which is going to be a TranslationStrategy. And then we can initialize it to whatever strategy we want to use at that particular time. Okay, so now we can use that translator, but at any particular time, we may want to update that strategy. We may want to use a different implementation. We might wanna switch from Spanish, to German, to any other language that we could possibly want to handle. So we're simply going to say, func setStrategy. And this one is going to take in another strategy, just like our initialization function did. This is gonna be a TranslationStrategy and we're simply going to set that strategy. Okay, pretty good. And now ultimately what we want our translator to do, is translate some sort of string, like we saw in our previous example. So now we have a function that is going to be translate. And we are simply going to translate some sort of string or text. And instead of us having the implementation in those specific ones. Now we can delegate that translation process, or that functionality to a particular strategy. So I can simply say, strategy.translate that string. Okay, that's pretty cool. So let's see how this works when we actually use this in an implementation. So let's create a couple different translations. So we'll say let german = GermanTranslation, let spanish = SpanishTranslation. And now anytime I want to add additional functionality. All I need to do, or add functionality for another language, all I need to do is create another strategy, another translation strategy. And provide that implementation, and then I can use it in my translator. So it's much more extendable and actually testable at the end of the day. Then we'll create a translator, which is going to be equal to a new translator. And by default we are going to pass it a strategy, we'll start with german. And then we can say translator.translate, and we're gonna translate "Hello there", just like we did before. And once this executes, you're gonna see that it's functioning in German. But then at any given time, when I want to change that, I can simply set my translator strategy. So I can set my strategy now to be in Spanish. And the next time I execute my translator and I translate some string, I can say, ""How are you?". And now when it fires, it's going to use the Spanish strategy and output Spanish, "How are you?". So you can see the concept behind the strategy pattern is very simple. In that we want to take the implementations of certain pieces of our class, and abstract out that implementation. And be able to swap it in and out for other versions of implementations, to allow us to easily extend the reach and the functionality of our application.







