CS231 lecture notes, Fall 1998 Week 8, Friday Process objects --------------- Until now, objects have been models of real-world things, and their methods have been operations we perform on those things. Another use of objects is to Encapsulate the state of an ongoing process. What do I mean by state? I mean all the information required to describe where we are in a process. For example, when you are reading a book, you use a bookmark to record the page you are on. That's all the information you need to resume where you left off. In translate, the state is: 1) the input string that we are processing 2) the index that indicates where in the string we are 3) the output StringBuffer 4) the stack of pending operations In evaluate, the state is: 1) the input string that we are processing 2) the index that indicates where in the string we are 3) the stack of Integers In Check.java (the paren-checker), the state is: 1) the stack of openers we have seen so far In each case, we can encapsulate the state in instance variables and create a PROCESS OBJECT. Each time you want to perform a translation, you would create a new Translator object. Each time you want to perform an evaluation, you would create a new Evaluator object. Each time you want to check an expression, you would create a new Checker object. For Translator and Evaluator, the advantages of this approach are mostly syntactic -- the code will be a little cleaner than the other two versions (using local and global variables). There is virtually no performance impact, except the cost associated with creating and collecting all the objects. For Checker, there is a real practical advantage. Remember that the checker only checks one line at a time, so the interface is likely to be something like this: public Checker (); create a new Checker public void checkLine (String line); parse a line of input public void endOfInput (); check the stack when we're done So a Checker lives for longer than one method invokation; we may invoke checkLine hundreds of times before invoking endOfInput. The nice thing about making Checker a process object is that we can have more than one check going on at a time, by invoking checkLine alternately on more than one Checker. What happens to Checker after we call endOfInput? 1) Nothing. It doesn't get garbage collected until all references go away. 2) As it turns out, we could reuse it, since we know that the stack will be empty again, and the stack contains all the state. Check out Checker, an example of a process object that is available from http://rocky.colby.edu/cs231/code/hw8/ Another example of a process object StringTokenizer --------------- (the following text is from the Sun java documentation page) http://java.sun.com/products/jdk/1.1/docs/api/java.util.StringTokenizer.html The string tokenizer class allows an application to break a string into tokens. The tokenization method is much simpler than the one used by the StreamTokenizer class. The StringTokenizer methods do not distinguish among identifiers, numbers, and quoted strings, nor do they recognize and skip comments. The set of delimiters (the characters that separate tokens) may be specified either at creation time or on a per-token basis. An instance of StringTokenizer behaves in one of two ways, depending on whether it was created with the returnTokens flag having the value true or false: If the flag is false, delimiter characters serve to separate tokens. A token is a maximal sequence of consecutive characters that are not delimiters. If the flag is true, delimiter characters are considered to be tokens. A token is either one delimiter character, or a maximal sequence of consecutive characters that are not delimiters. The following is one example of the use of the tokenizer. The code: StringTokenizer st = new StringTokenizer("this is a test"); while (st.hasMoreTokens()) { println(st.nextToken()); } prints the following output: this is a test