Download Iterators and Design Patterns in Programming Language - Lecture Slides | CMSC 433 and more Papers Programming Languages in PDF only on Docsity!
1
CMSC 433 – Programming Language
Technologies and Paradigms
Spring 2005
Iterators and Design Patterns
February 15, 2005
2
Administrivia
• Other resources:
– Thinking in Patterns with Java
- Link from the class web page
– Gamma, Helm, Johnson, Vlissides, Design Patterns ,
Addison-Wesley 1995
– Freeman et al, Head First Design Patterns, O’Reilly,
Inner Classes
• Classes can be nested inside other classes
– These are called inner classes
• Within a class that contains an inner class, you
can use the inner class just like any other class
Example: The Queue Class
class Queue { class Entry { // Java inner class Element elt; Entry next; Entry(Element i) { elt = i; next = null; } } private Entry theQueue; void enqueue(Element e) { if (theQueue == null) theQueue = new Entry(e); else { Entry last = theQueue; while (last.next != null) last = last.next; last.next = new Entry(e); } } ...
5
Example: The Queue Class (cont’d)
class Queue { ... Element dequeue() throws EmptyQueueException { if (theQueue == null) throw new EmptyQueueException(); Element e = theQueue.elt; theQueue = theQueue.next; return e; } } 6
Referring to Outer Class
class Queue { ... int numEntries; class Entry { Element elt; Entry next; Entry(Element i) { elt = i; next = null; numEntries++; } } }
• Each inner “object” has an implicit reference to
the outer “object” whose method created it
– Can refer to fields directly, or use outer class name.
Other Features of Inner Classes
• Outside of the outer class, use outer.inner
notation to refer to type of inner class
– E.g., Queue.Entry
• An inner class marked static does not have a
reference to outer class
– Can’t refer to instance variables of outer class
– Must also use outer.inner notation to refer to inner class
• Question: Can Queue.Element be made static?
Anonymous Inner Classes
(new Thread() { public void run() { try { Thread.sleep(10006020); System.out.println("..."); System.exit(1); } catch (Exception e) {} } }).start();**
• Create anonymous subclass of thread, and invoke
method on it
13
Using Iterators
Iterator i = c.iterator(); while (i.hasNext()) { Element e = (Element) i.next(); // do stuff with e } // alternatively use for for (Iterator i = c.iterator(); i.hasNext(); ) { Element e = (Element) i.next(); // do stuff with e } 14
Iterators and Queues
• Recall queue example from beginning of lecture
• We’ll explore options for adding iterators
next() Shouldn’t Mutate Aggregate
class Queue { ... class QueueIterator implements Iterator { Entry rest; QueueIterator(Entry q) { rest = q; } boolean hasNext() { return rest != null; } Element next() throws NoSuchElementException { if (rest == null) throw new NoSuchElementException(); Element e = rest.elt; rest = rest.next; // queue data intact return e; } } }
Evil Mutating Clients
• But a client could mutate the data structure …
HashMap h = ...; ... Iterator i = h.entrySet().iterator(); System.out.println(i.next()); System.out.println(i.next()); h.put(“Foo”, “Bar”); // hash table resize! System.out.println(i.next()); // prints ???
17
Defensive (Proactive) Copying
• Solution 1: Iterator copies data structure
class QueueIterator implements Iterator { Entry rest; QueueIterator(Queue q) { // copy q.theQueue to rest } }
• Pro: Works even if queue is mutated
• Con: Expensive to construct iterator
18
Timestamps
• Solution 2: Track Mutations
class Queue { ... int modCount = 0; void enqueue(Element e) { ... modCount++; } Element dequeue() { ... modCount++; } ...
Timestamps (cont’d)
class QueueIterator implements Iterator { int expectedModCount = modCount; // set at iterator // construction time Element next() { if (expectedModCount != modCount) throw new ConcurrentModificationException(); ... } // does hasNext() need to be modified? }}
• Pro: Iteration construction cheap
• Con: Doesn’t allow any mutation 20
Comments
• Neither solution tracks mutations to container elts
– Could use clone(), but tricky
25
Object Modeling Technique (OMT)
• Used to describe patterns in GO4 book
• Graphical representation of OO relationships
– Class diagrams show the static relationship between
classes
– Object diagrams represent the state of a program as
series of related objects
– Interaction diagrams illustrate execution of the
program as an interaction among related objects
26
Classes
Object instantiation
Subclassing and Abstract Classes
29
Pseudo-code and Containment
30
Object diagrams
Interaction diagrams
time
Structure of Iterator (Cursor) Pattern
37
Example
class P implements Processor { int count = 0; public void process(Element e) { count++; } } Processor p = new Processor(); q.intIterate(p); System.out.println(p.count); iterator i = q.extIterate(); int count = 0; while (i.hasNext()) { i.next(); count++; } System.out.println(p.count);
External Internal
38
CMSC 433 – Programming Language
Technologies and Paradigms
Spring 2005
Design Patterns
February 17, 2005
Design Patterns: Goals
• To support reuse of successful designs
• To facilitate software evolution
– Add new features easily, without breaking existing ones
• In short, we want to design for change
Underlying Principles
• Reduce implementation dependencies between
elements of a software system
• Sub-goals:
– Program to an interface, not an implementation
– Favor composition over inheritance
– Use delegation
41
Program to Interface, Not Implementation
• Rely on abstract classes and interfaces to hide
differences between subclasses from clients
– Interface defines an object’s use (protocol)
– Implementation defines particular policy
• Example : Iterator interface, compared to its
implementation for a LinkedList
42
Rationale
• Decouples clients from the implementations of
the applications they use
• When clients manipulate an interface, they
remain unaware of the specific object types being
used.
• Therefore: clients are less dependent on an
implementation, so it can be easily changed later.
Favor Composition over Class Inheritance
• White box reuse:
– Inheritance
• Black box reuse:
– Composition
AClass amethod BClass amethod BClass amethod AClass amethod aVar
Delegation
• Forward messages (delegate) to different
instances at run-time; a form of composition
– May pass invoking object’s this pointer to simulate
inheritance
Rectangle area() width height Window area() rectangle Return width * height return rectangle.area()
49
Behavioral Patterns
• Template
– Define the skeleton of an algorithm in an operation,
deferring some steps to subclasses
• State
– Allow an object to alter its behavior when its internal
state changes. The object will appear to change its class
• Observer
– Define a one-to-many dependency between objects so
that when one object changes state, all its dependents
are notified and updated automatically
50
Singleton Objects
• Problem:
– Some classes have conceptually one instance
- Many printers, but only one print spooler
- One file system
- One window manager
– Creating many objects that represent the same
conceptual instance adds complexity and overhead
• Solution: only create one object and reuse it
– Encapsulate the code that manages the reuse
The Singleton Solution
• Class is responsible for tracking its sole instance
– Make constructor private
– Provide static method/field to allow access to the only
instance of the class
• Benefit:
– Reuse implies better performance
– Class encapsulates code to ensure reuse of the object;
no need to burden client
Singleton pattern
53
Implementing the Singleton method
• In Java, just define a final static field
public class Singleton { private Singleton() {…} final private static Singleton instance = new Singleton(); public static Singleton getInstance() { return instance; } }
• Java semantics guarantee object is created
immediately before first use
54
Marshalling
• Marshalling is the process of transforming
internal data into a form that can be
– Written to disk
– Sent over the network
– Etc.
• Unmarshalling is the inverse process
Marhsalling in Java
• Java provides support for marshalling objects
– Classes implement the Serializable interface
– The JVM imlpements standard marhsalling and
unmarshalling automatically
- E.g., enables you to create persistent objects, stored on disk
- This can be useful for build a light-weight database
- Also useful for distributed object systems
• Often, generic implementation works fine
– But let’s consider singletons...
Marhsalling and Singletons
• What happens when we unmarshall a singleton?
• Problem: JVM doesn’t know about singletons
– It will create two instances of Singleton.instance!
– Oops!
Singleton.instance Singleton.instance
61
Enumerators in Java 1.
• New version of Java has type safe enums
– Built-in: Don’t need to use the design pattern
- public enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES }
– Type checked at compile time
– Implemented as objects (translated as prev slide?)
– Two extra class methods:
- public static [] values() -- the enumeration elts
- public static valueOf(String name) -- get an elt 62
Adapter ( aka Wrapper) Pattern
• Problem:
– You have some code you want to use for a program
– You can’t incorporate the code directly (e.g., you just
have the .class file, say as part of a library)
– The code does not have the interface you want
- Different method names
- More or fewer methods than you need
• To use this code, you must adapt it to your
situation
Adapter Pattern (cont’d)
• Here’s what we have:
– Client is already written, and it uses the Target interface
– Adaptee has a method that works, but has the wrong
name
• How do we enable the Client to use the Adaptee?
Adapter Pattern (cont’d)
• Solution: adapter class to implement client’s
expected interface, forwarding methods
65
Proxy Pattern Motivation
• Goal:
– Prevent an object from being accessed directly by its
clients
• Solution:
– Use an additional object, called a proxy
– Clients access protected object only through proxy
– Proxy keeps track of status and/or location of protected
object
66
Uses of the Proxy Pattern
• Virtual proxy : impose a lazy creation semantics,
to avoid expensive object creations when strictly
unnecessary.
• Monitor proxy : impose security constraints on the
original object, say by intercepting some method
calls to proxied object.
• Remote proxy : hide the fact that an object resides
on a remote location.
More OMT Notation
• Arrow ending in filled circle
– More than one
Example Usage Class Diagram
73
Example: Java I/O
class LineNumberReader extends BufferedReader { private int lineNumber; public LineNumberReader(Reader in) { super(in); } public int getLineNumber() { return lineNumber; } public int read() { int c = super.read(); if (c == ‘\n’) { lineNumber++; return ‘\n’; } return c; } } (^) 74
Interaction Diagram
More OMT Notation
• Arrow beginning with diamond
– “Part-of” or aggregation
– Only accessed by object pointing to it
Decorator Pattern: Another Example
77
Decorator Pattern: Features
• Decorator conforms to interface of decorated
component
– Its presence is transparent to the component's clients.
• Decorator forwards requests to encapsulated
component
– May perform additional actions before or after
• Can nest decorators recursively
– Allows unlimited added responsibilities
• Can add/remove responsibilities dynamically
78
Structure
79
Decorator Pattern Analysis
• Advantages
– Fewer classes than with static inheritance
– Dynamic addition/removal of decorators
– Keeps root classes simple
• Disadvantages
– Proliferation of run-time instances
– Abstract Decorator must provide common interface
• Tradeoffs:
– Useful when components are lightweight
– Otherwise use Strategy 80
Decorator vs. Adapter
• A decorator adds to the responsibilities of an
object
– Usually has the same interface plus more features
• An adapter changes the interface
– But usually not the responsibilities