![Page 1: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/1.jpg)
Java Generics – Chapter 9: Design patterns/*** INF329 - Spring 2007* Presented by Stian Stokkenes* [email protected]*/ {
![Page 2: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/2.jpg)
2
Chapter 9 - Design patterns• Goal: Show how design patterns can take advantage of
Java generics• Viewing the following patterns:
– Visitor pattern– Interpreter pattern– Function pattern– Strategy pattern– Subject- / Observer pattern
![Page 3: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/3.jpg)
3
9.1 – Visitor pattern• Data structure often defined by case analysis and
recursion• A binary tree of type Tree<E> is
– A leaf containing a single value of type E– A branch containing a left and a right sub tree of types E
• Represented in OO language by abstract class– Each case by subclass– Abstract class declares abstract method for all possible
operation– Subclasses implements the methods
![Page 4: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/4.jpg)
4
ex.1 – Simple tree and clientabstract class Tree<E>{
abstract public String toString();abstract public double sum();public static <E> Tree<E> leaf(final E e){
return new Tree<E>(){public String toString(){return e.toString();}public Double sum(){return ((Number)e).doubleValue();}
};}public static <E> Tree<E> branch(final Tree<E> l, final Tree<E> r){
return new Tree<E>(){public String toString(){
return “(“+l.toString()+”^”+r.toString()+”)”;}public Double sum(){return l.sum() + r.sum();}
};}class TreeClient{
public static void main(String[] args){Tree<Integer> t = Tree.branch(Tree.branch(Tree.leaf(1),
Tree.leaf(2)),Tree.leaf(3));assert t.toString().equals(“((1^2)^3)”);assert t.sum() == 6;
}}
}
![Page 5: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/5.jpg)
5
9.1 – Visitor pattern• Difficult to know all operations required on data
structure– Different developers responsible for definition classes and
client classes of the definition classes
• Visitor pattern -> possible to provide new operations without modifying the classes that defines the data structure– Abstract class declares visit method. Visitor as argument– Visitor implements interface that specifies one method for
each case in the specification of the structure– Subclasses implement visit method by calling method of the
visitor for the corresponding case.
![Page 6: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/6.jpg)
6
ex.2 – Tree with visitorsabstract class Tree<E> {
public interface Visitor<E, R>{public R leaf(E elt);public R branch(R left, R right);
}public abstract <R> R visit(Visitor<E, R> v);public static <T> Tree<T> leaf(final T e){
return new Tree<T>(){public <R> R visit(Visitor<T, R> v){return v.leaf(e);}
};}public static <T> Tree<T> branch(final Tree<T> l, final Tree<T> r){
return new Tree<T>(){public <R> R visit(Visitor<T, R> v){
return v.branch(l.visit(v), r.visit(v));}
};}
}
![Page 7: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/7.jpg)
7
9.1 – Visitor pattern• Abstract class Tree<E> only one abstract method• Interface Visitor<E, R> specifies two method
– leaf• Accepts a value of type E• Returns value of type R
– branch • Accept two values of type R• Returns value of type R
• Subclasses implements visit– leaf
• by invoking leaf method of visitor on element in leaf– branch
• By invoking branch method of visitor of the visitor on the result of recursive calls of the visitor on the left and right subtrees.
![Page 8: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/8.jpg)
8
9.1 – Visitor pattern• Without generics
– each visitor would have to return a result of type Object– many additional casts would be required– visitors often designed to not return a value– result often accumulated in variable local to visitor– complicating flow of data through the program
• With generics – each visitor has two type parameters
• One for the element type of the tree• One for the return type of the visitor
![Page 9: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/9.jpg)
9
ex.3 – Client with visitorsclass treeClient {
public static <T> String toString(Tree<T> t){return t.visit(new Tree.Visitor<T, String>(){
public String leaf(T e){ return e.toString(); }public String branch(String l, String r){
return “(“ + l + ”^” + r + ”)”; }
});}public static <N extends Number> double sum(Tree<N> t){
return t.visit(new Tree.Visitor<N, Double>() {public Double leaf(N e){ return e.doubleValue(); }public Double branch(Double l, Double r){ return l+r; }
});}public static void main(String[] args){
Tree<Integer> t = Tree.branch(Tree.branch(Tree.leaf(1),Tree.leaf(2)),Tree.leaf(3));
assert toString(t).equals(“((1^2)^3)”);assert sum(t) == 6;
}}
![Page 10: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/10.jpg)
10
9.1 – Visitor pattern• Sum method more precise with visitors• With simple trees
– Sum need type signature to indicate that it works on any element type
– Requires cast to convert leaf to Number– Class cast error is raised at run time if sum invoked on tree
without numbers
• With visitors– Sum method may have type signature that indicate it works
only on elements that are numbers• No cast required• Type error reported at compile time
![Page 11: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/11.jpg)
11
9.2 – Interpreter pattern• One use of trees is to represent expressions in a
programming language– Represented by abstract class– Each expression represented by subclass– Abstract method to evaluate an expression– Each subclass implements the method as appropiate for the
coreresponding expression
• With generics– Possible to parameterize expression type by type of
expression, e.g. Exp<Integer>, Exp<Pair<Integer, Integer>>
![Page 12: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/12.jpg)
12
ex.4 – Interpreter with genericsclass Pair<A,B> {
private final A left;private final B right;public Pair(A l, B r){ left = l; right = r;}public A left(){ return left; }public B right(){ return right; }
}abstract class Exp<T> {
abstract public T eval();static Exp<Integer> lit(final int i){
return new Exp<Integer>(){ public Integer eval(){ return i; }};}static Exp<Integer> plus(final Exp<Integer> e1, final Exp<Integer> e2){
return new Exp<Integer>(){ public Integer eval(){return e1.eval()+e2.eval();
}}; }static <A, B> Exp<Pair<A,B>> pair(final Exp<A> e1, final Exp<B> e2){
return new Exp<Pair<A, B>>(){ public Pair<A, B> eval(){return new Pair<A,B>(e1.eval(),e2.eval());
} };}static <A, B> Exp<A> left(final Exp<Pair<A, B>> e){
return new Exp<A>(){ public A eval() { return e.eval().left();} };}static <A, B> Exp<B> right(final Exp<Pair<A, B>> e){
return new Exp<B>(){ public B eval() { return e.eval().right();} };}public static void main(String[] args){
Exp<Integer> e = left(pair(plus(lit(3),lit(4)),lit(5)));assert e.eval() == 7;
}}
![Page 13: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/13.jpg)
13
9.2 – Interpreter pattern• In example:
– Integer literal of type Exp<Integer>– Sum expression of type Exp<Integer>,
• with two sub expressions of type Exp<Integer>– Expression to construct pair of type Exp<Pair<A, B>>
• with two sub expressions of type Exp<A> and Exp<B>– Expression to select the left component of a pair of type
Exp<A>• with subexpression of type Exp<Pair<A, B>>
– Expression to select the left component of a pair of type Exp<B>
• with subexpression of type Exp<Pair<A, B>>
![Page 14: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/14.jpg)
14
9.3 – Function pattern• Converts an arbitrary method into an object• Relation between an function and the corresponding
method similar to relation between Comparator and compareTo method
• Generic version demonstrate how to use type variable in throws clause of a method declaration.– Useful when different instances of a class contain methods
that may be useful when different instances of a class contain methods that may raise different checked exceptions
• See example 5.
![Page 15: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/15.jpg)
15
9.3 – Function pattern• Example defines class, Function <A, B, X>, which
represent a function– Class contains abstract method, apply
• Accepts argument of type A• Returns result of type B• May throw exception of type X
– Class contains applyAll method• Accept argument of type List<A>• Returns result of type List<B>• May throw exception of type X• Invokes apply on each element in argument list to produce
result list
![Page 16: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/16.jpg)
16
9.3 – Function pattern• Main method defines three objects
1. length of type Function<String, Integer, Error>– Accepts String– Returns integer (Length of given String)– Since it raises no checked exceptions, the third is set to error (Could be
set to RuntimeException)2. forName of type
Function<String, Class<?>, ClassnotFoundException>– Accepts String– Returns a class named by given String– Apply may throw ClassNotFoundException, which is given as the
third parameter3. getRunMethod of type Function<String, Method, Exception>
– Accepts String– Returns a method named run in the class named by the given String– Body of the method might raise a ClassNotFoundException or
NoSuchMethodException, so third parameter is taken to be Exception.
![Page 17: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/17.jpg)
17
9.3 – Function pattern• Last example shows chief limitations of giving
generics types to exception– Often no suitable class or interface that contains all
exceptions the function may raise.– Forced to fall back on Exception
• To general to provide useful information
![Page 18: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/18.jpg)
18
9.3 – Function pattern% Typical run of code in example 5:
% java Functions java.lang.Thread java.lang.Runnable[16, 18][class java.lang.Thread, interface java.lang.Runnable][public void java.lang.Thread.run(), public abstract void java.lang.Runnable.run()]
% java Functions java.lang.Thread java.util.List[16, 14][class java.lang.Thread, interface java.util.List]java.lang.NoSuchMethodException: java.util.List.run()
% java Functions java.lang.Thread Inf329[16, 6]java.lang.ClassNotFoundException: Inf329java.lang.ClassNotFoundException: Inf329
![Page 19: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/19.jpg)
19
9.4 – Strategy pattern• Used to decouple a method from an object
– Allowing to supply many possible instances of the method
• Illustrated by considering how tax payers may apply different tax strategies– A hierarchy for tax payers and a related hierarchy for tax
strategies• One default strategy applies to any tax payer• One subclass of tax payer is a trust• One subclass of default strategy applies only to trust
![Page 20: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/20.jpg)
20
9.4 – Strategy pattern• Example illustrate use of type variables with
recursive bounds– Applied to clarify the connection between tax payer and
associated tax strategies
• Example also illustrate use of getThis, which allows programmer to assign more precise type to this when type variables with recursive bounds appear
• See example 6.
![Page 21: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/21.jpg)
21
9.4 – Strategy pattern• Generics allows
– programmer to specialize a given tax strategy to a given type of tax payer
– compiler to detect when a strategy is applied to the wrong type of tax payer
– e.g trustStrategy.computeTax(person); //compile-time error
• Without generics computeTax would have to accept an argument of type TaxPayer and cast it to trust, and exception would be thrown at run-time
![Page 22: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/22.jpg)
22
9.4 – Strategy pattern• Example illustrates structuring technique of parallel
class hierarchies– One class hierarchy consist of TaxPayer, Person and Trust– A parallel class hierarchy consist of strategies corresponding
to each off these• DefaultTaxStrategy and DodgingTaxStrategy apply to any
Taxpayer• No specialized strategy apply to Person• TrustTaxStrategy specialized for Trust
![Page 23: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/23.jpg)
23
9.4 – Strategy pattern• Usually, some connection between such parallel
hierarchies– In this case, computeTax method for a TaxStrategy that is
parallel to a given Taxpayer expects an argument that is of the corresponding type
– e.g. computeTax method for TrustTaxStrategy expects argument of type Trust
• With generics, this connection can be captured in the types themselves– e.g. TaxStrategy<P> expects an argument of type P, where
P must be subclass of TaxPayer– By using this technique, generics can often be used to
capture similar relations in other parallel hierarchies
![Page 24: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/24.jpg)
24
9.4 – Strategy pattern• In example, instead of this we use a method called getThis
– Used because this doesn’t have type P– e.g. Person extends TaxPayer<Person>, so P is the same as
Person within the class– In fact, this will have the same type as P, but the compiler doesn't
know that – Returns the same value as this, but gives it the type P
• Declared abstract in the base class– Because it declares the type for getThis, but doesn't declare the
body– Body declared in the final subclasses Person and Trust
• Useful in situations whenever one wants to use this in the base type with more specific type provided by the type parameter
![Page 25: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/25.jpg)
25
9.5 – Subject-Observer pattern• Like strategy pattern, the Subject-Observer (SO)
pattern uses parallel class hierarchies, but requires two type variables with recursive bounds– One to stand for the specific kind of subject– One to stand for the specific kind of observer
• The java library implements a nongeneric version of SO in the package java.util with the class Observable and the interface Observer– Observable class contains methods to register observers, to
indicate that observable has changed and to notify all observers of any changes among others
![Page 26: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/26.jpg)
26
9.5 – Subject-Observer pattern• The Observer interface specifies the update method that is called
by notifyObservers– Takes two parameters
1. Observable – The subject that has changed2. Object – The broadcast argument
• The appearance of Object indicates an opportunity to generify– Should be generefied by adding type parameter A, corresponding to
the argument type• Observable and Observer can be replaced with type parameters
S and O– Within the update method of the observer, the programmer may
call on any method supported by the subject S without first requiriga cast
![Page 27: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/27.jpg)
27
9.5 - Subject-Observer pattern/* Observable and observer before generics */
package java util;public class Observable {
pulic void addObserver(Observer O){…}protected void clearChanged(){…}public int countObservers(){…}public void deleteObserver(Observer O){…}public boolean hasChanged(){…}public void notifyObservers(){…}public boid notifyObservers(Object arg){…}protected void setChanged(){…}
}package java.util;public interface Observer {
public void update(Observable o, Object arg);}
![Page 28: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/28.jpg)
28
9.5 - Subject-Observer pattern/* Observable with generics */
package java.util;class StubException extends UnsupportedOperationException {}public class Observable<S extends Observable<S, O, A>,
O extends Observer<S, O, A>, A>{
public void addObserver(O o){throw new StubException();}protected void clearChanged(){ throw new StubException();}public int countObservers(){ throw new StubException();}public void deleteObserver(O o){throw new StubException();}public boolean hasChanged(){throw new StubException();}public void notifyObservers(){throw new StubException();}public void notifyObservers(A a){
throw new StubException();}protected void setChanged(){throw new StubException();}
}
![Page 29: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/29.jpg)
29
9.5 - Subject-Observer pattern/* Observer with generics */
package java.util;public interface Observer<S extends Observable<S, O, A>,
O extends Observer<S, O, A>, A>{
public void update(S o, A a);}
![Page 30: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/30.jpg)
30
9.5 – Subject-Observer pattern• As an example, a currency converter is presented• The converter allows to enter conversion rates for
three currencies– Changing the entry for a rate, causes the corresponding value
to be recomputed– Changing the entry for a value, causes all the values to be
recomputed
• The client instantiates the pattern by – Declaring CModel to be a subclass of Observable– Declaring CView to be a subinterface of Observer– Instantiates the argument type to Currency
![Page 31: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/31.jpg)
31
9.5 – Subject-Observer pattern• CModel class invokes the update method of RateView
whenever a rate is changed,– Passing the corresponding currency as the argument
• Invokes the update method of ValueView whenever a value is changed, passing null as the argument
• See example 7.
![Page 32: Java Generics – Chapter 93 9.1 – Visitor pattern • Data structure often defined by case analysis and recursion • A binary tree of type Tree is – A leaf containing](https://reader035.vdocuments.us/reader035/viewer/2022081611/5f08d4bc7e708231d423ee7c/html5/thumbnails/32.jpg)
}//End of chapter 9