Object-Oriented Programming and Design
Final Exam, Fall 1999 Name:___________________________
(74 points - 7 pages)
The following might be names of patterns: Abstract Class, Abstract Factory, Adapter, Bridge, Builder, Chain of Responsibility, Collaborator, Composite, Decorator, Façade, Factory Method, Flyweight, Interpreter, Iterator, Mediator, Memento, Observer, Prototype, Proxy, Singleton, Specification, State, Strategy, Template Method, Visitor
Suppose you were designing a system for an insurance company that represents and processes insurance policies.
1. (2 points) An insurance policy can have many components, since it can have a part for a house, and a part for insuring a car. The part for insuring a house can have a part for insuring it against fire, a part for insuring it against flood, and a part for insuring it against theft. This can lead to a tree of components. Which pattern do you think about when a design requires a tree of components?
2. (2 points) A tree of components does not always (or even usually) use this pattern. What is an alternative to using this pattern?
3. (2 points) How do you know when you should use this pattern and when you should not? In other words, what are the conditions that tell you when this pattern is applicable?
4. (2 points) A system for approving insurance policies needs to keep track of the policy, the customer history, and the people who examine the policy and approve it. The software will only automatically approve the obvious insurance policies, and anything that is at all difficult will be routed to an expert to examine.
The rules for approving insurance policies and routing them to people for examination could be put in the policy, or they could be put in one of the other objects. But these rules change all the time. Most insurance systems use a particular pattern that encapsulates the rules in a separate object. This pattern promotes loose coupling by keeping the the insurance policies, the customer history objects, and the objects representing the workers at the insurance company from referring to each other It lets the way these objects interact vary without changing the objects. What pattern is it?
5. (2 points) A system for representing insurance policies has many classes in it, but you want to hide them from the application programmers and present a simpler interface to them so that they are easier to use. What design pattern lets you hide the complexity of a subsystem like an insurance system?
6. (2 points) Perhaps several people could be looking at an insurance policy at the same time. Changes that one makes should be immediately seen by the others. What design pattern would you probably use for this?
The purpose of many of the design patterns is to make it easy to change some property of the system. What design pattern would you use to make it easy to change:
7. (2 points) The class of the object that a method returns.
8. (2 points) The implementation of an abstraction.
9. (2 points) The algorithm that is being applied to a tree of objects, where the nodes in a tree are in many different classes.
10. (2 points) The internal state of an object, but you want to be able to remember this state and then later tell the object to go back to that state.
11. (10 points) Suppose there is a class Thingy with the following method
doSomething: anObject
flag
= #first ifTrue: [^self doFirstThing: anObject].
flag
= #second ifTrue: [^self doSecondThing: anObject].
flag
= #last ifTrue: [^self doLast: anObject].
self
error:'illegal option'
This looks like a case statement. This might be OK if flag came from user input, but you discover that it is assigned in several methods and is always one of the literals you see above. You notice that the doFirstThing method calls a private method removeAll and is the only place where removeAll is called. You notice that all three call a private method setUp. You decide to get rid of the case statement by using the Strategy pattern. Describe in detail what you would do. Show the new implementation of doSomething:for class Thingy.
12. (8 points) The following methods were taken from two classes, class A and class B, which had a common superclass C. C defines the instance variables socketStream and mySocket.
Refactor these methods to use the Template Method pattern. Show all the methods you would create.
Class A
startProcessing
| evaluateString result |
self sendWithCRLF: 'Hello from the server for ExecutionEngine 1!'.
evaluateString := socketStream through: Character cr.
result := (Compiler evaluate: evaluateString) printString.
self sendWithCRLF: evaluateString.
self sendWithCRLF: result.
socketStream close.
mySocket close
Class B
startProcessing
| evaluateString result |
self sendWithCRLF: 'Hello from the server for ExecutionEngine 2!'.
evaluateString := socketStream through: Character cr.
result := CharToCharEncoder encodeString: evaluateString.
self sendWithCRLF: evaluateString.
self sendWithCRLF: result.
socketStream close.
mySocket close
There are lots of ways to make streams in Smalltalk. For example,
ReadStream on: 'this is a string'
'input.txt' asFilename readstream
WordStream on: ('input.txt' asFilename readstream)
13. (2 points) The first two lines would return a stream of characters. But the third returns a stream of what? Note that there is not a standard class 'Word'.
14. (4 points) Show how you would use a stream to iterate over the elements of a collection. This is an example of the Iterator pattern. Streams are the "external iterator" variation.
15. (4 points) Most of the time you want to iterate over a collection in Smalltalk, you would use an "iternal iterator". Show a simple example of Smalltalk code that is using an internal iterator.
16. (4 points) Explain how WordStream is like the Decorator pattern. Explain how it is like the Adapter pattern. Which one do you think it is most like?
Composite Money
Suppose you had twenty US dollars and then you got twenty Canadian dollars. How much money would you have? The answer is not "forty dollars", because a US dollar and a Canadian dollar are different. The answer is "twenty US dollars and twenty Canadian dollars".
To keep track of currencies, it is best to have a Money class. To keep track of what happens when you put US and Canadian currency in the same pocket, we will make a CompositeMoney class. If you add two moneys with the same currency, you get a Money object. If you add two moneys with a different currency, you get a CompositeMoney.
17. (4 points) Is CompositeMoney a subclass of Money? Explain why or why not?
18. (2 points) What are the instance variables of Money?
19. (2 points) What are the instance variables of CompositeMoney?
Assume arithmetic is implemented using double-dispatching. Then the + method for Money is
+ anObject
^anObject sumFromMoney: self
and the + method for CompositeMoney is
+ anObject
^anObject sumFromCompositeMoney: self
20. (4 points) What is the sumFromMoney: method for class Money?
21. (4 points) What is the sumFromMoney: method for class CompositeMoney?
A CurrencyConversionTable knows the conversion rates of all currencies. It understands the message rateFrom:to: that returns the rate of converting from one currency to another. It also understands the to: message, which returns a CurrencyConverter that converts any currency to a particular currency. The CurrencyConverter just keeps track of the CurrencyConversionTable and the currency, so it is a simple class. The to: method of CurrencyConversionTable is
to:
aCurrency
^CurrencyConverter on: self to: aCurrency
CurrencyConverter has a from: method that is
from:
aMoney
^(conversionTable rateFrom: aMoney currency
to: currency) * aMoney
Money and CompositeMoney each have a convertedBy: method that takes a CurrencyConverter as an argument and returns the receiver converted by that converter. Note that convertedBy: always returns a Money.
22. (8 points) Show the convertedBy: method for class Money and CompositeMoney. Describe any assumptions you make.