






Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
Material Type: Exam; Professor: Foster; Class: PROG LANG TECH & PDGMS; Subject: Computer Science; University: University of Maryland; Term: Spring 2005;
Typology: Exams
1 / 10
This page cannot be seen from the preview
Don't miss anything!







Programming Language Technologies and Paradigms Spring 2005
March 17, 2005
This exam contains 10 pages, including this one. Make sure you have all the pages. Write your name on the top of this page before starting the exam. Write your answers on the exam sheets. If you finish at least 15 minutes early, bring your exam to the front when you are finished; otherwise, wait until the end of the exam to turn it in. Please be as quiet as possible. If you have a question, raise your hand. If you feel an exam question assumes something that is not written, write it down on your exam sheet. Barring some unforeseen error on the exam, however, you shouldn’t need to do this at all, so be careful when making assumptions. You may avail yourself of the punt rule. If you write down punt for any part of a question with a specifically-assigned point value, you will earn 1/5 of the points for that question (rounded down).
Question Score Max
Question 1. Short Answer (25 points).
a. (5 points) Compare and contrast interfaces and abstract classes.
Answer: Interfaces specify method names and their types, but do not include any code or fields. A class may implement many interfaces. An abstract class, on the other hand, can contain some methods with code, as well as some abstract methods with no code. A class may only extend one other class, including at most one abstract class. In some sense, an interface is like an abstract class that contains only abstract methods.
b. (5 points) Explain why it’s almost always a bad idea to use the String(String) constructor to create a new String object.
Answer: Because Strings are immutable, it’s safe to share objects that represent the same string. Using the String(String) constructor prevents sharing and thus wastes space to little or no benefit.
c. (5 points) Explain the difference between the declared and actual type of a variable. Which one is used in dynamic dispatch?
Answer: The declared type of a variable is the type it’s given in the source code at compile time. The actual type of a variable is its run-time type, which is fixed at object creation time. An object’s actual type is used when determining which method to invoke in dynamic dispatch.
Question 2. Refactoring (25 points). a. (15 points) In class we described a number of bad smells in code that suggest the need for refactoring. For each of the following bad smells, state which of the following refactorings you would use to “deodorize” them, and explain your answer: Pull Up, Extract Method, Introduce Parameter Object, Extract Class, and Replace Temp with Query. You may use zero, one, or more than one refactoring per smell, and you may or may not use all of the above refactorings.
i. (5 points) B and C are both immediate subclasses of A, and buried in the code for methods B.foo() and C.bar() is a section of identical code.
Answer: The problem here is duplicate code. First, pull out the identical sequences of code into identical methods using Extract Method. Then, apply Pull Up to move the identical method into class A.
ii. (5 points) Method foo() has 16 parameters.
Answer: The problem here is having a large number of parameters. Use Introduce Parameter Object to group several of foo()’s parameters that are logically associated, and thereby reducing the number of parameters to foo().
iii. (5 points) Method foo() is 2000 lines long.
Answer: The problem here is having a (much, much too) long method. Use Extract Method to pull out logical chunks of code into other methods, and use Replace Temp with Query to replace some intermediate computations with method calls to reduce the size of the method. Several people recommended using Extract Class, but while that could help the design of the code it would not help reduce the number of lines of foo().
b. (10 points) For each of the following two refactorings, describe any circumstances in which the refactoring is not safe, or argue that the refactoring is always safe.
i. (5 points) Encapsulate Downcast. Change a method that returns an Object that is downcast by the caller so that the downcast happens in the function. Example:
Object lastReading() { return readings.lastElt(); }
Reading lastReading() { return (Reading) readings.lastElt(); }
Answer: The intended answer is that this change is in general safe, since all clients expecting an Object can be given a subclass instead, with no change. However, due to the way the question was worded you could also argue it’s not safe if there are different types of elements in readings. In either case, the refactoring also cannot be done if a parent or child class has a different version of lastReading that can’t be changed in the same way.
ii. (5 points) Change Inner Class to Outer Class. Pull a static inner class out of an encapsulating outer class. Example (the right-hand code is in two files):
class ObjStack { static class Node { Object elt; Node next; Node(Object o, Node n) { elt = o; next = n; } ... }
class ObjStack { ... } class Node { Object elt; Node next; Node(Object o, Node n) { elt = o; next = n; } }
Answer: Because the inner class is static, it can be pulled out without worrying about holding a pointer to the enclosing class. However, if there are any private static fields of the outer class that are accessed by the inner class then we cannot perform the refactoring without making those classes public or protected. Also, we cannot perform this refactoring if its name conflicts with another class. Finally, if the inner class was private, then making it an outer class will render it publicly visible.
a. (15 points) The addShape method on the previous page has exactly three errors in it. Write a JUnit class (just like in Project 2) that has three test methods that catch all the errors in addShape. Each test case should find exactly one error (they do not overlap). You may use any assertX method you choose (e.g., assertTrue). You may use other ShapeBuffer methods not listed in your tests, though you don’t need to, and you may use setUp and or tearDown.
public class ShapeBufferTestCase extends TestCase {
// FILL IN public void test1() throws Exception { ShapeBuffer sb = new ShapeBuffer(); int id = addShape(0, new Integer(0)); assertTrue(id == 1); }
public void test2() throws Exception { ShapeBuffer sb = new ShapeBuffer(); try { addShape(0, null); } catch (InvalidShapeException e) { return; } assertTrue(false); }
public void test3() throws Exception { ShapeBuffer sb = new ShapeBuffer(); try { for (int i = 0; i < sb.MAX CAPACITY; i++) addShape(0, new Integer(3)); } catch (OverflowException e) { return; } assertTrue(false); } }
b. (5 points) Do your tests above cover all statements in the addShape method? Justify your answer.
Answer: Yes, every statement is covered. The only statements that might not be covered are the assignments to minZ and maxZ, which are guarded by an if. However, upon adding any shape to an empty buffer (e.g., in test1), both of these statements will be executed.
Question 4. Design Patterns (30 points). In this question, you will implement the rock-paper-scissors game using double-dispatch (part of the Visitor pattern). In this game, two players secretly choose rock, paper, or scissors and then reveal their choice simultaneously. If the two players choose the same item, they tie. Otherwise, rock beats scissors, paper beats rock, and scissors beats paper. Below we’ve provided you with a main method that runs one round of the game. This method creates instances of the classes named on the command line and calls the accept method from the Choice interface. c0.accept(c1) should return -1 if c0 loses to c1, 0 if they tie, and 1 if c0 beats c1.
public interface Choice { int versus(Rock r); int versus(Paper p); int versus(Scissors s);
int accept(Choice c); // Returns -1 if this loses to c, 0 if it ties c, 1 if it beats c }
public class Main { public static Choice toChoice(String s) { if (s.equals("Rock")) return Rock.INSTANCE; else if (s.equals("Paper")) return Paper.INSTANCE; else if (s.equals("Scissors")) return Scissors.INSTANCE; else throw new IllegalArgumentException(); }
public static void main(String[] args) { Choice c0 = toChoice(args[0]); Choice c1 = toChoice(args[1]);
int result = c0.accept(c1);
System.out.print(c0.toString()); switch (result) { case -1: System.out.print(" loses to "); break; case 0: System.out.print(" ties "); break; case 1: System.out.print(" beats "); break; } System.out.println(c1.toString()); } }
b (15 points). Suppose that we want to implement a game with the same three items as part (a) but alternate rules. For example, we may want paper to beat scissors, scissors to beat rock, and rock to beat paper. We’d like to use the same Choice interface but have two sets of possible implementations: PlainRock, PlainPaper, and PlainScissors for the normal rules, and BizarroRock, BizarroPaper, and BizarroScissors for our new rules. Below, draw a UML diagram showing this design using the Abstract Factory pattern. We’ve given you a head start. You should still use the Singleton pattern as well, so that there is exactly one instance each of PlainRock etc. You can use PR as an abbreviation for PlainRock, etc to save on writing. You should show all classes in your diagram, but you need only provide as much detail in methods and fields as necessary for an intelligent programmer to figure out what’s happening. In particular, you don’t need to write pseudocode for every factory method—one will do. And you don’t need to list all the methods of a class if they’re just the ones shown in a superclass/interface. (So, for example, we don’t list the methods of Rock below.) You also don’t need to show pseudocode for the versus or accept methods, since you wrote those in part (a). Use underlining to indicate abstract classes and interfaces. Finally, describe how the Main class will need to change to accommodate this design, assuming that which rules to use (Plain or Bizarro) is specified somehow on the command line.
Choice versus(Rock) versus(Paper) versus(Scissors) accept(Choice)
Rock Paper
Scissors
PlainRock INSTANCE
BizarroRock INSTANCE
PlainPaper INSTANCE
BizarroPaper INSTANCE
PlainScissors INSTANCE
BizarroScissors INSTANCE
ChoiceFactory makeRock() makePaper() makeScissors()
PlainFactory makeRock() ...
BizarroFactory ...
return PlainRock.INSTANCE
Answer: Instead of accessing the INSTANCE fields directly, toChoice will now need to invoke the makeX methods of the appropriate factory according to the command line arguments.