Josh Bloch Charlie Garrod School of Computer Science 15-214 1 - - PowerPoint PPT Presentation

josh bloch charlie garrod
SMART_READER_LITE
LIVE PREVIEW

Josh Bloch Charlie Garrod School of Computer Science 15-214 1 - - PowerPoint PPT Presentation

Principles of So3ware Construc9on: Objects, Design, and Concurrency Designing classes Introduc9on to design paDerns, con9nued and Parametric polymorphism (with Java generics) Josh Bloch Charlie Garrod School of Computer Science 15-214 1


slide-1
SLIDE 1

1

15-214

School of Computer Science

Principles of So3ware Construc9on: Objects, Design, and Concurrency Designing classes Introduc9on to design paDerns, con9nued and Parametric polymorphism (with Java generics)

Josh Bloch Charlie Garrod

slide-2
SLIDE 2

2

15-214

Administrivia

  • Homework 3 due Sunday, September 25th
  • Midterm exam next Thursday (September 29th)

– Review session Wednesday, September 28th, 7-9 pm, HH B103

slide-3
SLIDE 3

3

15-214

Java puzzlers: “Animal Farm” (2005)

public class AnimalFarm { public static void main(String[] args) { final String pig = "length: 10"; final String dog = "length: " + pig.length(); System.out.println("Animals are equal: " + pig == dog); } }

From An Evening Of Puzzlers by Josh Bloch

slide-4
SLIDE 4

4

15-214

What does it print? (a) Animals are equal: true (b) Animals are equal: false (c) It varies (d) None of the above

public class AnimalFarm { public static void main(String[] args) { final String pig = "length: 10"; final String dog = "length: " + pig.length(); System.out.println("Animals are equal: " + pig == dog); } }

slide-5
SLIDE 5

5

15-214

What does it print?

(a) Animals are equal: true (b) Animals are equal: false (c) It varies (d) None of the above: false The + operator binds tighter than ==

slide-6
SLIDE 6

6

15-214

Another look

public class AnimalFarm { public static void main(String[] args) { final String pig = "length: 10"; final String dog = "length: " + pig.length(); System.out.println("Animals are equal: " + pig == dog); } }

slide-7
SLIDE 7

7

15-214

You could try to fix it like this...

public class AnimalFarm { public static void main(String[] args) { final String pig = "length: 10"; final String dog = "length: " + pig.length(); System.out.println("Animals are equal: " + (pig == dog)); } }

Prints Animals are equal: false

slide-8
SLIDE 8

8

15-214

But this is much better

public class AnimalFarm { public static void main(String[] args) { final String pig = "length: 10"; final String dog = "length: " + pig.length(); System.out.println("Animals are equal: " + pig.equals(dog)); } }

Prints Animals are equal: true

slide-9
SLIDE 9

9

15-214

The moral

  • Use parens, not spacing, to express intent
  • Use parens whenever there is any doubt
  • Don’t depend on interning of string constants
  • Use .equals, not == for object references
slide-10
SLIDE 10

10

15-214

Key concepts from Thursday…

slide-11
SLIDE 11

11

15-214

UML you should know

  • Interfaces vs. classes
  • Fields vs. methods
  • Rela9onships:

– "extends" (inheritance) – "implements" (realiza9on) – "has a" (aggrega9on) – non-specific associa9on

  • Visibility: + (public) - (private) # (protected)
  • Basic best prac9ces…
slide-12
SLIDE 12

12

15-214

Discussion with design paDerns

  • Carpentry:

– "Is a dovetail joint or a miter joint beDer here?"

  • So3ware Engineering:

– "Is a strategy paDern or a template method beDer here?"

slide-13
SLIDE 13

13

15-214

Strategy paDern

  • Problem: Clients need different variants of an algorithm
  • Solu9on: Create an interface for the algorithm, with an

implemen9ng class for each variant of the algorithm

  • Consequences:

– Easily extensible for new algorithm implementa9ons – Separates algorithm from client context – Introduces an extra interface and many classes:

  • Code can be harder to understand
  • Lots of overhead if the strategies are simple
slide-14
SLIDE 14

14

15-214

Avoiding instanceof with the template method pattern

public void doSomething(Account acct) { float adj = 0.0; if (acct instanceof CheckingAccount) { checkingAcct = (CheckingAccount) acct; adj = checkingAcct.getFee(); } else if (acct instanceof SavingsAccount) { savingsAcct = (SavingsAccount) acct; adj = savingsAcct.getInterest(); } … }

