Command Pattern - Design Patterns

Поділитися
Вставка
  • Опубліковано 29 вер 2024
  • 🚨 IMPORTANT:
    1 Year Free Hosting: www.atlantic.n...
    Use code KYLE for an additional $50
    The command pattern is probably my favorite design pattern, because of all the fun things you can do with it. The idea of the command pattern is to create an abstraction between the operations an object can do, its commands, and the actual commands themselves. This makes it really easy to combine together or chain different commands without having to change the code. The program can dynamically chain and combine these actions. The best part is since each command is its own object you can easily implement and undo function for each command and make a set of undo-able actions.
    📚 Materials/References:
    GitHub Code: github.com/Web...
    Design Patterns Playlist: • What Are Design Patterns?
    🧠 Concepts Covered:
    - What the command pattern is
    - Why the command pattern is important
    - How to implement the command pattern in JavaScript
    - When to use the command pattern
    🌎 Find Me Here:
    My Blog: blog.webdevsim...
    My Courses: courses.webdev...
    Patreon: / webdevsimplified
    Twitter: / devsimplified
    Discord: / discord
    GitHub: github.com/Web...
    CodePen: codepen.io/Web...
    #CommandPattern #WDS #DesignPatterns

КОМЕНТАРІ • 114

  • @Greedygoblingames
    @Greedygoblingames 2 роки тому +38

    Ideally "undo" shouldn't take any parameters and the command class should be immutable, storing the "currentValue" itself, so undo is assured to reverse the original command.

  • @MrMarkgyuro
    @MrMarkgyuro 4 роки тому +2

    this was really clear and helpful : ) ! thank you !

  • @GaneshSatputeAtPlus
    @GaneshSatputeAtPlus 4 роки тому +16

    I get how the pattern is implemented, but I'm not sure what problem does it solve. The "why" is more important than "what" or "how".

    • @aanchalsharma8362
      @aanchalsharma8362 3 роки тому +5

      I was thinking the same.

    • @MrEnsiferum77
      @MrEnsiferum77 3 роки тому

      CQRS for example, is based on commands and events. Every modern event driven microservice architecture build the right way, use commands and events.

    • @paulodonovanmusic
      @paulodonovanmusic 2 роки тому

      Maybe it helps to think about the three examples given (calculator, save/save&exit/exit, bold/etc text), or any situation where you would need to manage the state of a variety of ‘tools’, and how much more complicated our code might be to do it if we didn’t know this pattern

    • @SaqibMubarak
      @SaqibMubarak 2 роки тому +1

      think about implementing chess game.

  • @JokersLaught
    @JokersLaught 4 роки тому +35

    This pattern makes even more sense in a static typed language where you can create a "Command" interface, which the Commands extend.

    • @thatsalot3577
      @thatsalot3577 2 роки тому

      It'll be way easier to implement in typescript.

    • @abhayanavkar2243
      @abhayanavkar2243 2 роки тому

      How can we implement this in java ? Especially the Calculator class

    • @bitgryph6450
      @bitgryph6450 2 роки тому

      ​@@abhayanavkar2243 You can use Stack commandStack = new Stack(). Declaring it this way will allow you to push() every object that implements interface Command. And when you'll want to use undo() write: Command last_command = commandStack.pop();
      Hope that helps :)

  • @linhdo1738
    @linhdo1738 4 роки тому +26

    Love your consistency!!! I gotta ring that bell to be notified when you post new videos :)

    • @Pspisripoff
      @Pspisripoff 4 роки тому +2

      Better donate some cash! Help the coder out!

  • @pinguincoder
    @pinguincoder 4 роки тому +4

    For doing save and exit i find this kinda overengineered. You could also just call Save () and then Exit() inside the Save&Exit and you would not have to duplicate anything. Also for Save and Exit.. Providing an undo is not really something that's is useful and should be done

    • @alimertc
      @alimertc 2 роки тому

      Well, dont take it literally. Its an example to show you that you can compose commands. SaveExit command can also do some additonal stuff, e.g cleanup(); save(); exit().

  • @bordertone_5138
    @bordertone_5138 4 роки тому +9

    But in that way maybe you eventually have to pay extra attention for the undo part ? Because if a function is sort of irreversable (i mean, in case you can't track of the original value just by doing the other way around) e.g in the typical case user put 0 as a multiplier. And because the undo part is coded in a bit of hard coded way, so there could be many cases you can't come back to the initial value and then you have to add extra code to fix it although it doesn't necessarily hurt the worth of pattern itself. Just a thought.

    • @WebDevSimplified
      @WebDevSimplified  4 роки тому +7

      That is a really good point. In cases like these one thing you can do is store the previous value inside the command class for the undo operation.

  • @laysdong
    @laysdong 4 роки тому +8

    Glad to see some sponsorship on your videos. These are hands down the best js videos ive ever seen, and you deserve to be compensated for them. Thanks!

    • @WebDevSimplified
      @WebDevSimplified  4 роки тому +4

      Thanks! I was a little worried doing a sponsorship that it might annoy people but I am glad that it doesn't bother you.

    • @laysdong
      @laysdong 4 роки тому +1

      @@WebDevSimplified Yep not an annoyance at all. As long as the sponsorship ads are fairly relevant and concise(60-90 seconds is probably about the longest a plug should last imo) then you're golden. Keep up the awesome work. You've taught me a ton!

  • @heavyraindrops4750
    @heavyraindrops4750 4 роки тому +6

    Thank you so much for showing this example without complicating it with threading as some examples do. This was very clearly explained!!

  • @randymartin9040
    @randymartin9040 20 днів тому

    This is sick! I definitely need to practice it as it's still really confusing, but you did a great job explaining it and how it could be used sort of like Lego or higher order functions (I think that's where you have a function that calls other functions right? :P ) Still pretty new. Thanks for your great videos.

  • @CryptoRootz
    @CryptoRootz 4 роки тому

    hella fucking confusing.... break this shit down even further bro....

  • @idev6775
    @idev6775 3 роки тому +2

    Hello, thank you so much!
    But you don't need to creating so many class as AddCommand, DivideCommand, etc
    You can create Command class and code as:
    class Command {
    constructor(value, method) {
    this.value = value;
    this.method = method;
    }
    execute(currentValue) {
    return {
    add: currentValue + this.value,
    subtract: currentValue - this.value,
    multiple: currentValue * this.value,
    divide: currentValue / this.value,
    }[this.method];
    }
    undo(currentValue) {
    return {
    add: currentValue - this.value,
    subtract: currentValue + this.value,
    multiple: currentValue / this.value,
    divide: currentValue * this.value,
    }[this.method];
    }
    }
    And then
    const calculator = new Calculator();
    calculator.executeCommand(new Command(10, 'add'));
    console.log(calculator.value);
    calculator.undo();
    If it is stupid... please comment below. Thank for reading.

    • @thatsalot3577
      @thatsalot3577 2 роки тому

      That's a really great way of simplifying the code
      But the problem is, your code doesn't follow open-close SOLID principle which means it's not open for extensions
      For eg : you do have all the methods for doing basic arithmetic like add, subtract, etc...
      But let's say you need to add square root as an option or raised to power or floor function or any other complicated function that'll take about 10+ lines of code
      Your calculator class would start disobeying the single dependency SOLID principle which states each class(or file or function) should do only one complicated thing.

  • @17corteznumber
    @17corteznumber 5 місяців тому

    Hi Kyle, thank you for the content!! I noticed that you didn't build a base command class that could be extended to child commands. Would you suggest implementing a base command with a value and execute and undo methods?

  • @ДенисБосый-ю7р
    @ДенисБосый-ю7р Рік тому

    It is really strange to explain pattern without abstract diagram, it could be more understandable if you had shown us an UML diagram.

  • @tacowilco7515
    @tacowilco7515 4 роки тому +19

    I feel like executeCommand() and undo() had to return 'this'. So you could do:
    calculator.executeCommand(new AddCommand(10))
    .executeCommand(new MutliplyCommand(2))
    .undo();
    But that's just me being picky on random youtube videos :-)

    • @WebDevSimplified
      @WebDevSimplified  4 роки тому +10

      That would be ideal actually. Nice point.

    • @pascalrenner4320
      @pascalrenner4320 4 роки тому +1

      Yes, using fluent interfaces in this example would be great and make combinations like AddThenMultiplay like that unnecessary.

    • @dariogabalec13
      @dariogabalec13 4 роки тому +1

      I tried this solution and it works. The problem with this approach, in my humble opinion, is that violates the single responsibility principle of SOLID. Because executeCommand() shouldn't return an object, just should execute a command.

    • @muchograndeyolatengo
      @muchograndeyolatengo 3 роки тому

      @@dariogabalec13 If I'm not mistaken then Java Streams and C# LINQ also is in violation. Or is it the semantics of "execute" you object to? That doesn't seem like a OOP issue to me, but about naming conventions (and can be easily fixed).

    • @CottidaeSEA
      @CottidaeSEA 2 роки тому

      ​@@muchograndeyolatengo It is not an OOP issue, returning the original instance is fairly common in OOP. However, it is most commonly used for things like the factory pattern.
      SOLID however is a different story. While I do not believe SOLID is technically against this sort of chaining, the issues is rather that the execute method then would have multiple uses, or responsibilities as Dario put it. While not necessarily multiple responsibilities in my opinion, it allows for potentially complicated chaining which *does* go against the principles of SOLID.
      I don't think you necessarily have to strictly follow a principle, it is just that, a principle. It is something you should follow where it makes sense, but it is not a law. In some cases not following a set principle is the best approach, other times it is not, which is why experience is necessary to judge the situation properly. In this case I absolutely agree that it should not return the instance. If multiple commands are to be chained, it is in my opinion better to simply loop through an array.
      As for Java Streams, they don't necessarily violate SOLID, but their usage can certainly do. The issue with streams and lambdas in Java is that they sometimes become very long and bulky, making them hard to read. As a result it can be better to just assign the return value to a variable which you then use on the following row.
      Depending on what you're doing in the function, it should follow those principles and all is fine. Besides, if you split literally everything into separate methods, you'll have a massive hell to work through, not to mention naming the damn things.

  • @Victor_Marius
    @Victor_Marius 3 роки тому +1

    But what if the command is not reversible?
    Like for example after scaling an image down you cannot scale it up because you lose information. Should then be used a history of state there, and for undo you pick the last state of your object / application - but this may increase memory usage for large objects like images / videos?

    • @CottidaeSEA
      @CottidaeSEA 2 роки тому

      Just save the initial state rather than try to calculate the original state. That's a bad idea regardless of the required computational power as it can lead to other side effects such as floating point variances, funky things happening to strings due to encoding, etc. It's better to instead just save the state somehow.

  • @xyzhang6053
    @xyzhang6053 4 роки тому +5

    The clearest and illustrative way explaining design pattern I ever get.

  • @TheAceInfinity
    @TheAceInfinity 3 роки тому +1

    An undo function that needs to be cognizant of the previous operation isn't really an undo however... There are some commands that you potentially cannot undo either (i.e. bitshifting where you've lost bits). A far better demonstration would've been to cache the original value, and it would've also saved on computations.

  • @lastdecember2496
    @lastdecember2496 4 роки тому +2

    SaveExit() { this.save(); this.exit(); }

  • @GoonCity777
    @GoonCity777 3 роки тому +1

    I mean, you would be a top computer teacher in a university or bootcamp

  • @JoeWong81
    @JoeWong81 4 роки тому +4

    Thanks a lot Kyle, this is the first time I've seen this.

  • @vivekborade6136
    @vivekborade6136 4 роки тому +1

    Hi I love you video the way u built it. Thks for all u efforts take to explain the concept.

  • @ProgrammingwithPeter
    @ProgrammingwithPeter 4 роки тому +4

    this was so clear and easy to understand! doing a great job!

  • @lutaseb
    @lutaseb 3 роки тому +1

    Back then i did not learn Command the way you explain, it had just en execute() method, no other method, no parameters, everything was wrapped before the call, which is very similar to the implementation of Runnable in java. Still, I had to implement some cancel operation, and I did not need to divide a value but just return the initial value that was passed on at the construction time

    • @CottidaeSEA
      @CottidaeSEA 2 роки тому +1

      The command pattern can be implemented pretty much however you want. The main thing to keep in mind is that the interface should be uniform; in fact, if you have access to interfaces in the language you're using, you should use them. That way you can add instructions that the executing class can use.
      What you mentioned regarding just returning the original value on cancel/undo is the better approach as it reduces computational power. In fact, I slightly disagree with what was done in this video. If using the principle you mentioned, it would be enough to simply have one execute method, the calculator itself can worry about dealing with the history, not the commands.

  • @shawnnosaurus
    @shawnnosaurus 3 роки тому +1

    Combined with statechart machines and you can make some impressive systems.

  • @deansprivatearchive
    @deansprivatearchive 3 роки тому +1

    This is randomly getting recommended now!

  • @xyzhang6053
    @xyzhang6053 4 роки тому +3

    Do more on design pattern, please!

  • @misterl8129
    @misterl8129 Рік тому

    this video was amazing

  • @hansalucas
    @hansalucas 2 роки тому

    too much staring o.o

  • @ayushdedhia25
    @ayushdedhia25 4 роки тому +1

    Hey Bro are you using any extension for not using semicolons...please tell🤔🤔🤔🤔

    • @WebDevSimplified
      @WebDevSimplified  4 роки тому +1

      Nope. Semi colons are optional in JS

    • @talfaran5849
      @talfaran5849 3 роки тому

      @@WebDevSimplified Try to use them as a standard because you very often have to use them with TypeScript. that said - u can use Prettier connected to an Eslint rule that will add the semi-columns for you.

  • @user-uh3zr7mo4i
    @user-uh3zr7mo4i 4 роки тому +1

    why arent your eyes blinking?

  • @zkiez2995
    @zkiez2995 4 роки тому +1

    What are u using to code??

  • @roytouw4374
    @roytouw4374 2 роки тому

    Clear explanation, only this seems like a lot of overhead compared to using the functional style of composing curried functions?

  • @blu3_enjoy
    @blu3_enjoy 2 роки тому

    Thank you

  • @manzourabdalla2279
    @manzourabdalla2279 4 роки тому +1

    Thank you for everything Incredible videos, keep going

  • @linkarysl9938
    @linkarysl9938 2 роки тому

    great, thx!

  • @Dragon20C
    @Dragon20C 3 роки тому

    what are the possibilities, I got told this is a good way of controlling what type of action/function I want to be called at a specific times, for example a turn base system.

  • @blokche_dev
    @blokche_dev 4 роки тому +1

    Nice and clean explaination of the command pattern.

  • @ksrele
    @ksrele 4 роки тому +1

    How do you record sound? It sounds like some "noise reduction" option is enabled and it destroys the sound...

    • @WebDevSimplified
      @WebDevSimplified  4 роки тому +2

      I am using OBS, but I agree something sounds off. I really need to sit down for an hour or so with someone who knows audio really well and go through my setup.

    • @ksrele
      @ksrele 4 роки тому

      @@WebDevSimplified Just follow this instructions but turn off all options.
      techtalk.currys.co.uk/gadgets/smart-home/how-to-reduce-microphone-noise/

  • @montebont
    @montebont 2 роки тому

    Lovely! I've been around for a bit and it reminds me of the postFix notation in Forth, SmallTalk and a few other languages. What it comes down to is that you first push values (operands) onto a stack followed by the operator. So rather "3 5 +" then "3 + 5". In this example, "3 5 +" pushes the numbers onto the stack because they are numbers/operands. The "+" is recognized as an operator. and It'll add the 2 numbers by pulling them from the stack and pushing the result "5".
    I am not sure if this was actually implemented in SmallTalk but you can easily manage history by adding markers to the stack in the same way as try/catch (and a few other "GOTO's in disguise") work.
    Stacks are just arrays of objects and can be easily inplemented in Javascript ;-)
    Anyway: thanks for all your efforts to share you knowledge in a very accessible way!
    Ed

  • @xBZZZZyt
    @xBZZZZyt 3 роки тому

    add undo limit because calculator will use more RAM every time command is executed

  • @pranavpatil5849
    @pranavpatil5849 4 роки тому

    Hey ..can u tell which design pattern is used in Modern web React-redux application?

  • @deansprivatearchive
    @deansprivatearchive 3 роки тому +1

    83th

  • @reignover17
    @reignover17 3 роки тому

    indeed the execute() method shouldnt receive any parameter

  • @eddiejaoude
    @eddiejaoude 4 роки тому

    Design patterns 👍💪🤓

  • @Trek_Tales
    @Trek_Tales 4 роки тому

    Bro can you please explain me function closures in JavaScript please ..please ..please..

  • @stefan4800
    @stefan4800 4 роки тому

    Good idea is to use Dependency Injection, creating for example Device interface, so you can have multiple devices which are implementing the interface, like Calculator, Remote, etc.
    You can create the class ExecuteCommand, with constructor require the interface Device, so you can do something like this:
    Class ExecuteCommand {
    constructor(Device insertDevice)
    execute(DoCommand);
    undo(UndoCommand);
    }
    executeCalcurator = new ExecuteCommand(new Calculator)
    executeRemote = new ExecuteCommand(new Remote)
    executeCalcurator->execute(new AddCommand(10))
    executeCalcurator->undo(new SubtractCommand(10))
    executeRemote->execute(new AddVolume(10))
    executeRemote->undo(new SubtractVolume(10))
    etc, etc...
    Note: My pseudo code reminiscent on PHP, the language I usually use, so sorry about that. ;)

    • @CottidaeSEA
      @CottidaeSEA 2 роки тому

      The calculator itself should worry about the history. I don't feel like the commands themselves should have to think much of it. However, even then it should be enough to remember the initial state, which should be set during execute. If you want to be proper, the execute command should also throw an error if it has already been run, that way you can ensure the state remains untouched.

  • @panchcw
    @panchcw 3 роки тому

    could do video for flywieght pattern

  • @xBZZZZyt
    @xBZZZZyt 3 роки тому

    09:45 just use functions to avoid duplication

  • @heavencanceller1863
    @heavencanceller1863 2 роки тому

    You explained this perfectly. Thank you

  • @sonayr2657
    @sonayr2657 4 роки тому +3

    Couldn't have made this concept anymore simple and easy to consume, great job!

  • @MOUNIROU60
    @MOUNIROU60 4 роки тому

    this is kind of command pattern with integrated factory pattern

  • @adeaf3396
    @adeaf3396 Рік тому

    Thanks a lot man, such a great job, cheers!

  • @elijahmuraoka
    @elijahmuraoka 2 роки тому

    What’s the benefit to using “const” rather than an “int” or “double”

    • @CottidaeSEA
      @CottidaeSEA 2 роки тому

      There is no int or double in JavaScript. A const cannot be reassigned, modified if an object however. There are two alternatives, let and var. Most favor let these days, but var can ensure it cannot be deleted and as such will technically keep being defined even though the value itself can be undefined. They also have different scope rules.
      But to answer your question; there is no reason not to, it just doesn't exist in JavaScript.

  • @paulodonovanmusic
    @paulodonovanmusic 2 роки тому

    I learnt so much today, thanks Kyle!

  • @TheKillermob13
    @TheKillermob13 4 роки тому

    did u just changed your shirt

  • @aditya234567
    @aditya234567 3 роки тому

    Isnt this memento pattern???

  • @AsciiKing
    @AsciiKing 2 роки тому

    Nice work. Very clearly explained, dude.

  • @jeromesnail
    @jeromesnail 3 роки тому

    Every pattern is your favorite 😁

  • @karnpratapsingh8860
    @karnpratapsingh8860 2 роки тому

    great explanation brother!

  • @jivanmainali1742
    @jivanmainali1742 4 роки тому

    I am using heroku so is there any benefits of using Atlantic hosting? Suggest me

    • @WebDevSimplified
      @WebDevSimplified  4 роки тому +1

      Atlantic is cheaper by a lot for the power you get but it requires you to do more devops yourself since it is just a ser we and you have to manage everything yourself. It is great for learning devops.

  • @MrXception007
    @MrXception007 4 роки тому

    Which mic you are using?

  • @ransabalon
    @ransabalon 4 роки тому

    can you please blink? hahaha

  • @priyantanugupta7643
    @priyantanugupta7643 3 роки тому

    Loved it

  • @neoX12000
    @neoX12000 4 роки тому +3

    Hey everyone had a awesome life until webassembly comes

  • @QQ-kh6uf
    @QQ-kh6uf 4 роки тому

    Absolutely splendid!

  • @pooyadehghan17
    @pooyadehghan17 4 роки тому

    Just love it ...

  • @aotechdev
    @aotechdev 4 роки тому

    Thanks Keil

  • @susanthawarnapura
    @susanthawarnapura 4 роки тому

    nice explanation

  • @jivanmainali1742
    @jivanmainali1742 4 роки тому

    Always impressive

  • @Lyrik-Klinge
    @Lyrik-Klinge 4 роки тому

    you made a good job of it!

  • @tech-andgar
    @tech-andgar 4 роки тому

    🤯👌

  • @mosup5007
    @mosup5007 4 роки тому

    I clicked the video to see your spin.
    why didn't you do it.

    • @WebDevSimplified
      @WebDevSimplified  4 роки тому

      I only ever did it in one video

    • @mosup5007
      @mosup5007 4 роки тому

      @@WebDevSimplified it was about positioning in css and it was a good one.
      I wanted to learn a little a bout front-end.

    • @WebDevSimplified
      @WebDevSimplified  4 роки тому

      I have a bunch of videos on the frontend on my channel you can checkout. Unfortunately, none have a chair spin though.

  • @cliffordowusuamponsah9532
    @cliffordowusuamponsah9532 3 роки тому +1

    One of my favorite youtubers so far. Blessings Kyle. I have been following the series and it’s great!!!

  • @GoldenPanthersLax
    @GoldenPanthersLax 4 роки тому +1

    Great video, for the history array you should try out concat or the spread operator to keeps things immutable

  • @IslamIsDanger
    @IslamIsDanger 3 роки тому

    Amaizing !!!