Download presentation
Presentation is loading. Please wait.
1
Summary prepared by Kirk Scott
Chapter 25 Interpreter Summary prepared by Kirk Scott
7
Design Patterns in Java Chapter 25 Interpreter
Summary prepared by Kirk Scott
8
Introduction The interpreter design pattern is related to the command pattern The Interpreter design pattern can be used to make objects where the objects are like individual commands Different kinds of commands are implemented as different classes Each of these classes has a method of the same name, something like execute()
9
The difference in the command objects consists of the fact that the code for the execute() method differs among the different command classes In this respect the pattern is like lots of other patterns You have many different implementations of methods with the same name Polymorphism and dynamic binding sort out which version applies
10
The Interpreter pattern is also related to the composite pattern
A structured program consists of sequences of statements It can also contain macros or subroutines The macros or subroutines are collections of sequences of statements
11
A complete application of the Interpreter pattern will allow multiple commands to be put together into a composite Individual leaf items will be single statements and composite nodes will be (sub)sequences of statements
12
Book Definition of Pattern
The intent of the Interpreter pattern is to let you compose executable objects according to a set of composition rules that you define.
13
An Interpreter Example
The book illustrates the Interpreter design pattern with Oozinoz Robots transport material between machines Robots also load and unload the machines It will be possible to write programs that compose sequences of robot actions
14
The UML diagram on the following overhead shows a Robot class and a small hierarchy of commands
The command hierarchy is the same in structure as a composite hierarchy execute() is the method that the classes in the hierarchy have in common
16
execute() is abstract in the Command class at the top of the command hierarchy
It is concretely implemented in the two subclasses, CarryCommand and CommandSequence
17
The CarryCommand class has a constructor, which takes two machines as input parameters
There are corresponding instance variables for these references in the CarryCommand class The execute() method of CarryCommand will cause the material to be carried from one machine to the other by a robot
18
The CommandSequence class has an add() method for building up composite sequences of instructions
The execute() method of CommandSequence will cause the complete sequence of commands which it contains to be executed
19
What part of the UML diagram represents the interpreter?
The composite command hierarchy in its entirety is in essence the interpreter
20
Example Code that Uses the Classes Given so Far
The book does not start by showing the code for the command hierarchy It starts with the ShowIntepreter program, which uses the commands Several things happen in the program It obtains a machine composite object for the factory in Dublin, Ireland
21
It obtains three references to specific machines at the factory
It loads bins into the machines It construct two instances of CarryCommand using these machines as input parameters
22
It constructs an instance of CommandSequence and adds the individual commands
Finally, it calls execute() on the sequence object It is this one, final line of code which controls the robot/machines in the factory
23
In essence, the whole machine control program has been packaged up in the one object and the one call to the execute() method In other words, the interpreter pattern is illustrated by packaging a complete sequence of machine/robot commands in a single instance of the CommandSequence class The code is given on the following overhead
24
public class ShowInterpreter
{ public static void main(String[] args) MachineComposite dublin = OozinozFactory.dublin(); ShellAssembler assembler = (ShellAssembler) dublin.find("ShellAssembler:3302"); StarPress press = (StarPress) dublin.find("StarPress:3404"); Fuser fuser = (Fuser) dublin.find("Fuser:3102"); assembler.load(new Bin(11011)); press.load(new Bin(11015)); CarryCommand carry1 = new CarryCommand(assembler, fuser); CarryCommand carry2 = new CarryCommand(press, fuser); CommandSequence seq = new CommandSequence(); seq.add(carry1); seq.add(carry2); seq.execute(); }
25
Code for the CommandSequence Class
The code for the CommandSequence (composite) class will be given on the overhead following the next one The CommandSequence class has an ArrayList of commands The add() method allows commands to be added
26
The execute() method looks like the methods getMachineCount() and isTree() in the composite design pattern It iterates over all of the elements of the ArrayList calling execute() on them If the element is a leaf, then the version of execute() in the CarryCommand class is used If the element is a composite, then the call is recursive
27
public class CommandSequence extends Command
{ protected List commands = new ArrayList(); public void add(Command c) commands.add(c); } public void execute() for (int i = 0; i < commands.size(); i++) { Command c = (Command) commands.get(i); c.execute();
28
Code for the CarryCommand Class
The CarryCommand class has references to two machines It has a constructor that takes two machine references as input parameters It has an execute() method execute() calls carry() on the single instance of Robot maintained in the Robot class, passing the machine references as parameters to this method The code is shown on the following overhead
29
public class CarryCommand extends Command
{ protected Machine fromMachine; protected Machine toMachine; public CarryCommand(Machine fromMachine, Machine toMachine) this.fromMachine = fromMachine; this.toMachine = toMachine; } public void execute() Robot.singleton.carry(fromMachine, toMachine);
30
Adding Different Types of Commands to the Pattern
The Interpreter can be expanded by adding more subclasses to the Command hierarchy Each different command will package up a different action in its execute() method This generalizes the kind of program for machine control that the interpreter pattern can generate
31
In addition to the CarryCommand, there might be a StartUpCommand and a ShutDownCommand
In addition to simple commands, there might be commands that reflect the structure of a programming language This is where the complexity starts to set in
32
A “for” Looping Command
The tree-like structure of the composite makes it possible to model a macro or subroutine This is a sequence of commands which is run once when it’s called A complete programming language also allows iteration A loop consists of a sequence of commands which is potentially run more than once when it’s encountered
33
The book introduces the idea of a ForCommand into the Command hierarchy
The ForCommand class implements the logic of a for each loop The UML diagram for the expanded interpreter is shown on the next overhead It includes the StartUpCommand, ShutDownCommand, and ForCommand classes Explanations follow
35
The UML diagram shows an arrow from the ForCommand class to the Command class
An instance of ForCommand has a reference to a command that is the body of the for each loop It can be a single command or an instance of CommandSequence
36
Adding Variables to the Language Which the Interpreter Handles
Something that works like a for each loop depends on a variable You repeat the execution of the body You do this for a set of things or values in succession The loop variable takes on the values of the set of things that you’re iterating over
37
The syntax of a simple Java for each loop was given in Unit 9 of CS 202 with this example:
for(Cup7 someCup: mycollection) { myterminal.println(someCup); }
38
mycollection is an ArrayList of cups
someCup is a variable that is declared as part of the syntax of the loop It represents the single instance of mycollection that you refer to during a given iteration through the loop A variable that works like someCup will be needed to making the ForCommand work
39
The constructor for the ForCommand class will take 3 parameters:
1. A collection (tree) of machines, the objects to iterate over 2. Something typed as a variable, to hold the reference to a machine in the collection during the execution of the loop 3. A command (possibly composite), the body of the loop
40
Notice how the composite design pattern shows up twice
The command sequences in the interpreter themselves are composite like The structure we iterate over is taken directly from the discussion of composite We are iterating over a composite of machines
41
Adding Variables to the Interpreter
Adding variables to the interpreter is a significant change It will take several overheads to discuss variables before returning to the implementation of ForCommand The classes needed to include variables are shown in the UML diagram on the following overhead
43
What is a Term? The UML diagram has an abstract Term class at the top of the hierarchy The concrete classes under it are Variable and Constant Empirically, a term is either a variable or a constant More theoretically, terms are the things that the syntax of a programming language deals with
44
The system works with machines
Constants are objects with references to machines Variables are objects that have a name and have terms associated with them In essence, this means that a variable can have either the value of a constant or another variable assigned to it
45
The Constant Class The Constant class is basically a wrapper for a Machine reference A constant is constructed with a machine as the input parameter The Constant class has an equals() method, which tests to see whether two constants are (contain) the same machine
46
It also has an eval() method which is essentially like a get() method
This method returns a reference to whatever machine the constant happens to contain
47
The code for the Constant class is given on the following overhead
Most of the methods are straightforward I would observe that the coding style for the equals() method is somewhat like the orange book’s (and I don’t care for it)
48
public class Constant extends Term
{ protected Machine machine; public Constant(Machine machine) this.machine = machine; } public boolean equals(Object obj) if (obj == this) return true; if (!(obj.getClass() == this.getClass())) return false; Constant that = (Constant) obj; return this.machine.equals(that.machine);
49
public int hashCode() { return machine.hashCode(); } public Machine eval() return machine; public String toString() return machine.toString();
50
The Variable Class The Variable class has a String instance variable
This String is the name of the variable The Variable class also has a Term instance variable The class can be thought of as a wrapper for a Term reference The Variable class consists of a value and a name, and identifier, associated with it
51
The Term instance variable holds whatever value is assigned to the variable by a call to the assign() method A constant or the contents of another variable can be assigned to a variable in this way The variable class also has an eval() method This method returns the value of the Term that has been assigned to the variable
52
The Variable class has an equals() method
It is important to notice that equals() is not testing for equality of the values assigned to variables It is testing for whether or not the variables themselves are the same This is done by testing for equality of the names of variables
53
The code for the Variable class is given on the following overhead
The coding style for the equals() method is again not ideal
54
public class Variable extends Term
{ protected String name; protected Term value; public Variable(String name) this.name = name; } public String getName() return name; public void assign(Term term) this.value = term;
55
public boolean equals(Object o)
{ if (o == this) return true; if (!(o instanceof Variable)) return false; Variable v = (Variable) o; return name.equals(v.name); }
56
public int hashCode() { return name.hashCode(); } public Machine eval() return value.eval(); public String toString() return name + ": " + value;
57
Generalizing Simpler Commands by Using Terms
If you introduce variables, the whole language the interpreter implements will be affected The book isn’t ready yet to show the use of variables in the implementation of the ForCommand class First it shows how some of the simpler commands could be generalized by using references to terms
58
Commands can then be used with variables which refer to machines rather than with machine references themselves Whenever a term is used, it is resolved to a machine reference by calling eval() on it The CarryCommand class rewritten using terms is shown on the following overhead
59
public class CarryCommand extends Command
{ protected Term from; protected Term to; public CarryCommand(Term fromTerm, Term toTerm) from = fromTerm; to = toTerm; } public void execute() Robot.singleton.carry(from.eval(), to.eval());
60
On the next overhead, code for a StartUpCommand class is given which uses terms
The same approach is used as for the CarryCommand Whenever a term is used, it is resolved to a machine reference by calling eval()
61
public class StartUpCommand extends Command
{ protected Term term; public StartUpCommand(Term term) this.term = term; } public void execute() Machine m = term.eval(); m.startup();
62
What Do You Gain from Using Terms?
It’s not clear what you’ve gained by this since everything has to resolve to a machine The book’s first answer to this is the following: Suppose that machines come from vendors with a proprietary control language A fully-fledged machine control language would have variables
63
Suppose you want to integrate command sequences for different machines into overall Java programs
You would need to parse and interpret the proprietary command sequences If the proprietary machine control code has variables, the interpreter would also have to have variables
64
The second answer to the question is the following:
The overall goal is to have a ForCommand, which requires a variable Assuming that you’re going to have that more advanced use of a variable in the interpreter, it makes sense to consider the simpler basic case first
65
Writing the Code for the ForCommand Class
The motivation for introducing variables was the need to support looping The book now tackles the topic of how to write the ForCommand class Adding this to the interpreter is not trivial
66
The book presents partial code
The most difficult part of the implementation is reserved as a challenge As usual, rather than doing this as a challenge, the complete code will be given, broken up with explanations
67
An outline of the constructor for ForCommand was given earlier
It is repeated on the following overhead
68
The constructor for the ForCommand class will take 3 parameters:
1. A collection of machines, the objects to iterate over 2. Something typed as a variable, to hold the reference to a machine in the collection during the execution of the loop 3. A command, the body of the loop
69
The following overhead shows the instance variables and the constructor of the ForCommand class
There is an instance variable for each of the construction parameters The thing you’re iterating over is named root It is the root of a component/composite of machines
70
public class ForCommand extends Command
{ protected MachineComponent root; protected Variable variable; protected Command body; public ForCommand(MachineComponent mc, Variable v, Command body) this.root = mc; this.variable = v; this.body = body; }
71
The rest of the ForCommand class consists of two execute() methods
This pair of execute() methods follows the approach of the isTree() methods in the composite design pattern Client code will call the version of execute() without the parameter The version without the parameter will use the version with a parameter The code for these methods follows
72
Here is the execute() method that doesn’t take a parameter:
public void execute() { execute(root); }
73
It is possible to make the first call to execute() on an instance of ForCommand without having to pass in a parameter This is because the root is set at construction time
74
The version of execute() that does take a parameter is recursive
It contains a base, non-recursive case It also contains a recursive case It calls itself, the version with the parameter, in the recursive case In the recursive case, it passes in specific explicit parameter, the current child
75
Code for the execute() method with a parameter is given starting on the following overhead
Explanatory comments have been added The declaration line of the method is shown This is followed by a test of what kind of parameter was passed in On the overhead following the next one, the recursive case is shown
76
private void execute(MachineComponent mc)
{ /* Notice that for a change, the if will be matched with an else that will be given later. */ if (mc !instanceof Machine) /* If what you’ve reached isn’t a Machine, it’s a composite. */ MachineComposite comp = (MachineComposite) mc;
77
/* Iterate over the components in the composite. */
List children = comp.getComponents(); for (int i = 0; i < children.size(); i++) { MachineComponent child = (MachineComponent) children.get(i); /* Call this execute() method, the one defined in ForCommand. Pass in each component (child) in the list. You are looping. However, this is recursive because the thing you are looping over is a tree. You are traversing the tree. If the component you encounter is a Machine (leaf), the code will hit the base case. If the component is a Composite, it will hit this recursive case. The current child is passed because it’s the root of the new recursion. */ execute(child); }
78
The code for the execute() method with a parameter continues on the following overhead
The non-recursive, base case is shown Explanatory comments have been added
79
else { Machine m = (Machine) mc; /* Set the iterator variable to the individual Machine you’ve encountered. This is a critical step. It will only be possible to explain it after this code. */ variable.assign(new Constant(m)); /* Execute the body of the loop (once) for this individual machine. Note that the body could be any command. It could be another loop or any other command. In either case, the version of execute() called is one without a parameter. */ body.execute(); return; }
80
How the Looping Variable Works
The base case is where you’ve reached a leaf in the tree you’re iterating over This is where a single execution of the body of the loop occurs This is also where the loop variable appears Neither the loop variable nor the body appear in either the parameter-less execute() method or in the recursive case of the one with a parameter
81
Concretely, this is how the variable takes on the value of the current, leaf object that you’ve iterated to: variable.assign(new Constant(m)); The variable object is constructed in client code and passed in as a construction parameter to the ForCommand object The object that “variable” refers to exists independently of ForCommand and is merely being assigned a particular value here
82
Concretely, this is how the body of the loop is executed:
body.execute(); The burning question is this: What is the connection between the leaf object that you’ve reached during iteration and the execution of the body? The execution of the body should depend on the leaf. If the execution of the body doesn’t depend on the leaf, then you would just be executing exactly the same body statements x times, where x is the number of leaves in the tree you’re iterating over
83
There should be and is a connection between the variable and the body
It comes in the client code, not in the ForCommand code Recall that a ForCommand object is constructed with a root, a variable, and a body The body itself is constructed with a reference to the variable
84
This only becomes apparent when you reach the book’s next example, which illustrates the use of ForCommand Look at the third parameter, the construction of the body, in the construction of the ForCommand: Command c = new ForCommand(dublin, v, new ShutDownCommand(v));
85
Recall that originally the ShutDownCommand took a machine as its construction parameter
It was then rewritten to take a variable as its construction parameter Either way, this is the way it works: You call execute() without a parameter on a ShutDownCommand object, and it shuts down the machine that it was constructed with
86
Look at the lines of code in the sequence in which they would be run:
In the client: Command c = new ForCommand(dublin, v, new ShutDownCommand(v)); In the base case of ForCommand: variable.assign(new Constant(m)); body.execute(); The effect is that the execution of the body will shut down the machine that you are currently on in the iteration
87
What is going on is not very easy to see
v is passed into ShutDownCommand, but a reference to v is saved and passed on to ForCommand Then in ForCommand, a value is assigned to v In effect, an instance variable belonging to a ShutDownCommand object is having its value changed without calling a set method on the object
88
In a sense, encapsulation is being violated
You are passing around a reference to an instance variable belonging to a particular object Another way of looking at the situation is that ShutDownCommand and ForCommand share an instance variable
89
From the perspective of the design pattern, it is not so much that ShutDownCommand and ForCommand share an instance variable— They do share a variable The ForCommand has an iteration variable It takes on the values being iterated over, in succession As it takes on these values, by reference, the values belonging to the body command these values
90
In any case, this apparent violation of encapsulation is intentional
It makes it possible for the design pattern to do what it’s supposed to do But the code is hard to understand, and for that reason, potentially dangerous
91
An Alternative? It might be possible to treat v as inherently part of the body object Then in the ForCommand code, you could call a set method for v on that object rather than changing the value of a passed reference At that point, it may not be necessary to keep v as an instance variable in ForCommand
92
An Example Program that Uses ForCommand
The book next gives the complete little program that uses the ForCommand , which the single line of code given previously was taken from The ForCommand iterates over all of the machines in the factory The body of the loop consists of a call to a ShutDownCommand with the current machine as its parameter The code is given on the next overhead
93
public class ShowDown { public static void main(String[] args) MachineComposite dublin = OozinozFactory.dublin(); Variable v = new Variable("machine"); Command c = new ForCommand(dublin, v, new ShutDownCommand(v)); c.execute(); }
94
The previous example is mainly just a reminder of the power of iteration
However, it also serves the purpose of beginning to illustrate the power of the Interpreter design pattern Instead of having to hand code the shutdown of every machine, it is possible to do this by constructing and executing a single instance of the ForCommand class
95
Adding More Control Commands
Continuing with the development of the Interpreter design pattern: An interpreter would become even more complete by adding commands like IfCommand and WhileCommand which are additional constructs of high level languages Both of these constructs require the ability to test a condition that will give a boolean result
96
The book hints that the way to do this might be to develop a new hierarchy of boolean classes
However, the authors opt to put the new classes into the Term hierarchy they already introduced It’s hard to say which alternative is better
97
The book’s approach has the obvious advantage of not requiring that a new hierarchy be developed
It also has the apparent disadvantage that the classes in the hierarchy don’t necessarily seem related However, it does work because the new classes will be based on an eval() method, and that’s the method that Variable and Constant classes were based on
98
boolean results will be modeled using this technique:
The eval() method will be typed to return a reference to a machine If eval() returns null, this will signify false If eval() returns a reference to an actual machine, that will signify true
99
The UML diagram on the next overhead shows the new Term hierarchy with an Equals and a HasMaterial class added to it Note that there is a small, potentially confusing mistake in the diagram There appears to be an equals() method in the class This is the constructor They forgot to capitalize it
101
The Equals Class The Equals class has a constructor that takes in two terms as parameters The eval() method doesn’t take in any parameters The eval() method of the Equals class uses the eval() method of the Term class to convert its instance variable terms to machine references
102
It then uses the equals() method of the Machine class to test for equality
It returns the reference to the first machine if the two machines are equal, and returns null if they’re not equal The code is shown on the following overhead
103
public class Equals extends Term
{ protected Term term1; protected Term term2; public Equals(Term term1, Term term2) this.term1 = term1; this.term2 = term2; } public Machine eval() Machine m1 = term1.eval(); Machine m2 = term2.eval(); return m1.equals(m2) ? m1 : null;
104
The HasMaterial Class The HasMaterial class has a constructor that takes in one Term as a parameter and initializes an instance variable named term The eval() method doesn’t take in any parameters It uses the eval() method of the Term class to convert its instance variable term to a machine reference
105
It then uses the hasMaterial() method of the Machine class to see whether the machine has any material It returns the reference to the machine if it has material, and returns null if it doesn’t The code is shown on the following overhead
106
public class HasMaterial extends Term
{ protected Term term; public HasMaterial(Term term) this.term = term; } public Machine eval() Machine m = term.eval(); return m.hasMaterial() ? m : null;
107
The NullCommand Class If you’re going to have if statements, it is helpful to also have a null command This represents the situation where you have either an empty if or an empty else In practice, this is just a command where the execute() method itself is empty Code for a NullCommand class is shown on the next overhead
108
public class NullCommand extends Command
{ public void execute() }
109
If and While With boolean conditions modeled, it’s possible to add an IfCommand and a WhileCommand to the Command hierarchy The UML diagram on the next overhead shows this Note that just like with ForCommand, IfCommand and WhileCommand have a reference to another command This other command will be the body of the if statement or the while statement, respectively
111
The IfCommand Class The book does the completion of the code for the IfCommand, and the entirety of the code for the WhileCommand as challenges As usual, it’s easiest not to bother with incomplete code and to go directly to the challenges and their solutions
112
Challenge 25.2 Complete the code in the execute() method of the IfCommand class. Solution 25.2 One solution is: [See the complete code on the following overhead.]
113
public class IfCommand extends Command
{ protected Term term; protected Command body; protected Command elseBody; public IfCommand(Term term, Command body, Command elseBody) this.term = term; this.body = body; this.elseBody = elseBody; } public void execute() if (term.eval() != null) body.execute(); else elseBody.execute();
114
The WhileCommand Class
Challenge 25.3 Write the code for the WhileCommand class. Solution 25.3 One way to write WhileCommand.java is: [See the code on the following overhead.]
115
public class WhileCommand extends Command
{ protected Term term; protected Command body; public WhileCommand(Term term, Command body) this.term = term; this.body = body; } public void execute() while (term.eval() != null) body.execute();
116
Once you start getting used to the Interpreter design pattern, the code for these command classes doesn’t seem too difficult The execute() method “wraps” the logic for if and while, using terms and bodies as stand-ins for whatever actual items and actions come from the problem domain
117
The IfCommand is simple because no variable is involved
The WhileCommand appears simple because no variable is involved, but it has complexity similar to that in ForCommand Execution of the body has to have some effect on the Term; otherwise, the value of the looping condition would never change
118
An example of the use of WhileCommand will be given next
As with ForCommand, the connection between the looping elements is made in the client code, not the WhileCommand code
119
Using the WhileCommand Class
The code for the ShowWhile program is given on the following overhead It uses the WhileCommand Its logic is that while the star press has material, that material will be carried to the fuser
120
public class ShowWhile
{ public static void main(String[] args) MachineComposite dublin = OozinozFactory.dublin(); Term starPress = new Constant((Machine) dublin.find("StarPress:1401")); Term fuser = new Constant((Machine) dublin.find("Fuser:1101")); starPress.eval().load(new Bin(77)); starPress.eval().load(new Bin(88)); WhileCommand command = new WhileCommand( new HasMaterial(starPress), new CarryCommand(starPress, fuser)); command.execute(); }
121
The connection between the term and the body can be seen in the line of code where the WhileCommand is constructed The parameters for that construction are themselves constructed in place The connection consists of the fact that both the term and the body take the star press as their construction parameter This is shown on the following overhead
122
This is the construction of the WhileCommand
WhileCommand command = new WhileCommand( new HasMaterial(starPress), new CarryCommand(starPress, fuser)); This is what happens when the WhileCommand is executed: public void execute() { while (term.eval() != null) body.execute(); }
123
Execution of the body means execution of the carry command
Carrying material should eventually remove all material from the start press At that point, term.eval() will return null (false)
124
The Difference Between Command and Interpreter
Challenge 25.4 Close this book and write down a short explanation of the difference between Command and Interpreter.
125
Solution 25.4 One answer is: The intent of the Interpreter pattern is to let you compose executable objects from a hierarchy of classes that provide various interpretations of a common operation. The intent of Command is merely to encapsulate a request in an object
126
Solution 25.4, cont’d. Can an interpreter object function as a command? Sure! The question of which pattern applies depends on your intent. Are you creating a toolkit for composing executable objects, or are you encapsulating a request in an object?
127
Comment mode on: I would summarize my own answer in this way: If you are trying to build up a hierarchy of command classes that wrap a set of programming language constructs, then you’re using the Interpeter design pattern If you are trying to wrap a single command for one-shot use, then you’re using the Command pattern
128
Why Use the Interpreter Pattern?
The point of using the interpreter pattern may not be clear Why not just write the code for machine and robot control programs? The book’s scenario is as follows You may have a simple high-level language that was designed for machine and robot control
129
The book gives this as a pseudo-code example of a program in that language:
for(m in factory) if(not(m is unloadBuffer)) ub = findUnload for m while(m hasMaterial) carry(m, ub)
130
Then, in theory, you could write a parser program that took machine control programs as input and created interpreter objects as output In other words, you wouldn’t have to handcode a program like ShowInterpreter; the parser would do it for you
131
Of course, this added step is not simple
The reality is that the task of writing a parser that would translate into interpreter objects would be far from trivial Once you realize that a parser would be needed before the pattern could be profitably employed, you’re back to wondering how useful the pattern is
132
If you did have the parser, the benefit you would gain is that users would not have to code in Java
They could code in the machine control language and the parser/interpreter combination would produce Java programs that implemented the machine control programs written by users
133
Another Example The UML diagram on the following overhead is intended to serve as a definition of a simple assembly language A program in the language consists of a sequence (an ArrayList) of commands The commands consist of things like moves, arithmetic, and jumps This visual definition is based on the ideas of composite and interpreter used in this unit
135
Lasater’s UML Lasater’s diagram is shown on the following overhead
To its advantage, it does show a context, or client It focuses on those types of commands that have references to other commands, to the exclusion of simple commands All in all, I prefer the diagrams of the book’s examples
137
Summary The Interpreter design pattern is based on a hierarchy of command classes The names of the command classes suggest what it is they do Each class implements an execute() method The implementation should correspond to the name of the class
138
The class constructors should take the needed input parameters
The execute method should then work on instance variables and not need input parameters Some of the commands will be simple actions Another (composite) command will make it possible to compose multiple simple commands into a sequence
139
The interpreter design pattern may be accompanied by a hierarchy that defines terms for variables, booleans, etc. This will support the addition of things like for, if, and while commands In order to be practical, interpreters may also be used along with parsers, although how parsing works wasn’t really covered in the chapter
140
The End
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.