2

In an attempt to solidify my understanding of the command pattern, I decided to write a calculator application that utilised it.

After making some progress, I realised that my choice of application may not have been the ideal choice.

enter image description here

I have the following components:


View.xml

This is the user interface of the calculator, and is equivalent to the “client” in diagram. This is my view layer.


Controller.cs

This is the equivalent to the “invoker” in the diagram, this holds the commands, and calls execute on them. This is my controller layer


Model.cs

This is the equivalent to the “receiver” on the diagram.


commandOne.cs, comandTwo.cs, commandMinus.cs...... etc

These are my concrete commands , that define a binding between an action and the model.


As well as executing the commands, the controller also mains a queue of commands for the purposes of undo and redo.

In applying the command pattern to a calculator, I realised that execution of the commands is deferred until the entire expression has been created and equals has been pressed. I therefore set about recoding the sequence of button presses in the model layer before realising that I already had a container storing these in the form of the undo/redo queue in the controller.

Therefore, my question is, should I pass my controller/invoker to the model layer when the expression has been completed so that the commands in the queue can be run sequentially to calculate the result.

Or should I persist a similar queue in the model layer for the purposes of evaluating the expression when the equals button has been pressed.

  • 2
    While this question is not strictly a duplicate, my answer here to a similar question applies to this too: programmers.stackexchange.com/questions/257259/… – whatsisname Mar 24 '16 at 17:18
  • 4
    You should not design an application based on which design pattern you want to use. Your application needs should define what design pattern(s) you should use. You will often run into problems conceptually when you try to fit square pegs into circular holes if you attempt this with drastically different patterns/use cases. – enderland Mar 24 '16 at 17:26
  • In MVC, neither your View nor your Controller should really have any knowledge of your underlying application logic (in this case, your calculator logic). A View is for layout/colours/fonts/etc. A Controller is for Interactivity logic (e.g. enabling/disabling buttons, querying the view for data, or sending data to the view). As far as MVC is concerned, the Model (which may be a slightly misleading term) is a catch-all term meaning "the rest of your application logic". – Ben Cottrell Mar 25 '16 at 7:49
  • 1
    @dangerousdave: Entirely ignoring/misunderstanding what enderland said doesn't make enderland wrong. – Lightness Races in Orbit Mar 25 '16 at 14:07
  • 1
    @BarryTheHatchet - Are you suggesting that I should not endeavor to understand the command pattern by trying to actually use it? because the only way I see of doing this, short of stumbling upon a usecase, is contriving a usecase; which is what I have done. Furthermore, in my original question I state "my choice of application may not have been the ideal choice" even so, I don't believe this makes my attempt to learn any less valid. – dangerousdave Mar 25 '16 at 19:40
4

The problem you're describing is that the model needs to know the internal state of the controller. This is a symptom of a much bigger problem, namely: Most of the state that belongs in your model is not being stored in your model. The solution here is not to duplicate the controller's state inside the model or pass the controller into the model, but rather to move that state into the model.

A closely related problem is that you're trying to use commands to represent not-yet-performed mathematical operations, when you should really be using them to represent the orders the user is giving your calculator app. It may be counterintuitive, but when the user presses the * button on a calculator, they are not telling the calculator to multiply two numbers, they're actually telling it to add a multiplication symbol to the current expression.

Specifically, your model should contain a representation of the current expression, whether that's a single number like "123" or a complicated not-yet-evaluated expression like "3+4*90-8", and evaluating that expression should be its own command, separate from the commands to add a * and a 90 and a - and an 8 to the current expression.

For example, if your model is currently "123" and the user presses the * key, the model should be changed to "123*", the view should be told to update itself, and the undo/redo stacks should be given command objects that add and remove a *. Then when the user presses 4, the model should change to "123*4", the view should be told to update itself, and the undo/redo stacks should be given command objects that add/remove a 4. Finally, when the user presses =, the model should be told to evaluate its expression so it changes to "492", the view should be told to update itself, the undo stack should be given a command object that resets the current expression back to "123*4" and the redo stack should be given a command object that evaluates the current expression. This way, there's absolutely no need for the model to ever receive a reference to the controller or the view, and you only need one pair of undo/redo stacks in the controller.

Note that the model doesn't have to be a simple string as I just described. In practice it's often better to represent an expression like this as an AST and give the model a method that converts said AST to a string for the view to display. But for a very simple calculator app a string might be sufficient.

  • 1
    Perfect, thanks very much Ixrec, you addressed all my issues! – dangerousdave Mar 26 '16 at 17:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.