Strategy Pattern, The Best Software Design Pattern

แชร์
ฝัง
  • เผยแพร่เมื่อ 23 ธ.ค. 2024

ความคิดเห็น • 114

  • @jonowilliams26
    @jonowilliams26  7 หลายเดือนก่อน +2

    I made a follow up to this showing how we can extend this to send notifications based on a users preference. Check it out here th-cam.com/video/aBOrVRKK3fA/w-d-xo.html

  • @nanonkay5669
    @nanonkay5669 7 หลายเดือนก่อน +263

    I didn't know this was called the strategy pattern, to me its just an example of why and how interfaces are useful lol

    • @blipojones2114
      @blipojones2114 7 หลายเดือนก่อน +53

      honestly, these patterns....once you have written enough software you just refer them all as "abstraction" and you just know how much or how little based purely by feel, business circumstances, team skill, tech stack maturity, product maturity etc etc....
      i think attempting to give labels trivalise things which invites devs just slapping on random ones instead of engaging a brain cell.
      In other words, design patterns was an attempt to short-cut having experience.

    • @darylphuah
      @darylphuah 7 หลายเดือนก่อน +50

      ​@@blipojones2114 design patterns was supposed to be a communication tool. So if I say "we can use a strategy pattern here", we should both be at ~90% understanding of what that means. Without having to describe the whole abstraction.
      The problem is when people started using a communication tool as a bible.

    • @glorfyndel8533
      @glorfyndel8533 7 หลายเดือนก่อน

      Totally right sir ! The ‘pattern’ is that there is no pattern !
      (Also remember that encapsulation is more important than polymorphism in OOP) ;)

    • @CottidaeSEA
      @CottidaeSEA 7 หลายเดือนก่อน

      @@blipojones2114 Math formulas are an attempt to short-cut having experience. See how that doesn't work in other fields? Design patterns are the same way, they are defined ways of doing a certain thing.

    • @blipojones2114
      @blipojones2114 7 หลายเดือนก่อน

      @@CottidaeSEA I do not agree that a mathematical formula and a software design pattern are comparable.
      Formulas give the same reliable results, software pattens don't.

  • @francksgenlecroyant
    @francksgenlecroyant 7 หลายเดือนก่อน +12

    it added an abstraction layer, everything is happening within that method containing the switch statement, it's just fine cuz the service where the business logic happens does not need to worry about the instanciation of the OrderNotifier type

  • @TESkyrimizer
    @TESkyrimizer 7 หลายเดือนก่อน +53

    But couldn't I have just extracted the switch statement logic into individual methods?
    Clean code fans vs monolith class enjoyers
    But seriously lately I have been bothered about how convoluted it becomes to trace code after adopting proper architecture patterns. Maintainability is easier in some ways but also harder in other ways 😓

    • @darylphuah
      @darylphuah 7 หลายเดือนก่อน +4

      Extracting the code into methods still couples the code to the class. So everytime you want to add/remove an implementation of a notifier, you'll have to modify the Order Service. The switch statement is just an example, but the dependency can be injected for the class in many different ways. So a notifier can be implemented without touching the OrderService class. It makes testing much easier too.
      The layers of abstraction can get ridiculous when implementing design patterns liberally. This is where a senior/tech lead with experience should help guide to make sure things don't get out of hand.

    • @RaVq91
      @RaVq91 7 หลายเดือนก่อน +6

      Abstractions add complexity. Avoid not needed abstractions. Your idea looks good and IMO may work in mentioned scenario.

    • @pitchwaiz
      @pitchwaiz 7 หลายเดือนก่อน +2

      @@darylphuah also some of these methods might need their own private methods in the future if they get more complex, so it's better to have their own services so you can keep logic of the sms in the sms service.

    • @Nellak2011
      @Nellak2011 7 หลายเดือนก่อน +5

      FP would solve this, but that is too simple. If you aren't making things convoluted, you aren't a "real programmer" as they say.

    • @duncanlgeoghegan6333
      @duncanlgeoghegan6333 7 หลายเดือนก่อน +10

      @@pitchwaiz yeah that's true but on first writing, sometimes it's easier to keep it all in a single class / function. Clean code wants us to almost anticipate future complexity that might never arrive, and in doing so brings its own overhead. My feeling would be the if else statements are more readable, not running up chains to see what actually happens. If it gets really complex, then yeah, abstract up a layer, but I guess... not prematurely.

  • @eliseusalomao4906
    @eliseusalomao4906 7 หลายเดือนก่อน +48

    It's all about interchangeability. Also, those are pretty cool animations it helps to get a better grasp on the examples

  • @seannewell397
    @seannewell397 7 หลายเดือนก่อน +26

    I see a switch still! It's just in the DI.
    You can't always do this if you need to decide based on the request/order/user-preferences

    • @jordixboy
      @jordixboy 7 หลายเดือนก่อน +3

      you sound like a senior, not like the one from the video, lol.

    • @mcdev6868
      @mcdev6868 7 หลายเดือนก่อน

      Exactly, and even if this notification settings were user settings then you'd have to restart the client in order to take effect.

    • @dumax97
      @dumax97 7 หลายเดือนก่อน +1

      There has to be at least one switch to support multiple implementations unless you want your DI to choose what implementation to pick

    • @jordixboy
      @jordixboy 7 หลายเดือนก่อน +1

      @@dumax97 do you get that the switch statement is the same as the if, and you are just moving it somewhere else?

    • @dumax97
      @dumax97 7 หลายเดือนก่อน +2

      @@jordixboy switch statements are usually safer as in case you add additional enum value, it force you to add a case for that new value - you don't get that with if statements

  • @SimGunther
    @SimGunther 7 หลายเดือนก่อน +10

    The interpreter pattern is such a good pattern you can implement every pattern, including itself, in it

    • @linkernick5379
      @linkernick5379 7 หลายเดือนก่อน +1

      Tagless Final the ultimate one 😎

  • @rauljerilara
    @rauljerilara 8 วันที่ผ่านมา

    Means that we have to create a new class for a new NotificationType right?

  • @DrFlash-mh6st
    @DrFlash-mh6st 4 หลายเดือนก่อน

    Brother, Please cover all design patterns in these short videos please. It is just the world's best video to revise a pattern or to get a quick intro if you are new to them.

  • @srki22
    @srki22 7 หลายเดือนก่อน +1

    What do you do if a customer wants to receive both email and SMS notifications? What is the best way to deal with that?

  • @ReeceEngle4
    @ReeceEngle4 17 วันที่ผ่านมา

    I think this is definitely a good approach, however if I'm not mistaken it only allows for one type of notification or am I mistaken?

  • @tayyabshaikh8129
    @tayyabshaikh8129 8 วันที่ผ่านมา

    Please can you tell me which software you used to create the video?

  • @zyph.
    @zyph. 7 หลายเดือนก่อน +2

    The pattern itself is fine, but the example has a problem in my opinion.
    An “EmailService” or an “SMSService” should have limited responsibility. The “EmailService” shouldn’t know how to send an order confirmation. This can be the responsibility of a class that implements the interface and uses the “EmailService”. By using composition, your “EmailService” will stay simple and be more portable between implementations.

    • @grenadier4702
      @grenadier4702 3 หลายเดือนก่อน

      What if you need to use the email service twice and thus send the confirmation twice as well, you'll need to create an additional class that just does that. Isn't it too much?

    • @zyph.
      @zyph. 3 หลายเดือนก่อน

      @@grenadier4702 I don’t think there’s necessarily one perfect solution. As your platform grows you might first group functionality a certain way and change that over time. I think that people sometimes are worried to get it 100% right from the start.
      You could have an “OrderService” that can use the “EmailService” and “SMSService” to send order confirmations.
      It seems likely that you’ll want to send more types of emails in the future. I recommend designing it in a way where you could port certain classes to other apps. If you need Email or SMS functionality in another app, those classes would be a lot more portable if they don’t focus on the actual content that they are sending.

  • @fabricehategekimana5350
    @fabricehategekimana5350 หลายเดือนก่อน

    I love using the strategy pattern with higher order functions: no need to create an interface and classes that implement it. Just create function or directly inject anonymous ones👌

  • @guidosalescalvano9862
    @guidosalescalvano9862 7 หลายเดือนก่อน +1

    It is also great for finding different calculation strategies

  • @PankajNikam
    @PankajNikam 7 หลายเดือนก่อน +4

    What if we must send the notification through all the providers (including the pigeon 😁) ?

    • @jonowilliams26
      @jonowilliams26  7 หลายเดือนก่อน +14

      Rather than injecting a single IOrderNotifier, inject an IEnumerable and loop through and call each provider

    • @ashbjorn
      @ashbjorn 7 หลายเดือนก่อน +6

      @@jonowilliams26 probably nicer then to perhaps introduce an OrderManager that holds on to that internal collection of providers? Kinda how the logging is implemented maybe? #thought-out-loud

  • @xthenuwara
    @xthenuwara 8 วันที่ผ่านมา

    It's dependency inversion?

  • @Tuscani2005GT
    @Tuscani2005GT 6 หลายเดือนก่อน

    This is the same thing as the delegate pattern although you could make an argument that delegates have more methods and/or are long lived but still the same imo. Either way this becomes extremely powerful when using mock strategies/delegates for testing.

  • @noahginsburg6140
    @noahginsburg6140 7 หลายเดือนก่อน +2

    I does OrderService know which registered implementation to use?

    • @jamestacular
      @jamestacular 7 หลายเดือนก่อน

      Dependency Injection. In the Project or Startup class in ConfigureServices he is setting which concrete class to use whenever a class takes a IOrderNotifier parameter. The concrete implementation is set in the configuration file. .NETs dependency injection will work behind the scenes after you register a service to give you the implementation later on

  • @pacholoamit
    @pacholoamit 7 หลายเดือนก่อน

    Hello! What do you use to create these stunning code presentation videos

  • @user-hk3ej4hk7m
    @user-hk3ej4hk7m 7 หลายเดือนก่อน

    How is this different from just using a function that takes an order and does the notification thing?

    • @0xSLN
      @0xSLN 7 หลายเดือนก่อน

      I often like this approach. Higher abstractions only when the need has been proven, unless its clearly a part of the requirements.
      I come from JS and a lot of enterprise software terminology has been bloated. Di, strategy, adaptor etc. A function is good precisely because it has a lot of those concepts baked into it at a fundamental level.

  • @sunnypatel1045
    @sunnypatel1045 7 หลายเดือนก่อน +11

    I use this pattern with a factory pattern!

    • @jonowilliams26
      @jonowilliams26  7 หลายเดือนก่อน +4

      I do too! It’s really good especially when you need to create a strategy based on some runtime variables

    • @sunnypatel1045
      @sunnypatel1045 7 หลายเดือนก่อน

      I like the way you handle DI. Instead of registering each one the scan through the interface and register it via DI and in the calling class I inject Ienumerable

  • @ricardoduarte442
    @ricardoduarte442 7 หลายเดือนก่อน +4

    Would have liked to see an runtime implemention / usage of this examples, because the example u gave was using the Startup of the app to choose one of the implementations, but most times I feel like u would use this in runtime with some kind of Resolver to get the wanted implementation of the Interface.
    Still very well explained, my favorite pattern as well

    • @junior.santana
      @junior.santana 7 หลายเดือนก่อน

      If you the implementation can vary in runtime maybe depending on the custom for example one approach could be using the factory pattern. So you inject the factory into the OrderService which is responsible for instantiating the appropriate implementation

    • @dumax97
      @dumax97 7 หลายเดือนก่อน

      In that factory, there again will be the same switch

    • @junior.santana
      @junior.santana 7 หลายเดือนก่อน +1

      @@dumax97 yeah, no problem with that. The factory will centralize the logic for creating the objects. How they are created is another story, using a switch is not wrong, a hashmap or other techniques are possible as well

  • @seth111yta1
    @seth111yta1 7 หลายเดือนก่อน +1

    watch as this if stack (@0:36) gets ✨COMPLETELY TRANSFORMED ✨into a switch statement (@2:05)

  • @avinashsuresh5221
    @avinashsuresh5221 2 หลายเดือนก่อน

    This is surprisingly common thing to do. I didn't know it was called Strategy. Isn't this what interfaces are about?

    • @jonowilliams26
      @jonowilliams26  2 หลายเดือนก่อน

      Yep, it’s really simple and like you said, it’s common practice

  • @nengforgame8145
    @nengforgame8145 7 หลายเดือนก่อน +1

    good video plz make more content like this.

  • @mattymattffs
    @mattymattffs 7 หลายเดือนก่อน +2

    This is great until you try and figure out which implementation is actually being used... Plus if you want multiple notifies it's now annoying

  • @VictorMenge
    @VictorMenge 7 หลายเดือนก่อน +11

    or you could just pass a closure ¯\_(ツ)_/¯

    • @user-hk3ej4hk7m
      @user-hk3ej4hk7m 7 หลายเดือนก่อน

      You wouldn't even need to do that. Just a regular function call when you get the order. Strategies are OOP coping hard

  • @-solitude.
    @-solitude. 7 หลายเดือนก่อน

    I've been doing this since I started into code, I thought that it was the motive of the existence of functions

  • @fifty-plus
    @fifty-plus 7 หลายเดือนก่อน +1

    Nice one. A strategy factory would be nice then you just have a new registration for each type and you're done. OCP FTW.

  • @matinlh644
    @matinlh644 7 หลายเดือนก่อน

    I'm confused, it was like dependency invertion

  • @Nellak2011
    @Nellak2011 7 หลายเดือนก่อน +5

    My professor introduced this pattern, but had written several Java files to implement it with complex relationships.
    I implemented it functionally in 7 lines of code.
    This is one reason why I really really hate OOP related crap.

  • @alexulag
    @alexulag 7 หลายเดือนก่อน +2

    excellent explanation Jono. Short and as we said in colomba "Al grano"

  • @ilyahryapko
    @ilyahryapko 7 หลายเดือนก่อน +1

    This logic is nice when we have that distinction and comptime. But when there's a need to use customer provided means of communication (whether or not customer added phone and accepted sms notification, added email and accepted email notification and so on) this logic basically will be extracted in another class with same if-else statements? Do we have a pattern for such usecase? Or we will be making more abstractions with something like "IOrderNotificationPossibility.CanAccept(NotificationType.Sms, user)" in order to make it look seamless and easy to extend?

    • @jonowilliams26
      @jonowilliams26  7 หลายเดือนก่อน +2

      You could use the factory pattern along side the strategy pattern. The factory takes in a customer/user which creates the order notifier strategy to be used

    • @ilyahryapko
      @ilyahryapko 7 หลายเดือนก่อน +1

      @@jonowilliams26 hi! Thank you for an answer. So it basically means that this "if-else\switch" related to some users properties would be located inside this factory?

    • @jonowilliams26
      @jonowilliams26  7 หลายเดือนก่อน

      @@ilyahryapko yeah that’s right

    • @hc1770
      @hc1770 7 หลายเดือนก่อน

      My way of doing this is to have a function parameter maybe called "extras" that you can pass in additional information.
      The service itself will then know how to handle the "extras". That way you can still use the same pattern.

  • @Fanmade1b
    @Fanmade1b 7 หลายเดือนก่อน +1

    It's my favorite pattern, but usually I has to be combined with another logic and/or pattern to be the most useful.
    For example I used it in a validator class.
    There I created an interface for validation rules. They have one "isApplicable" method that accepts the validation rules of the current request and return a boolean, and a "validate" method, that return a validation response with an optional error message bag.
    The validator has a method for registering validation rules.
    Whenever it receives a request, it will then loop through all registered validation rules, validate the request for each one that is applicable for it and collect all error messages.
    Adding new validation rules is very easy and you don't have to touch any existing code apart from the place where the rules are registered.
    Not a single "switch" used anywhere :)

  • @maxpaju
    @maxpaju 7 หลายเดือนก่อน +5

    From my perspective, this is complexity-galore added to solve some problem that could be solved with a simple switch-statement. To me, a lot of OOP is just adding layers of complexity, making the code harder to debug and reason about.

    • @Nellak2011
      @Nellak2011 7 หลายเดือนก่อน +3

      Absolutely correct. Functional Programming is the way to go.

    • @jareerareerarr5053
      @jareerareerarr5053 6 หลายเดือนก่อน

      I Agree but it's required for my assignments lol

  • @ix4564
    @ix4564 7 หลายเดือนก่อน

    That carrier pigeon notification though is now going to be sent to everybody because of that one client. Clearly there's a flaw in the logic. It needs to be personalized ;)

  • @karmatraining
    @karmatraining 7 หลายเดือนก่อน +1

    Good old polymorphism!

  • @zahansafallwa3263
    @zahansafallwa3263 6 หลายเดือนก่อน

    Why it looks like factory pattern to me 😬😬😬😬

  • @DrewTeter
    @DrewTeter 7 หลายเดือนก่อน

    Reminds me of Duck Typing.

  • @Disorrder
    @Disorrder 7 หลายเดือนก่อน +1

    Not sure it’s a strategy pattern

  • @deepfuchsia7204
    @deepfuchsia7204 7 หลายเดือนก่อน

    I thought it's a video from prnhub

  • @jordixboy
    @jordixboy 7 หลายเดือนก่อน +7

    You're just moving the conditional elsewhere in this case switch statement... People often misuse and abuse patterns/architectures, they have there place yes, but the problem with a lot of engineers is precisely that, over-engineering, having a hammer and seeing needles everywhere, you're opening clearly demonstrates that by saying "this is my favourite pattern", we should not have favourite "things" this doesn't make us good engineers imho. This only leads to fanboys applying shitty solution to problems, like javascript on the desktop lol

  • @dustinramsey5940
    @dustinramsey5940 7 หลายเดือนก่อน

    Julia has this thing called "multiple dispatch" that basically does what you're doing but within the language.

    • @CamaradaArdi
      @CamaradaArdi 7 หลายเดือนก่อน

      Almost every single language has this feature in one way or another

  • @seyproductions
    @seyproductions 7 หลายเดือนก่อน

    So the strategy pattern obeys the open-closed principle then.

  • @nonefvnfvnjnjnjevjenjvonej3384
    @nonefvnfvnjnjnjevjenjvonej3384 7 หลายเดือนก่อน +2

    see this is where these software principles break down. you are still doing the switch statement (basically the if statement) in another place now. this is the problem with clean code, uncle bob and design patterns. has made everything messy by hiding different things in different places.
    dont follow these please. take it from a software dev with over 10 yrs of experience, what you want to do is write simple imperative code with re usability through functions and that is it.
    if you are an intermediate dev it feels very good to learn these new things, (i went through them myself) but once you gain even more experience you realize this is all bs.
    code should be as easy to follow as possible. look at how game devs do things. when there is no space to waste time on useless cycles due to real performance reasons, the code becomes much more simpler and streamlined.
    anyways, reply to my comment if you want me to clarify something further.

  • @salah1x
    @salah1x หลายเดือนก่อน

    bruh, i give up lol, idk why I find this shit so complicated

  • @vikkio88
    @vikkio88 7 หลายเดือนก่อน +1

    8000 lines of code and 50 files to avoid a switch statement.
    man I hate enterprise code like this

  • @CamaradaArdi
    @CamaradaArdi 7 หลายเดือนก่อน +8

    This is almost good. This has a significant performance overhead, it's much better to send in a function pointer or a closure instead of an interface with no downsides.

    • @chrismoutray9206
      @chrismoutray9206 7 หลายเดือนก่อน +16

      What a ridiculous comment.

    • @thanhtamle4138
      @thanhtamle4138 7 หลายเดือนก่อน +1

      A closure is a great idea 👍

    • @liquidpebbles
      @liquidpebbles 7 หลายเดือนก่อน +1

      Care to explain?

    • @CamaradaArdi
      @CamaradaArdi 7 หลายเดือนก่อน +7

      @@liquidpebbles You don't need a class that implements a method called through a vtable.
      You can just pass the function directly. It's often clearer (just a function doing what you want or a closure which can be just declared right there) and faster (literally a function call).
      I'm all for strategy pattern and dependency inversion, I think it's good but OOP tends to make it more convoluted than it needs to be.

    • @Nellak2011
      @Nellak2011 7 หลายเดือนก่อน +7

      @@CamaradaArdi Finally someone sees logic and simplicity. This pattern is literally solvable by higher order functions. Just pass a function as an argument. The argument would be the strategy it employs.

  • @lpi3
    @lpi3 7 หลายเดือนก่อน

    Remember kids: the best pattern is a function which gets other functions as an argument

  • @jsonkody
    @jsonkody 7 หลายเดือนก่อน +1

    Cool video, nice animations, excelent explanation .. god how I hate Java-ish verbosity and it's OOP style 🤢🤢😅

  • @SlowCarToChina
    @SlowCarToChina 7 หลายเดือนก่อน +7

    LOL…just moved the if’s somewhere else.

    • @mennonis
      @mennonis 7 หลายเดือนก่อน +5

      Ofcourse, in the end the same code has to run. But the idea behind refactoring is to make it readable/maintainable/scalable

  • @greob
    @greob 7 หลายเดือนก่อน

    What if I want only two or three types of notifications out of the 5 you ended up with at the end?

  • @133289ify
    @133289ify 7 หลายเดือนก่อน

    Ughhh classes...
    meanwhile in JavaScript:
    const shipOrder = {
    'email': () => ...
    'sms': () => ...
    'push': () => ...
    }
    shipOrder['email']()

    • @jonowilliams26
      @jonowilliams26  7 หลายเดือนก่อน +1

      Meanwhile in JavaScript:
      let x = [2, 10, 1]
      x.sort()
      // result = [1, 10, 2]