Instead:

public void doSomething(Account acct) { long adj = acct.getMonthlyAdjustment(); … }

slide-15
SLIDE 15

15

15-214

Today:

  • A puzzler…
  • More design paDerns for reuse

– Iterator paDern (reprised) – Decorator paDern

  • Parametric polymorphism (a.k.a. generics)
slide-16
SLIDE 16

16

15-214

Traversing a collec9on

  • Old-school Java for loop for ordered types

List<String> arguments = …; for (int i = 0; i < arguments.size(); i++) { System.out.println(arguments.get(i)); }

  • Modern standard Java for-each loop

List<String> arguments = …; for (String s : arguments) { System.out.println(s); } public interface Iterable<E> { public Iterator<E> iterator(); }

Works for every implementa9on

  • f Iterable:
slide-17
SLIDE 17

17

15-214

The Iterator interface

public interface java.util.Iterator<E> { boolean hasNext(); E next(); void remove(); // removes previous returned item } // from the underlying collection

  • To use explicitly, e.g.:

List<String> arguments = …; for (Iterator<String> it = arguments.iterator(); it.hasNext(); ) { String s = it.next(); System.out.println(s); }

slide-18
SLIDE 18

18

15-214

Iterator design paDern

  • Problem: Clients need uniform strategy to access all elements in

a container, independent of the container type

– Order is unspecified, but access every element once

  • Solu9on: A strategy paDern for itera9on
  • Consequences:

– Hides internal implementa9on of underlying container – Easy to change container type – Facilitates communica9on between parts of the program

slide-19
SLIDE 19

19

15-214

A design principle for reuse: low coupling

  • Each component should depend on as few other components as

possible

  • Benefits of low coupling:

– Enhances understandability – Reduces cost of change – Eases reuse

slide-20
SLIDE 20

20

15-214

Gejng an Iterator

public interface Collection<E> extends Iterable<E> { boolean add(E e); boolean addAll(Collection<? extends E> c); boolean remove(Object e); boolean removeAll(Collection<?> c); boolean retainAll(Collection<?> c); boolean contains(Object e); boolean containsAll(Collection<?> c); void clear(); int size(); boolean isEmpty(); Iterator<E> iterator(); Object[] toArray() <T> T[] toArray(T[] a); … } Defines an interface for creating an Iterator, but allows Collection implementation to decide which Iterator to create.

slide-21
SLIDE 21

21

15-214

public class Pair<E> { private final E first, second; public Pair(E f, E s) { first = f; second = s; } }

An Iterator implementa9on for Pairs

Pair<String> pair = new Pair<String>("foo", "bar"); for (String s : pair) { … }

slide-22
SLIDE 22

22

15-214

public class Pair<E> implements Iterable<E> { private final E first, second; public Pair(E f, E s) { first = f; second = s; } public Iterator<E> iterator() { return new PairIterator(); } private class PairIterator implements Iterator<E> { private boolean seenFirst = false, seenSecond = false; public boolean hasNext() { return !seenSecond; } public E next() { if (!seenFirst) { seenFirst = true; return first; } if (!seenSecond) { seenSecond = true; return second; } throw new NoSuchElementException(); } public void remove() { throw new UnsupportedOperationException(); } } }

An Iterator implementa9on for Pairs

Pair<String> pair = new Pair<String>("foo", "bar"); for (String s : pair) { … }

slide-23
SLIDE 23

23

15-214

Using a java.util.Iterator<E>: A warning

  • The default Collec9ons implementa9ons are mutable…
  • …but their Iterator implementa9ons assume the collec9on

does not change while the Iterator is being used

– You will get a ConcurrentModificationException

slide-24
SLIDE 24

24

15-214

Using a java.util.Iterator<E>: A warning

