CreationCreational Design al Design PatternsPatterns
Yaodong BiYaodong Bi
April 20, 2023April 20, 2023
Creational design patternsCreational design patterns
FactoryFactory Abstract FactoryAbstract Factory PrototypePrototype SingletonSingleton BuilderBuilder
FactoryFactory
ProblemProblem– The client needs to create an object of a The client needs to create an object of a
subclass, but it does not know the subclass, but it does not know the subclass until runtime.subclass until runtime.
Design PurposeDesign Purpose– Create individual objects in situations Create individual objects in situations
where the constructor alone is where the constructor alone is inadequate.inadequate.
Design Pattern SummaryDesign Pattern Summary– Use methods to return required objectsUse methods to return required objects
Factory – an exampleFactory – an example
Client+useStack(Stack)
stack+push()+pop()
MyStack+push()+pop()
void useStack(Stack s) { while (condition) { stackn = new Stack(); //????? }}Stack = new MyStack();useStack(s); //?????
Factory - structureFactory - structure
Client+useProduct()
Product Creator+factoryMethod()
ConcreteCreator
+factoryMethod()
Product factorMethod() { Return new ConcreteProduct();}
ConcreteProduct
void useProduct(Creator c) { Product p = c.factoryMethod(); // use p}….Creator c = new ConcreteCreator();useProduct(c);
Factory - participantsFactory - participants
ProductProduct– defines the interface of objects the factory method creates.defines the interface of objects the factory method creates.
ConcreteProduct ConcreteProduct – implements the Product interface.implements the Product interface.
Creator Creator – declares the factory method, which returns an object of type declares the factory method, which returns an object of type
Product. Creator may also define a default implementation of Product. Creator may also define a default implementation of the factory method that returns a default ConcreteProduct the factory method that returns a default ConcreteProduct object.object.
– Creator and Product could be the same classCreator and Product could be the same class ConcreteCreatorConcreteCreator
– overrides the factory method to return an instance of a overrides the factory method to return an instance of a ConcreteProduct.ConcreteProduct.
ClientClient– It depends only on Product and Creator.It depends only on Product and Creator.
CollaborationsCollaborations– Creator relies on its subclasses to define the factory method Creator relies on its subclasses to define the factory method
so that it returns an instance of the appropriate so that it returns an instance of the appropriate ConcreteProduct. ConcreteProduct.
Factory – sequence diagramFactory – sequence diagram
Client ProductCreator ConcreteCreator
ConcreteProduct
factoryMethod() factoryMethod() constructor()
op() op()
Factory – sample codeFactory – sample code
Class StackClient { void opUsingStacks(StackCreator sc) { Stack s1 = sc.createStack(); ... Stack si = sc.createStack(); ... Stack sn = sc.createStack(); }}Interface Stack { void push(Item i); Item pop();}Interface StackCreator { Stack createStack();}Class MyStack implements Stack { ...}Class YourStack implements Stack {}
Class MyStackCreator implements StackCreator { Stack createStack() { return new MyStack(); }}Class YourStackCreator implements StackCreator { Stack createStack() { return new YourStack(); }}Class ClientDriver { void main() { StackClient c = new StackClient(); StackCreator sc = new MyStackCreator(); c.opUsingStacks(sc); sc = new YourStackCreator(); c.opUsingStacks(sc); }}
Factory – commentsFactory – comments
Factory methods are necessary for the OCP Factory methods are necessary for the OCP on object creationon object creation
Factory methods make the DIP more viableFactory methods make the DIP more viable Factory Method gives subclasses a hook for Factory Method gives subclasses a hook for
providing an extended version of an objectproviding an extended version of an object Creator could be a concrete class providing a Creator could be a concrete class providing a
default implementation of Productdefault implementation of Product Creator and Product could be the same classCreator and Product could be the same class There is an advantage of using a separate There is an advantage of using a separate
creator class for the productcreator class for the product– The product and its creation are separate concernsThe product and its creation are separate concerns– When the product is very complex, the creator can When the product is very complex, the creator can
create products (even the first one) as demanded – create products (even the first one) as demanded – lazy loadinglazy loading
Abstract FactoryAbstract Factory
Design purposeDesign purpose– Provide an interface for creating Provide an interface for creating
families of related or dependent families of related or dependent objects without specifying their objects without specifying their concrete classesconcrete classes
Pattern summaryPattern summary– Capture family creation in a class Capture family creation in a class
containing a factory method for each containing a factory method for each class in the familyclass in the family
Abstract Factory – examplesAbstract Factory – examples
Word processor for different window systemsWord processor for different window systems– Word processor is designed to a set of interfaces of Word processor is designed to a set of interfaces of
graphical elementsgraphical elements– Each windows system manufactures its own set of Each windows system manufactures its own set of
button, windows, dialogs, etcbutton, windows, dialogs, etc– Each installation of the word processor is given a Each installation of the word processor is given a
windows system (concrete factory)windows system (concrete factory) Kitchen showroomKitchen showroom
– The program is designed to a common set of cabinets, The program is designed to a common set of cabinets, counters, etccounters, etc
– Each different style of kitchen furniture provide the Each different style of kitchen furniture provide the furniture in the style (classic, contemporary, etc) furniture in the style (classic, contemporary, etc)
– Each individual kitchen showroom is given a style Each individual kitchen showroom is given a style (concrete factory) (concrete factory)
GUI themesGUI themes
Abstract Factory - structureAbstract Factory - structure
Client
Factory+createProductA()+createproductB()
ProductB createProductB() { Return new ProductB1();}
ProductA
ProductA1
ProductA2
ProductB
ProductB1
ProductB2
Factory1+createProductA()+createproductB()
Factory2+createProductA()+createproductB()
ProductA createProductA() { Return new ProductA1();}
Abstract Factory – Two Abstract Factory – Two FamiliesFamilies
ProductA1
ProductA2
ProductB1
ProductB2
Factory1+createProductA()+createproductB()
Factory2+createProductA()+createproductB()
Abstract Factory - Abstract Factory - participantsparticipants
ProductA and ProductBProductA and ProductB– defines the interface of a family of objects.defines the interface of a family of objects.
ProductA1, ProductB1, ProductA2, and ProductB2 ProductA1, ProductB1, ProductA2, and ProductB2 – TTwowo separate families of product implementation. separate families of product implementation.
FactoryFactory– Defines the interface of the factory that returns the Defines the interface of the factory that returns the
productsproducts Factory1 and Factory2Factory1 and Factory2
– Concrete factories that can produce products of the Concrete factories that can produce products of the family.family.
– Factory1 produces ProductA1 and ProductB1, Factory2 Factory1 produces ProductA1 and ProductB1, Factory2 produces ProductA2 and ProductB2produces ProductA2 and ProductB2
ClientClient– It depends only on the interfaces of the family products It depends only on the interfaces of the family products
and the factory interface.and the factory interface. CollaborationsCollaborations
– The client asks a subclass of Factory to create concrete The client asks a subclass of Factory to create concrete products of ProductA and productB. products of ProductA and productB.
Abstract Factory – Two Abstract Factory – Two FamiliesFamilies
StackViaArray
StackViaListQueueViaArray
QueueViaList
DSFactoryViaArray+createStack()+createQueue)
DSFactoryViaList+createStack)+createQueue()
Data Structures Via Array
Data Structures Via List
Abstract Factory - structureAbstract Factory - structure
DataStructsClient
DSFactory+createStack()+createQueue()
Queue createQueue (){ return new QueueViaArray();}
Stack
StackViaArray
StackViaList
Queue
QueueViaArray
QueueViaList
DSFactoryViaArray+createStack()+createQueue)
DSFactoryViaList+createStack)+createQueue()
Stack createStack (){ return new StackViaArray(); }
Queue createQueue (){ return new QueueViaList();}
Stack createStack() { return new StackViaList(); }
Abstract Factory – sample Abstract Factory – sample codecode
Class DataStructsClient { DSFactory af; DataStructsClient( DSFactory af) { this.af = af; } void op() { Stack s1 = af.createStack(); Stack s2 = af.createStack(); ... Queue q = af.createQueue(); ... Tree t = af.createTree(); }}
Interface DSFactory { Stack createStack(); Queue createQueue(); Tree createTree();}
Interface Stack {...}Interface Queue {...}Interface Tree {...}
Class StackViaArray implements Stack {...}Class QueueViaArray implements Queue {...} Class TreeViaArray implements Tree {...}
Class DSFactoryViaArray implements DSFactory { Stack createStack() { return new StackViaArray(); } Queue createQueue() { return new QueueViaArray(); } Tree createTree() { return new TreeViaArray(); }}
Abstract Factory – sample Abstract Factory – sample codecode
Class ClientDriver { void main() { // Using Array-based structures DSFactory af = new DSFactoryViaArray(); DataStructsClient dsc = new DataStructsClient(af); dsc.op(); // Using list-based structures DSFactory af2 = new DSFactoryViaList(); DataStructsClient dsc2 = new DataStructsClient(af2); dsc2.op(); }}
Class StackViaList implements Stack {...}Class QueueViaList implements Queue {...} Class TreeViaList implements Tree {...}
Class DSFactoryViaList implements DSFactory { Stack createStack() { return new StackViaList(); } Queue createQueue() { return new QueueViaList(); } Tree createTree() { return new TreeViaList(); }}
Abstract Factory – Abstract Factory – commentscomments
Use the Abstract Factory when Use the Abstract Factory when a a clientclient needs needs to useto use one of multiple one of multiple familiesfamilies of products of products
It is hard to add new types of products since It is hard to add new types of products since adding a new product means adding a new adding a new product means adding a new factory method to the AbstractFactory factory method to the AbstractFactory interface and its all subclassesinterface and its all subclasses
When families of products are different When families of products are different combinations of the same set of products combinations of the same set of products and/or the # of families is large, many and/or the # of families is large, many ConcreteFactory subclasses would be ConcreteFactory subclasses would be needed. In this case, the Prototype pattern needed. In this case, the Prototype pattern may be employedmay be employed
PrototypePrototype
Design purposeDesign purpose– Create a set of almost identical Create a set of almost identical
objects whose type is determined at objects whose type is determined at runtimeruntime
Pattern summaryPattern summary– Assume that a prototype instance is Assume that a prototype instance is
known; clone it whenever a new known; clone it whenever a new instance is neededinstance is needed
Prototype – examplesPrototype – examples
Kitchen showroomKitchen showroom– A showroom may have all cabinets in A showroom may have all cabinets in
one style, counters in a different style, one style, counters in a different style, etcetc
– Instead of creating a factory for each Instead of creating a factory for each possible combination of different possible combination of different furniture in different styles, each furniture in different styles, each individual showroom is given a individual showroom is given a prototype of each type of furniture of a prototype of each type of furniture of a stylestyle
– Each prototype can clone itselfEach prototype can clone itself
Prototype - structurePrototype - structure
Client+anOperation()
Prototype+clone()+otherOperations()
Return a copy of itself
ConcreteProduct1
+clone();+otherOperations();
ConcreteProduct2
+cone();+otherOperations();
Return a copy of itself
Prototype p = prototype.clone();
prototype
Prototype - participantsPrototype - participants
PrototypePrototype– defines the interface (an operation) of defines the interface (an operation) of cloning cloning
itselfitself.. ConcreteProduct1 and ConcreteProduct2ConcreteProduct1 and ConcreteProduct2
– Concrete objects that can clone themselvesConcrete objects that can clone themselves.. ClientClient
– Obtain more objects by asking them to clone Obtain more objects by asking them to clone themselvesthemselves..
CollaborationsCollaborations– The client asks The client asks the prototype to clone itself the prototype to clone itself
for a new object of the prototypefor a new object of the prototype. .
Shallow vs. deep cloning Shallow vs. deep cloning (copying)(copying)
Client+anOperation()
:Prototype+clone()-Nested:ref
prototype ref:Nested
+op()-data
Client+anOperation()
:Prototype+clone()-Nested:ref
prototype ref:Nested
+op()-data
clone:Prototype
+clone()-Nested:ref
ref
Client+anOperation()
:Prototype+clone()-Nested:ref
prototype ref:Nested
+op()-data
clone:Prototype
+clone()-Nested:ref
ref clone:Nested+op()-data
Shallow cloning
Deep cloning
Shallow vs. deep cloningShallow vs. deep cloning
Shallow cloning: sample codeShallow cloning: sample code
Class Prototype implements Cloneable {Class Prototype implements Cloneable { private int x;private int x; private Nested ref = new Nested();private Nested ref = new Nested();
public Prototype clone() {public Prototype clone() { Prototype p = new Prototype()Prototype p = new Prototype() p.x = this.x;p.x = this.x; p.ref = this.ref; return p;return p; }}}}Class Nested { int data;int data; public void op() {}public void op() {}}}Class Client {Class Client { private Prototype prototype = private Prototype prototype = new Prototype();new Prototype(); public void op() {public void op() { Prototype clone = Prototype clone =
prototype.clone();prototype.clone(); // use clone// use clone}}
Deep cloning: sample codeDeep cloning: sample code
Class Prototype implements Cloneable Class Prototype implements Cloneable {{
private int x;private int x; private Nested ref = new Nested();private Nested ref = new Nested(); public Prototype clone() {public Prototype clone() { Prototype p = new Prototype()Prototype p = new Prototype() p.x = this.x;p.x = this.x; p.ref = this.ref.clone();p.ref = this.ref.clone(); return p;return p; }}}}Class Nested Class Nested implements Cloneable {implements Cloneable { int data;int data; public void op() {}public void op() {} public Nested clone() {public Nested clone() { Nested n = new Nested()Nested n = new Nested() n.data = this.data;n.data = this.data; return n;return n; }}}}Class Client {Class Client { // the same Client as for Shallow // the same Client as for Shallow
cloningcloning}}
Abstract Factory – Two Abstract Factory – Two FamiliesFamilies
StackViaArray
StackViaList
QueueViaArray
Data Structures Via Array
Data Structures Via List
Stack
Queue QueueViaList
Prototype – sample codePrototype – sample code
Class PrototypeClient { Stack sp; Queue qp; PrototypeClient( Stack s, Queue q) { this.s = s; this.q = q; } void op() { Stack s1 = sp.clone(); Stack s2 = sp.clone(); ... Queue q1 = qp.clone(); Queue q2 = qp.clone(); }}
Interface Queue { Queue clone(); ...}
Interface Stack { Stack clone(); ...} Class StackViaArray implements Stack { Stack clone() { StackViaArray s = new StackViaArray(); s.attr = this.attr; return s; } ...}Class StackViaList implements Stack { Stack clone() { StackViaList s = new StackViaList(); s.attr = this.attr; return s; } ...}
Prototype – sample codePrototype – sample code
Class QueueViaArray implements Queue { Queue clone() { QueueViaArray s = new QueueViaArray(); s.attr = this.attr; return s; } ...}Class QueueViaList implements Queue { Queue clone() { QueueViaList s = new QueueViaList(); s.attr = this.attr; return s; } ...}
Interface Queue { Queue clone(); ...}
Class ClientDriver { void main() { Stack s = new StackViaArray(); Queue q = new QueueViaList(); PrototypeClient pc = new PrototypeClient(s, q); pc.op(); }}
Prototype – commentsPrototype – comments
If the clone does not need to be If the clone does not need to be identical as its original, a factory identical as its original, a factory method may be usedmethod may be used
Be aware of the shallow cloning Be aware of the shallow cloning problem – to the deepest levelproblem – to the deepest level
When prototypes can be grouped When prototypes can be grouped in a small # of different in a small # of different combinations, the Abstract combinations, the Abstract Factory may be suitableFactory may be suitable
SingletonSingleton
Design purposeDesign purpose– Ensure there is exactly one instance Ensure there is exactly one instance
of a classof a class– Be able to obtain the instance from Be able to obtain the instance from
anywhere in the applicationanywhere in the application Pattern summaryPattern summary
– Make the Make the constructorconstructor of class of class private private oror protected protected, define a , define a private static private static attributeattribute of the class, define a of the class, define a public public accessoraccessor to it. to it.
Singleton – an exampleSingleton – an example
A concrete factory in the Abstract A concrete factory in the Abstract Factory pattern in most cases Factory pattern in most cases should have only one instance – should have only one instance – all objects are produced by the all objects are produced by the same factorysame factory
In JGrasp (or any IDE), we want In JGrasp (or any IDE), we want one JVM (Singleton) for all Java one JVM (Singleton) for all Java programs.programs.
Singleton - structureSingleton - structure
return soleInstance;
Singleton+static getInstance();+operations()-data
soleInstance
<<static>>
Singleton - participantsSingleton - participants
SingletonSingleton– Declare all constructors private and provide Declare all constructors private and provide
only one entry for obtaining a reference to only one entry for obtaining a reference to the sole instancethe sole instance..
ClientClient– Clients can get to the sole instance of Clients can get to the sole instance of
Singleton by asking Singleton to return a Singleton by asking Singleton to return a reference to itreference to it..
CollaborationsCollaborations– A client can only call getInstance() to get a A client can only call getInstance() to get a
reference to the sole instancereference to the sole instance..– A client cannot create any instance of A client cannot create any instance of
SingletonSingleton
Singleton – sample codeSingleton – sample code
class Singleton {class Singleton { // since private no client can // since private no client can
accessaccess // this reference directly// this reference directly private static Singleton private static Singleton
soleInstance soleInstance = new Singleton();= new Singleton(); private int data;private int data; // since protected, no client can // since protected, no client can // create any instance directly// create any instance directly protected Singleton();protected Singleton(); // the only entry for clients to get // the only entry for clients to get
aa // reference to the sole instane// reference to the sole instane public static Singleton public static Singleton
getInstance() {getInstance() { return soleInstance;return soleInstance; }} // other operations// other operations public void operations() { }public void operations() { }}}
class Client1 {class Client1 { void anOperation() {void anOperation() { // Singleton ref = new Singleton();// Singleton ref = new Singleton(); // illegal since Singleton() is // illegal since Singleton() is
protectedprotected Singleton ref = Singleton ref =
Singleton.getInstance();Singleton.getInstance(); ref.operations();ref.operations(); }}} }
class Client2 {class Client2 { void anOperation() {void anOperation() { Singleton ref = Singleton ref =
Singleton.getInstance();Singleton.getInstance(); // use ref// use ref }}}}
NOTE: objects of Client1 and NOTE: objects of Client1 and Client2 would all share the Client2 would all share the same sole instance of same sole instance of Singleton.Singleton.
Singleton – commentsSingleton – comments
Lazy loadingLazy loading– If the object of Singleton is complex, it may take much If the object of Singleton is complex, it may take much
resource to create. We better create the object only when it resource to create. We better create the object only when it is referenced – lazy loadingis referenced – lazy loading
– Change the body of Change the body of getInstance()getInstance() with the following with the following if (soleInstance == null) {if (soleInstance == null) { soleInstance = new Singleton();soleInstance = new Singleton(); }} return soleInstance;return soleInstance; Not thread safe (Java)Not thread safe (Java)
– Two concurrent threads could cause two instances created Two concurrent threads could cause two instances created if executed concurrentlyif executed concurrently
– Solution: Make getInstance() Solution: Make getInstance() synchronizedsynchronized All static members?All static members?
– Since there is only one instance, why don’t we just make all Since there is only one instance, why don’t we just make all members static?members static?
– If yes, then the instance may not fit with the rest of the If yes, then the instance may not fit with the rest of the application: e.g., display(Employee) would not work if application: e.g., display(Employee) would not work if singleton CEO is all staticsingleton CEO is all static
BuilderBuilder
Design purposeDesign purpose– Separate the construction of a Separate the construction of a
complex object from its complex object from its representation so that the same representation so that the same construction process can create construction process can create different representationsdifferent representations
Pattern summaryPattern summary– Use a builder to encapsulate the Use a builder to encapsulate the
representation.representation.
Builder – an exampleBuilder – an example
Language translatorLanguage translator– Translate a Java programs to other Translate a Java programs to other
programming languages (C++, Delphi)programming languages (C++, Delphi)– The translation process is the same for The translation process is the same for
all target languages – mapping all target languages – mapping “import” to something (“include” in “import” to something (“include” in C++)C++)
– Each target language has a Each target language has a builderbuilder to to handle each keyword/structurehandle each keyword/structure
Builder - structureBuilder - structure
Director+buildProduct()
Builder+buildPartA()+buildPartB()+buildPartC()
ProductA
BuilderA+buildPartA()+buildPartB()+buildPartC()+getProductA()
For (every part needed in product) if (part A) builder.buildPartA(); else if (part B) builder.buildPartB(); else if (part C) builder.buildPartC();}
builder
ProductB
Client+madeProduct()
director
BuilderB+buildPartA()+buildPartB()+buildPartC()+getProductB()
Builder - participantsBuilder - participants
ProductA and ProductBProductA and ProductB– Concrete products that are created by different builders.Concrete products that are created by different builders.
Director Director – A class that knows what steps it takes to build a product, but it A class that knows what steps it takes to build a product, but it
does not know how each step is to be carried out or does not does not know how each step is to be carried out or does not know how each part may be added to the final productknow how each part may be added to the final product
BuilderBuilder– Defines an interface for concrete buildersDefines an interface for concrete builders
BuildlerA and BuilderBBuildlerA and BuilderB– Concrete builders who know to construct each part of the Concrete builders who know to construct each part of the
product and add it to the final productproduct and add it to the final product ClientClient
– A client selects a director and a concrete builder to build the A client selects a director and a concrete builder to build the product it needs. The client asks the concrete builder to return product it needs. The client asks the concrete builder to return the final constructed productthe final constructed product
CollaborationsCollaborations– The director knows what parts are needed for the final product The director knows what parts are needed for the final product
and the selected concrete builder knows how to product the part and the selected concrete builder knows how to product the part and add it to the final product. and add it to the final product.
Builder – sequence diagramBuilder – sequence diagram
Client ProductDirector ConcreteBuilder
builder = constructor()
constructor(builder)
constructor()
buildPartA()
buildPartB()
buildPartC()
addPartA()
addPartB()
addPartC()
getProduct()
buildProduct()
Builder – sample codeBuilder – sample code
Class Product {Class Product {addPartA() {}addPartA() {}addPartB() {}addPartB() {}
addPartC() {}addPartC() {}……}}Class ConcreteBuilderClass ConcreteBuilder
implements Builder {implements Builder {Private: Product p;Private: Product p;
ConcreteBuilder() {ConcreteBuilder() {p = new Product();p = new Product();
}}buildPartA() {… p.addPartA(); … }buildPartA() {… p.addPartA(); … }buildPartB() {… p.addPartB(); … }buildPartB() {… p.addPartB(); … }buildPartC() {… p.addPartC(); … }buildPartC() {… p.addPartC(); … }Product getResult() { return p; }Product getResult() { return p; }
}}
Class Director {Class Director {private Builder b;private Builder b;
Director(Builder b) {this.b = b;}Director(Builder b) {this.b = b;}void buildProduct() {void buildProduct() {
for each part in Product {for each part in Product {if (partA) if (partA)
b.buildPartA();b.buildPartA(); else if (partB) else if (partB)
b.buildPartB();b.buildPartB(); else if (partC) else if (partC)
b.buildPartC();b.buildPartC(); }} }}}}client() {client() { Builder b = new Builder b = new
ConcreteBuilder();ConcreteBuilder(); Director d = new Director(b);Director d = new Director(b); d.buildProduct()d.buildProduct() FinalProduct fp = b.getResult();FinalProduct fp = b.getResult();}}