I enjoyed this chapter because of the example, an command-line RPN (Reverse Polish Notation) calculator. I still make regular use of my RPN-based HP-12C calculator, and it was cool to see how easy it was to implement a command-line RPN calculator using Cocoa’s dynamic creation pattern.
Motivation: “Decouple classes from each other and postpone decisions about which class to use until runtime. Provide a simple mechanism for overriding which classes are used for particular tasks within frameworks. Simplify the creation of plug-in architectures.”
Cocoa can dynamically create an object using the NSClassFromString() function. The class object it returns can be used to instantiate an object of that class, even if that class wasn’t known to the compiler when the program was linked.
The chapter demonstrates this pattern with a command-line RPN calculator. The book gives the core code for the calculator, namely classes for the stack, a generic command class, the parser (inside the main routine), and the implementation of two commands: print and add.
Modifying add to implement the other arithmetic options was trivial. It was also easy to work out the classes for the pi and dump commands (dump displays the entire stack). After that, I added the trig functions sine, cosine and tangent, but not their inverses (I heard dinner calling my name…).
Goofing around with the calculator will show that it doesn’t handle errors well. If you type a non-existent command, it will simply place that text on the stack (you can verify that with the dump command). If you then use the add command (or a plus sign), it will just drop the text. That’s convenient, but probably not the best way to handle things.
Non-trivial extensions for this calculator would be adding a mode to do trig operations in degrees or radians, and adding some formatting settings for printing results.
So is there any enthusiasm out there for taking this farther by adding modes, formatted printing, and error handling? I’ve spent a little time thinking about how to do the radians vs. degrees, and have come up with two ways of implementing it.
One involves keeping track of what state the calculator is in, and either (1) passing that state to the instance of the trig operation class, or (2) having the trig operation class query the main program about the state. (2) sounds better, since it doesn’t require as much effort on the part of the main parsing loop.
The other would involve two different classes for each trig function. It would more or less be the abstract factory pattern, with one factory creating degree mode classes and the other creating radian mode classes. That seems too much like “patterns for patterns sake” than good software design.
Any other suggestions out there?