  • The default Collec9ons implementa9ons are mutable…
  • …but their Iterator implementa9ons assume the collec9on

does not change while the Iterator is being used

– You will get a ConcurrentModificationException – If you simply want to remove an item: List<String> arguments = …; for (Iterator<String> it = arguments.iterator(); it.hasNext(); ) { String s = it.next(); if (s.equals("Charlie")) arguments.remove("Charlie"); // runtime error }

slide-25
SLIDE 25

25

15-214

Using a java.util.Iterator<E>: A warning

  • The default Collec9ons implementa9ons are mutable…
  • …but their Iterator implementa9ons assume the collec9on

does not change while the Iterator is being used

– You will get a ConcurrentModificationException – If you simply want to remove an item: List<String> arguments = …; for (Iterator<String> it = arguments.iterator(); it.hasNext(); ) { String s = it.next(); if (s.equals("Charlie")) it.remove(); }

slide-26
SLIDE 26

26

15-214

Today:

  • A puzzler…
  • More design paDerns for reuse

– Iterator paDern (reprised) – Decorator paDern

  • Parametric polymorphism (a.k.a. generics)
slide-27
SLIDE 27

27

15-214

Limita9ons of inheritance

  • Suppose you want various extensions of a Stack data structure…

– UndoStack: A stack that lets you undo previous push or pop opera9ons – SecureStack: A stack that requires a password – SynchronizedStack: A stack that serializes concurrent accesses

slide-28
SLIDE 28

28

15-214

Limita9ons of inheritance

  • Suppose you want various extensions of a Stack data structure…

– UndoStack: A stack that lets you undo previous push or pop opera9ons – SecureStack: A stack that requires a password – SynchronizedStack: A stack that serializes concurrent accesses – SecureUndoStack: A stack that requires a password, and also lets you undo previous opera9ons – SynchronizedUndoStack: A stack that serializes concurrent accesses, and also lets you undo previous opera9ons – SecureSynchronizedStack: … – SecureSynchronizedUndoStack: …

Goal: arbitrarily composable extensions

slide-29
SLIDE 29

29

15-214

Limita9ons of inheritance

slide-30
SLIDE 30

30

15-214

Workarounds?

  • Combining inheritance hierarchies?
  • Mul9ple inheritance?
slide-31
SLIDE 31

31

15-214

The decorator design paDern

  • Problem: You need arbitrary or dynamically composable

extensions to individual objects.

  • Solu9on: Implement a common interface as the object you are

extending, add func9onality, but delegate primary responsibility to an underlying object.

  • Consequences:

– More flexible than sta9c inheritance – Customizable, cohesive extensions – Breaks object iden9ty, self-references

slide-32
SLIDE 32

32

15-214

Decorators use both subtyping and delega9on

public class LoggingList<E> implements List<E> { private final List<E> list; public LoggingList<E>(List<E> list) { this.list = list; } public boolean add(E e) { System.out.println("Adding " + e); return list.add(e); } public E remove(int index) { System.out.println("Removing at " + index); return list.remove(index); } …

slide-33
SLIDE 33

33

15-214

The AbstractStackDecorator forwarding class

public abstract class AbstractStackDecorator implements Stack { private final Stack stack; public AbstractStackDecorator(Stack stack) { this.stack = stack; } public void push(Item e) { stack.push(e); } public Item pop() { return stack.pop(); } … }

slide-34
SLIDE 34

34

15-214

The concrete decorator classes

public class UndoStack extends AbstractStackDecorator implements Stack { private final UndoLog log = new UndoLog(); public UndoStack(Stack stack) { super(stack); } public void push(Item e) { log.append(UndoLog.PUSH, e); super.push(e); } … }

slide-35
SLIDE 35

35

15-214

Using the decorator classes

  • To construct a plain stack:

Stack stack = new ArrayStack();

  • To construct an undo stack:
slide-36
SLIDE 36

36

15-214

Using the decorator classes

  • To construct a plain stack:

Stack stack = new ArrayStack();

  • To construct an undo stack:

UndoStack stack = new UndoStack(new ArrayStack());

slide-37
SLIDE 37

37

15-214

Using the decorator classes

  • To construct a plain stack:

Stack stack = new ArrayStack();

  • To construct an undo stack:

UndoStack stack = new UndoStack(new ArrayStack());

  • To construct a secure synchronized undo stack:
slide-38
SLIDE 38

38

15-214

Using the decorator classes

  • To construct a plain stack:

Stack s = new ArrayStack();

  • To construct an undo stack:

UndoStack s = new UndoStack(new ArrayStack());

  • To construct a secure synchronized undo stack:

SecureStack s = new SecureStack(new SynchronizedStack(new UndoStack

slide-39
SLIDE 39

39

15-214

Decorators from java.util.Collections

  • Turn a mutable list into an immutable list:

static List<T> unmodifiableList(List<T> lst); static Set<T> unmodifiableSet( Set<T> set); static Map<K,V> unmodifiableMap( Map<K,V> map);

  • Similar for synchroniza9on:

static List<T> synchronizedList(List<T> lst); static Set<T> synchronizedSet( Set<T> set); static Map<K,V> synchronizedMap( Map<K,V> map);

slide-40
SLIDE 40

40

15-214

The UnmodifiableCollec9on (simplified excerpt)

public static <T> Collection<T> unmodifiableCollection(Collection<T> c) { return new UnmodifiableCollection<>(c); } class UnmodifiableCollection<E> implements Collection<E>, Serializable { final Collection<E> c; UnmodifiableCollection(Collection<> c) {this.c = c; } public int size() {return c.size();} public boolean isEmpty() {return c.isEmpty();} public boolean contains(Object o) {return c.contains(o);} public Object[] toArray() {return c.toArray();} public <T> T[] toArray(T[] a) {return c.toArray(a);} public String toString() {return c.toString();} public boolean add(E e) {throw new UnsupportedOperationException(); } public boolean remove(Object o) { throw new UnsupportedOperationException public boolean containsAll(Collection<?> coll) { return c.containsAll public boolean addAll(Collection<? extends E> coll) { throw new UnsupportedOperationException public boolean removeAll(Collection<?> coll) { throw new UnsupportedOperationException public boolean retainAll(Collection<?> coll) { throw new UnsupportedOperationException public void clear() { throw new UnsupportedOperationException(); } }

slide-41
SLIDE 41

41

15-214

The decorator paDern vs. inheritance

  • Decorator composes features at run 9me

– Inheritance composes features at compile 9me

  • Decorator consists of mul9ple collabora9ng objects

– Inheritance produces a single, clearly-typed object

  • Can mix and match mul9ple decora9ons

– Mul9ple inheritance is conceptually difficult

slide-42
SLIDE 42

42

15-214

Today:

  • A puzzler…
  • More design paDerns for reuse

– Iterator paDern (reprised) – Decorator paDern

  • Parametric polymorphism (a.k.a. generics)
slide-43
SLIDE 43

43

15-214

public class Pair { private final Object first, second; public Pair(Object first, Object second) { this.first = first; this.second = second; } public Object first() { return first; } public Object second() { return second; } }

An implementa9on of pairs, a la 2003

slide-44
SLIDE 44

44

15-214

public class Pair { private final Object first, second; public Pair(Object first, Object second) { this.first = first; this.second = second; } public Object first() { return first; } public Object second() { return second; } }

An implementa9on of pairs, a la 2003

  • Some possible client code?

Pair p = new Pair("Hello", "world"); String result = p.first();

slide-45
SLIDE 45

45

15-214

public class Pair { private final Object first, second; public Pair(Object first, Object second) { this.first = first; this.second = second; } public Object first() { return first; } public Object second() { return second; } }

An implementa9on of pairs, a la 2003

  • Some possible client code?

Pair p = new Pair("Hello", "world"); String result = p.first(); // Won't compile--type error

slide-46
SLIDE 46

46

15-214

public class Pair { private final Object first, second; public Pair(Object first, Object second) { this.first = first; this.second = second; } public Object first() { return first; } public Object second() { return second; } }

An implementa9on of pairs, a la 2003

  • Some possible client code:

Pair p = new Pair("Hello", "world"); assert p.first() instanceof String; String result = (String) p.first();

slide-47
SLIDE 47

47

15-214

Parametric polymorphism (a.k.a. generics)

  • Parametric polymorphism is the ability to define a type

generically, allowing sta9c type-checking without fully specifying the type

– e.g.: public class Frequency { public static void main(String[] args) { Map<String, Integer> m = new TreeMap<>(); for (String word : args) { Integer freq = m.get(word); m.put(word, (freq == null ? 1 : freq + 1)); } System.out.println(m); } }

slide-48
SLIDE 48

48

15-214

public class Pair<E> { private final E first, second; public Pair(E first, E second) { this.first = first; this.second = second; } public E first() { return first; } public E second() { return second; } }

A generic implementa9on of pairs

  • BeDer client code:

Pair<String> p = new Pair<>("Hello", "world"); String result = p.first();

slide-49
SLIDE 49

49

15-214

Java Generics to be con9nued…

slide-50
SLIDE 50

50

15-214

Summary

  • Reduce coupling to increase understandability, reuse
  • Decorator paDern provides composable extensions without

mul9ple inheritance

  • Generics provide API flexibility with type safety