Oliver Haase
Design Patterns
Factory Method
Idea
If client knows when to create certain object(s), but doesn't know (neither care) how, then...
‣ make client an abstract class;
‣ define an abstract method for object creation;
‣ leave implementation to concrete subclass(es).
Also known as virtual constructor.
DocManager Reloaded
Originally:
@ThreadSafe // assuming that LatexDoc is threadsafe public class DocManager {
private final Collection<Document> docs;
public DocManager() {
docs = new ConcurrentLinkedQueue<Document>();
}
public void createDoc() {
Document doc = new LatexDoc();
docs.add(doc);
doc.open();
}
DocManager Reloaded
With factory method:
@ThreadSafe // assuming that concrete Document is threadsafe public abstract class DocManager {
private final Collection<Document> docs;
public DocManager() {
docs = new ConcurrentLinkedQueue<Document>();
}
protected abstract Document newDocument();
public void createDoc() {
Document doc = newDocument();
docs.add(doc);
doc.open();
}
public void openDocs() {
for ( Document doc : docs ) doc.open();
} ...
DocManager Reloaded
@ThreadSafe // assuming that LatexDoc is threadsafe public class LatexDocManager extends DocManager {
@Override
protected Document newDocument() { return new LatexDoc();
} }
Concrete subclass LatexDocManager :
Structure
newDocument() createDoc()
openDocs()
DocManager
Document doc = newDocument();
docs.add(doc);
doc.open();
open() close()
Document
open() close()
LatexDoc newDocument()
LatexDocManager return
new LatexDoc();
Structure - in General
factoryMethod() someOperation()
Creator
Product product = factoryMethod();
product.use();
use()
Product
use()
ConcreteProduct factoryMethod()
ConcreteCreator return
new ConcreteProduct();
superclass/interface of products to be created
implementation of
‣ defines factory method
‣ uses factory method to create products
‣ may provide default implementation
implements factory
Comparison: Starting Point
someOperation() Client
Product product =
new ConcreteProduct();
product.use();
use()
Product
use()
ConcreteProduct
Misc
‣ Pro: Simple technique to decouple client from object creation
‣ Con: Creator class must be extended to override a single method might lead to bloated class hierarchy
‣ Relationship with other patterns: Abstract factories usually use factory methods that are implemented by
concrete factories.
Naming Conventions
‣ get<Type> : returns an instance that is described by the input params; can be either an existing or a new instance
‣ new<Type> : as above; guarantees that each invocation
return a new instance
Caveat
Don't confuse with static factory methods that a class provides to instantiate itself.
Alternative to direct constructor invocation, see Joshua Bloch: Effective Java, 2 nd Edition, item 1.
Naming convention for static factory methods:
‣ getInstance : see get<Type>
‣ newInstance : see new<Type>
Excercise
Use the factory method pattern to remove the dependencies on ConcreteBufferHolder and ConcreteUdpTask .
@ThreadSafe // because DatagramSocket and Executor are threadsafe public class UdpServer {
private static final int POOL_SIZE = 10;
private final DatagramSocket udpSocket;
private final ExecutorService executor;
public UdpServer(int port) throws SocketException { udpSocket = new DatagramSocket(port);
executor = Executors.newFixedThreadPool(POOL_SIZE);
}
public void start() throws IOException { while ( true ) {
BufferHolder bufferHolder = new ConcreteBufferHolder();
byte[] buffer = bufferHolder.getBuffer();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
udpSocket.receive(packet);
executor.execute(new ConcreteUdpTask(packet));
}
Prototype
… Somewhere in the deeply remote past it seriously traumatized a small random group of atoms drifting
through the empty sterility of space and made them cling together in the most extraordinarily unlikely patterns.
These patterns quickly learnt to copy themselves (this was
Idea
If client knows when to create certain object(s), but doesn't know (neither care) how, then...
. . . provide client with prototype of the object that can be
cloned to get more instances.
DocManager Reloaded
Originally:
@ThreadSafe // assuming that LatexDoc is threadsafe public class DocManager {
private final Collection<Document> docs;
public DocManager() {
docs = new ConcurrentLinkedQueue<Document>();
}
public void createDoc() {
Document doc = new LatexDoc();
docs.add(doc);
doc.open();
}
DocManager Reloaded
With prototype:
@ThreadSafe // assuming that concrete Document is threadsafe public class DocManager {
private final Collection<Document> docs;
private final Document prototype;
public DocManager(Document prototype) {
docs = new ConcurrentLinkedQueue<Document>();
this.prototype = prototype;
}
public void createDoc() {
Document doc = prototype.clone();
docs.add(doc);
doc.open();
}
public void openDocs() {
for ( Document doc : docs ) doc.open();
} ...
DocManager Reloaded
DocManager docManager = new DocManager(new LatexDoc());
docManager.createDoc();
Sample usage of prototype-based DocManager :
Structure
open() close() clone()
Document
open() close() clone()
LatexDoc Document doc =
prototype.clone();
docs.add(doc);
doc.open();
return copy of itself createDoc()
openDocs()
prototype: Document
DocManager
General Structure
use() clone()
Product
use() clone()
ConcreteProduct Product product =
prototype.clone();
product.use();
return copy of itself someOperation()
prototype: Product Client
superclass/interface of products to be created,
incl. declaration of clone operation
‣ owns a product prototype
‣ creates new products by asking the prototype to clone itself
How does prototype get into client?
out of scope of this pattern!
Pros & Cons
‣ Pro:
• avoids bloating of type hierarchy, i.e. no client subclass
(factory method), no factory interfaces ( → abstract factories)
• client can be dynamically configured with new prototype
‣ Con:
• product must support clone operation
• difficult or impossible if product already exists
• correct implementation of clone operation difficult, clone
concept in Java seriously flawed see later
Relationship with Other Patterns
‣ Abstract factories usually use factory methods that are implemented by concrete factories
‣ Alternative option: concrete factory gets prototype for each
product type and uses cloning to create new products
fewer types, more flexibility, less type safety
Java’s Clone Concept
‣ class Object contains a protected clone method
‣ a subclass can only use Object.clone() if it implements the Cloneable marker interface, otherwise
Object.clone() throws CloneNotSupportedException
‣ cloneable subclass must provide public clone method which is not enforced by Cloneable
‣ Object.clone
• returns a copy of the right type, i.e. the object’s runtime
type
Java’s Clone Concept
To implement clone method,
‣ call super.clone()
‣ replace shallow copies of own fields with deep copies as needed; usually done with fields’ clone methods
works only if each supertype in the hierarchy
adheres to this behavior!
Cloning: Example I
@Immutable
public final class PhoneNumber implements Cloneable { private final short areaCode;
private final short prefix;
private final short lineNumber;
public PhoneNumber(short areaCode, short prefix, short lineNumber) { this.areaCode = areaCode;
this.prefix = prefix;
this.lineNumber = lineNumber;
} ...
@Override public PhoneNumber clone() { try {
return (PhoneNumber) super.clone();
Cloning: Example II
@Threadsafe
public final class Stack implements Cloneable { private Object[] elements;
private int size = 0;
private static final int INITIAL_CAPACITY = 16;
public Stack() {
this.elements = new Object[INITIAL_CAPACITY];
}
public synchronized void push(Object e) { ensureCapacity();
elements[size++] = e;
}
public synchronized Object pop() { if ( size == 0 )
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null;
return result;
}
Cloning: Example II, cont’d
private void ensureCapacity() { if ( elements.length == size )
elements = Arrays.copyOf(elements, 2 * size +1);
}
@Override public synchronized Stack clone() { try {
Stack result = (Stack) super.clone();
result.elements = elements.clone();
return result;
} catch (CloneNotSupportedException e) {
throw new AssertionError(); // Can’t happen }
} }
Note that
Cloning: Example III
public final class HashTable implements Cloneable { private Entry[] buckets;
private static class Entry { final Object key;
Object value;
Entry next;
Entry(Object key, Object value, Entry next) { this.key = key;
this.value = value;
this.next = next;
} }
public HashTable(int size) { buckets = new Entry[size];
} ...
}
Cloning: Example III, cont’d
@Override public HashTable clone() { try {
HashTable result = (HashTable) super.clone();
result.buckets = buckets.clone();
return result;
} catch (CloneNotSupportedException e) {
throw new AssertionError(); // Can’t happen }
} }
Broken, because cloned buckets array references same
clone method, first try:
Cloning: Example III, cont’d
private static class Entry { final Object key;
Object value;
Entry next;
Entry(Object key, Object value, Entry next) { this.key = key;
this.value = value;
this.next = next;
}
Entry deepCopy() {
return new Entry(key, value, next == null ? null: next.deepCopy());
} }
Add deepCopy method to Entry class:
Cloning: Example III, cont’d
@Override public HashTable clone() { try {
HashTable result = (HashTable) super.clone();
result.buckets = new Entry[buckets.length];
for ( int i = 0; i < buckets.length; i++ ) if ( buckets[i] != null )
result.buckets[i] = buckets[i].deepCopy();
return result;
} catch (CloneNotSupportedException e) {
throw new AssertionError(); // Can’t happen }
} }
Alternatively,
clone method, second try:
Java Cloning - Summary
J. Bloch advises to generally avoid clone but to use copy constructor instead
not directly suitable for prototype patterns because Client does not know prototype’s runtime type
declare clone/copy operation in Product , have each
ConcreteProduct implement clone / copy directly, e.g.
through copy constructor
‘Own’ Cloning: Example I
public final class PhoneNumber implements Product { private final short areaCode;
private final short prefix;
private final short lineNumber;
public PhoneNumber(short areaCode, short prefix, short lineNumber) { this.areaCode = areaCode;
this.prefix = prefix;
this.lineNumber = lineNumber;
}
public PhoneNumber(PhoneNumber pn) {
this(pn.areaCode, pn.prefix, pn.lineNumber);
} ...
‘Own’ Cloning: Example II
public final class Stack implements Product { private Object[] elements;
private int size = 0;
private static final int INITIAL_CAPACITY = 16;
public Stack() {
this.elements = new Object[INITIAL_CAPACITY];
}
public Stack(Stack s) {
elements = s.elements.clone();
}
...
@Override public synchronized Stack copy() { return new Stack(this);
} }
Synchronization
If ConcreteProduct is to be thread-safe, clone operation
needs to be synchronized like any other method.
Discussion
‣ Prototype pattern is flexible, dynamically configurable, and doesn’t bloat type hierarchy
‣ Rather don’t use Java’s cloning concept but provide your own, independent cloning, preferably based on copy
constructors (consistent with final concept)
‣ Prototype pattern not suitable if objects with different states are needed (requires setters for otherwise
immutable fields)
Excercise
Use the prototype pattern to remove the dependencies on
ConcreteBufferHolder and ConcreteUdpTask .
@ThreadSafe // because DatagramSocket and Executor are threadsafe public class UdpServer {
private static final int POOL_SIZE = 10;
private final DatagramSocket udpSocket;
private final ExecutorService executor;
public UdpServer(int port) throws SocketException { udpSocket = new DatagramSocket(port);
executor = Executors.newFixedThreadPool(POOL_SIZE);
}
public void start() throws IOException { while ( true ) {