Java Design Patterns Overview
Java Design Patterns Overview
Vanderbilt University
Nashville, Tennessee, USA
Learning Objectives in this Lesson
• Know what topics we’ll cover
2
Learning Objectives in this Lesson
• Know what topics we’ll cover
• Learn where to find Java
JDK/JRE & IDE platforms
3
Learning Objectives in this Lesson
• Know what topics we’ll cover
• Learn where to find Java
JDK/JRE & IDE platforms
• Be aware of other digital
learning resources
4
Learning Objectives in this Lesson
• Know what topics we’ll cover
• Learn where to find Java
JDK/JRE & IDE platforms
• Be aware of other digital
learning resources
• Be able to locate examples
of Java programs
See [Link]/douglascraigschmidt/LiveLessons
5
Overview of this Course
Overview of this Course
• We focus on programming “Gang-of-Four” (GoF) design patterns in Java, e.g.
7
Overview of this Course
• We apply many GoF patterns in the context of a case study app
Design Problem Pattern
Non-extensible & error-prone designs Composite
Minimizing impact of variability Bridge
Inflexible expression tree traversal Iterator
Obtrusive behavior changes Strategy
Scattered operation implementations Command
Inflexible creation of variabilities Factory Method
Non-extensible tree operations Visitor
Incorrect user request ordering State
Non-extensible operating modes Template Method
Inflexible expression input processing Interpreter
Inflexible interpreter output Builder
Minimizing global variable liabilities Singleton
See [Link]/douglascraigschmidt/LiveLessons/tree/master/ExpressionTree
8
Overview of this Course
• We apply many GoF patterns in the context of a case study app (Day 1)
Design Problem Pattern
Non-extensible & error-prone designs Composite
Minimizing impact of variability Bridge
Inflexible expression tree traversal Iterator
Obtrusive behavior changes Strategy
Scattered operation implementations Command
Inflexible creation of variabilities Factory Method
Non-extensible tree operations Visitor
Incorrect user request ordering State
Non-extensible operating modes Template Method
Inflexible expression input processing Interpreter
Inflexible interpreter output Builder
Minimizing global variable liabilities Singleton
9
Overview of this Course
• We apply many GoF patterns in the context of a case study app (Day 2)
Design Problem Pattern
Non-extensible & error-prone designs Composite
Minimizing impact of variability Bridge
Inflexible expression tree traversal Iterator
Obtrusive behavior changes Strategy
Scattered operation implementations Command
Inflexible creation of variabilities Factory Method
Non-extensible tree operations Visitor
Incorrect user request ordering State
Non-extensible operating modes Template Method
Inflexible expression input processing Interpreter
Inflexible interpreter output Builder
Minimizing global variable liabilities Singleton
10
Overview of this Course
• This course focuses on both pattern-oriented design & implementation topics
ExpressionTree
exprTree = ...;
Visitor printVisitor
= ...;
11
Overview of this Course
• The Java expression tree processing app we cover is available on github
See [Link]/douglascraigschmidt/LiveLessons/tree/master/ExpressionTree
12
Accessing Java
Features & Functionality
Accessing Java Features & Functionality
• The Java runtime environment (JRE) supports Java features
See [Link]/javase/8/docs/technotes/guides/install/install_overview.html
14
Accessing Java Features & Functionality
• The Java runtime environment (JRE) supports Java features
• Intellij & Eclipse are popular
Java IDE platforms
See [Link]/2017/03/[Link]
16
Accessing Java Features & Functionality
• The Java runtime environment (JRE) supports Java features
• Intellij & Eclipse are popular
Java IDE platforms
• Most Java features are
supported by Android API
level 24 (& beyond)
• Make sure to get Android
Studio 3.x or later if you
use Java 8!
See [Link]/studio/preview/features/[Link]
17
Accessing Java Features & Functionality
• Java source code is available online
• For downloading
[Link]/[Link]
18
Other Digital
Learning Resources
Other Digital Learning Resources
• Addition pattern topics not covered here appear in my LiveLessons course
See [Link]/~schmidt/LiveLessons/DPiJava
20
Other Digital Learning Resources
• There’s a Facebook group dedicated to discussing Java design pattern topics
See [Link]/groups/623398741056491
21
Other Digital Learning Resources
• Several related Live Training courses on Java are coming soon
See [Link]/~schmidt/DigitalLearning
22
Other Digital Learning Resources
• See my website for many more videos
& screencasts related to programming
with patterns, frameworks, Java, etc.
See [Link]/~schmidt/DigitalLearning
23
Other Digital Learning Resources
• See my website for many more videos
& screencasts related to programming
with patterns, frameworks, Java, etc.
• Videos from my MOOC “Pattern-
Oriented Software Architecture”
are relevant!
See [Link]/playlist?list=PLZ9NgFYEMxp6CHE-QQ040tlDILNcBqJnc
24
Other Digital Learning Resources
• See my website for many more videos
& screencasts related to programming
with patterns, frameworks, Java, etc.
• Videos from my MOOC “Pattern-
Oriented Software Architecture”
are relevant!
26
See [Link]/wiki/Design_Patterns
Other Digital Learning Resources
• The “POSA” books contain good sources
of material on other types of patterns &
pattern relationships
27
See [Link]/~schmidt/POSA
End of Course Overview
Overview of the Expression
Tree Processing App Case
Study (Part 1)
Douglas C. Schmidt
Learning Objectives in This Lesson
• Understand the goals of the object-oriented (OO) expression tree case study.
−5*(3+4)
−35
Learning Objectives in This Lesson
• Understand the goals of the object-oriented (OO) expression tree case study.
• Recognize the key behavioral & structural
properties in the expression tree domain.
−5*(3+4)
−35
Douglas C. Schmidt
Lesson Introduction
Lesson Introduction
• While patterns can be discussed abstractly,
effective design & programming practices
are not learned best by generalities.
programs.
• This lesson describes a realistic—yet tractable
—expression tree processing app we’ll use as
−35
a case study throughout the course.
Lesson Introduction
• While patterns can be discussed abstractly,
effective design & programming practices
are not learned best by generalities.
• Instead, it’s usually better to see how
patterns can help improve nontrivial
programs.
• This lesson describes a realistic—yet tractable
—expression tree processing app we’ll use as
a case study throughout the course.
• This case study applies many “Gang of
Four” (GoF) patterns.
See [Link]/wiki/Design_Patterns
Douglas C. Schmidt
Expression Tree Processing App
Case Study Goals
Expression Tree Processing App Case Study Goals
• Develop an OO expression Design Problem Pattern
tree processing app using
Non-extensible & error-prone designs Composite
patterns & frameworks.
Minimizing impact of variability Bridge
Inflexible expression input processing Interpreter
Inflexible interpreter output Builder
−5*(3+4)
Naturally, these patterns apply to more than expression tree processing apps!
Expression Tree Processing App Case Study Goals
• This app uses expression trees to remove Binary
ambiguity in algebraic expressions. Nodes
×
− +
−5*(3+4)
−35 Unary
Node
5 3 4
Leaf
Nodes
See [Link]/wiki/Binary_expression_tree
Expression Tree Processing App Case Study Goals
• Compare/contrast algorithmic decomposition
& object-oriented (OO) approaches. ExpressionTree
Despite decades of
OO focus, algorithmic ComponentNode
decomposition is still
surprisingly common.
Composite
LeafNode
UnaryNode
CompositeBinary CompositeNegate
Node Node
Composite Composite
1 AddNode SubtractNode
Tree
Composite Composite
Node MultiplyNode DivideNode
0|1|2
Pattern- & Object-Oriented
Algorithmic Decomposition
Decomposition
See [Link]/windows/software-complexity-bringing-order-to-ch/199901062
Expression Tree Processing App Case Study Goals
• Demonstrate scope, commonality, & Product Product Product Product
Application Frameworks
Virtual Machine
System Libraries
Runtime
See [Link]/~schmidt/PDF/Commonality_Variability.pdf
Expression Tree Processing App Case Study Goals
• Demonstrate scope, commonality, &
variability (SCV) analysis as a means
to achieve systematic software
reuse.
−5*(3+4)
• Apply SCV in the context of the
expression tree processing app.
−35
Expression Tree Processing App Case Study Goals
• Show how to implement pattern- ExpressionTree exprTree = ...;
oriented OO frameworks & Visitor printVisitor = ...;
functional programs in Java.
for (Iterator<ExpressionTree> iter
= [Link]();
[Link]();
)
[Link]().accept
(printVisitor);
exprTree
.forEach
(node ->
[Link](printVisitor));
Expression Tree Processing App Case Study Goals
• Show how to implement pattern- ExpressionTree exprTree = ...;
oriented OO frameworks & Visitor printVisitor = ...;
functional programs in Java.
for (Iterator<ExpressionTree> iter
= [Link]();
[Link]();
)
[Link]().accept
(printVisitor);
Java-style GoF Iterator pattern
exprTree
.forEach
(node ->
[Link](printVisitor));
See [Link]/wiki/Iterator_pattern
Expression Tree Processing App Case Study Goals
• Show how to implement pattern- ExpressionTree exprTree = ...;
oriented OO frameworks & Visitor printVisitor = ...;
functional programs in Java.
for (Iterator<ExpressionTree> iter
= [Link]();
[Link]();
)
[Link]().accept
(printVisitor);
exprTree
.forEach
Java forEach() method (also (node ->
assumes ExpressionTree [Link](printVisitor));
implements Iterable)
Douglas C. Schmidt
Overview of the Expression Tree
Processing Domain
Overview of Expression Tree Processing Domain
• Expression trees consist of nodes containing
operators & operands.
×
− +
5 3 4
5 3 4
Leaf
Nodes
Overview of Expression Tree Processing Domain
• Operators have different precedence levels, Binary
different associativities, & different arities Nodes
×
− +
Unary
Node
5 3 4
See [Link]/wiki/Order_of_operations
Overview of Expression Tree Processing Domain
• Operators have different precedence levels, Binary
different associativities, & different arities, e.g., Nodes
• Precedence defines which operator ×
to perform first to evaluate a
mathematical expression.
• Multiplication takes − +
precedence over addition
• Operator locations in a Unary
tree unambiguously
designate precedence
Node
5 3 4
See [Link]/wiki/Operator_associativity
Overview of Expression Tree Processing Domain
• Operators have different precedence levels, Binary
different associativities, & different arities, e.g., Nodes
• Precedence defines which operator ×
to perform first to evaluate a
mathematical expression.
• Associativity determines how − +
operators of the same level of
precedence are grouped in
the absence of parentheses. Unary
• Arity defines the number of
Node
5 3 4
operands an operator takes.
• Multiplication & addition operators
have two arguments (arity == 2)
See [Link]/wiki/Arity
Overview of Expression Tree Processing Domain
• Operators have different precedence levels, Binary
different associativities, & different arities, e.g., Nodes
• Precedence defines which operator ×
to perform first to evaluate a
mathematical expression.
• Associativity determines how − +
operators of the same level of
precedence are grouped in
the absence of parentheses. Unary
• Arity defines the number of
Node
5 3 4
operands an operator takes.
• Multiplication & addition operators
have two arguments (arity == 2)
• The unary minus operator has one
argument (arity == 1)
Overview of Expression Tree Processing Domain
• Operands can be integers, doubles, variables, etc. Binary
• We'll just handle integers in this case study. Nodes
×
− +
Unary
Node
5 3 4
Leaf
Nodes
(Integers)
Overview of Expression Tree Processing Domain
• Operands can be integers, doubles, variables, etc. Binary
• We'll just handle integers in this case study. Nodes
• It’s easy to extend the app ×
to handle other types.
− +
Unary
Node
5.2 3.4 4.1
Leaf
Nodes
(Doubles)
Overview of Expression Tree Processing Domain
• Trees may be “evaluated” via different traversal
orders, e.g.,
• “In-order traversal” = -5×(3+4) ×
• “Pre-order traversal” = ×-5+34
• “Post-order traversal” = 5-34+×
• “Level-order traversal” = ×-+534
− +
5 3 4
Douglas C. Schmidt
Learning Objectives in This Lesson
• Understand the goals of the object-oriented (OO) expression tree case study.
• Recognize the key behavioral & structural
properties in the expression tree domain.
• Evaluate the functional & non- Functional
requirements
functional requirements of the
case study. Non-runtime Business
qualities constraints
Expre
ssion
Runtime −5*(3+4)
tree Technology
qualities proce constraints
−35 ssing
app
Patterns are best applied to address requirements, rather than applied blindly!
Learning Objectives in This Lesson
• Understand the goals of the object-oriented (OO) expression tree case study.
• Recognize the key behavioral & structural
properties in the expression tree domain.
• Evaluate the functional & non-
functional requirements of the
case study.
• Put all the pieces together.
Douglas C. Schmidt
Functional &
Non-Functional Requirements
of the Case Study
Functional & Non-Functional Requirements
• A functional requirement defines what a system should be able to do, i.e.,
the behavior it should perform.
−35
Case Study: Functional Requirements
• The succinct mode can be command-line
or GUI interface.
• In the GUI version, a user presses Android
buttons to enter expressions. −5*(3+4)
Iterator
Composite
BinaryNode …
Composite
LevelOrder
Iterator
InOrder
Iterator
Java
Queue
PostOrder Java
Iterator Stack
PreOrder
Strategy Iterator
Case Study: Non-Functional Requirements
• Apply a pattern-oriented OO design to simplify extensibility & portability, e.g.,
• Add new operations on the expression tree nodes
without modifying the tree structure or
implementation
Case Study: Non-Functional Requirements
• Apply a pattern-oriented OO design to simplify extensibility & portability, e.g.,
• Add new operations on the expression tree nodes
without modifying the tree structure or
implementation, e.g.,
• Print the contents of the expression
tree in various traversal orders
See [Link]/douglascraigschmidt/LiveLessons/tree/master/ExpressionTree
Putting All the Pieces Together
• The expression tree processing app provides a realistic case study of how to
apply GoF patterns.
• All the case study code is written in Java.
• There are command-line & Android GUI-
based versions. −5*(3+4)
−35
See [Link]/douglascraigschmidt/LiveLessons/tree/master/ExpressionTree
The Object-Oriented Design
of the Expression Tree
Processing App
Douglas C. Schmidt
Learning Objectives in This Lesson
• Understand the OO design of the expression tree processing app.
ExpressionTree
ComponentNode
Composite
LeafNode
UnaryNode
CompositeBinary CompositeNegate
Node Node
Composite Composite
AddNode SubtractNode
Composite Composite
MultiplyNode DivideNode
Polymorphism
Object-
Extensibility Oriented Abstraction
Design
Encapsulation
PostOrder
Iterator
PreOrder
Iterator
Bridge
ExpressionTree ComponentNode
InOrder
Iterator
Java
Queue
PostOrder Java
Iterator Stack
PreOrder
Strategy Iterator
×
− +
5 3 4
OO Design of Expression Tree Processing App
• Conduct scope, commonality, & variability analysis to determine stable APIs
& variable extension points.
×
− +
5 3 4
See [Link]/~schmidt/PDF/Commonality_Variability.pdf
OO Design of Expression Tree Processing App
• Conduct scope, commonality, & variability analysis to determine stable APIs
& variable extension points.
• Model a tree as a collection of nodes. Binary
Nodes
×
− +
Unary
Node
5 3 4
Leaf
Nodes
(Integers)
OO Design of Expression Tree Processing App
• Conduct scope, commonality, & variability analysis to determine stable APIs
& variable extension points.
• Model a tree as a collection of nodes. Binary
Nodes
×
− +
Note the different types
of nodes in a tree.
Unary
Node
5 3 4
Leaf
Nodes
(Integers)
OO Design of Expression Tree Processing App
• Conduct scope, commonality, & variability analysis to determine stable APIs
& variable extension points.
ExpressionTree
• Model a tree as a collection of nodes.
• Represent nodes as class hierarchy,
capturing properties of each node. ComponentNode
• e.g., the “arities” (binary & unary
nodes)
Composite
LeafNode
UnaryNode
CompositeBinary CompositeNegate
Node Node
Composite Composite
AddNode SubtractNode
Composite Composite
MultiplyNode DivideNode
See [Link]/wiki/Arity
OO Design of Expression Tree Processing App
• Apply “Gang of Four” (GoF) patterns to guide the development of a
framework of extensible classes.
Visitor
Bridge
ExpressionTree ComponentNode
Visitor
<< accept >>
<< create >>
Composite LeafNode
UnaryNode
Iterator
Composite
BinaryNode …
Composite
LevelOrder
Iterator
InOrder
Iterator
Java
Queue
PostOrder Java
Iterator Stack
PreOrder
Strategy Iterator
See [Link]/~schmidt/[Link]
OO Design of Expression Tree Processing App
• Apply “Gang of Four” (GoF) patterns to guide the development of a
framework of extensible classes.
• A framework is an integrated set of software components that collaborate
to provide a reusable architecture for a family of related applications.
• Frameworks exhibit three characteristics that differentiate them from other
forms of systematic reuse. Application-Specific Functionality
See [Link]/wiki/Inversion_of_control
OO Design of Expression Tree Processing App
• Apply “Gang of Four” (GoF) patterns to guide the development of a
framework of extensible classes.
• A framework is an integrated set of software components that collaborate
to provide a reusable architecture for a family of related applications.
• Frameworks exhibit three characteristics that differentiate them from other
forms of systematic reuse. Application-Specific Functionality
1. Inversion of control (IoC)
• The framework controls the
main execution thread
OO Design of Expression Tree Processing App
• Apply “Gang of Four” (GoF) patterns to guide the development of a
framework of extensible classes.
• A framework is an integrated set of software components that collaborate
to provide a reusable architecture for a family of related applications.
• Frameworks exhibit three characteristics that differentiate them from other
forms of systematic reuse. Application-Specific Functionality
1. Inversion of control (IoC)
• The framework controls the
main execution thread
• Decides how/when to run
app code via callbacks
See [Link]/wiki/Callback_(computer_programming)
OO Design of Expression Tree Processing App
• Apply “Gang of Four” (GoF) patterns to guide the development of a
framework of extensible classes.
• A framework is an integrated set of software components that collaborate
to provide a reusable architecture for a family of related applications.
• Frameworks exhibit three characteristics that differentiate them from other
forms of systematic reuse. Application-Specific Functionality
1. Inversion of control (IoC)
• The framework controls the
main execution thread
• Decides how/when to run
app code via callbacks
• e.g., an Android looper
dispatches a handler,
which then dispatches
a runnable
See [Link]/android-core-looper-handler-and-handlerthread-bd54d69fe91a
OO Design of Expression Tree Processing App
• Apply “Gang of Four” (GoF) patterns to guide the development of a
framework of extensible classes.
• A framework is an integrated set of software components that collaborate
to provide a reusable architecture for a family of related applications.
• Frameworks exhibit three characteristics that differentiate them from other
forms of systematic reuse. Application-Specific Functionality
1. Inversion of control (IoC)
• The framework controls the
main execution thread
• Decides how/when to run
app code via callbacks
• IoC is often called “The
Hollywood Principle”
See [Link]/~schmidt/Coursera/articles/[Link]
OO Design of Expression Tree Processing App
• Apply “Gang of Four” (GoF) patterns to guide the development of a
framework of extensible classes.
• A framework is an integrated set of software components that collaborate
to provide a reusable architecture for a family of related applications.
• Frameworks exhibit three characteristics that differentiate them from other
forms of systematic reuse. Application-Specific Functionality
1. Inversion of control (IoC)
2. Domain-specific structure
& functionality
Stock Mobile
Trading Social Apps
Media
Networking
Databases
GUIs
See [Link]/wiki/Domain-driven_design
OO Design of Expression Tree Processing App
• Apply “Gang of Four” (GoF) patterns to guide the development of a
framework of extensible classes.
• A framework is an integrated set of software components that collaborate
to provide a reusable architecture for a family of related applications.
• Frameworks exhibit three characteristics that differentiate them from other
forms of systematic reuse. Application-Specific Functionality
1. Inversion of control (IoC)
2. Domain-specific structure
& functionality
• e.g., capabilities that can
be reused in 1+ domain(s) Stock Mobile
Trading Social Apps
Media
Application
domains
Networking
Databases
Infrastructure GUIs
domains
OO Design of Expression Tree Processing App
• Apply “Gang of Four” (GoF) patterns to guide the development of a
framework of extensible classes.
• A framework is an integrated set of software components that collaborate
to provide a reusable architecture for a family of related applications.
• Frameworks exhibit three characteristics that differentiate them from other
forms of systematic reuse. Application-Specific Functionality
1. Inversion of control (IoC)
2. Domain-specific structure
& functionality
• e.g., capabilities that can
be reused in 1+ domain(s) Stock Mobile
Trading Social Apps
Media
Networking
Databases
GUIs
Networking
Databases
GUIs
OO Design of Expression Tree Processing App
• Apply “Gang of Four” (GoF) patterns to guide the development of a
framework of extensible classes.
• A framework is an integrated set of software components that collaborate
to provide a reusable architecture for a family of related applications.
• Frameworks exhibit three characteristics that differentiate them from other
forms of systematic reuse. Application-Specific Functionality
1. Inversion of control (IoC)
2. Domain-specific structure
& functionality
3. Semi-complete applications
Mobile
• Hook methods plug app Stock
Social Apps
Trading
logic into the framework Media
Networking
Databases
GUIs
See [Link]/davelaribee/2008/06/16/hook-methods
OO Design of Expression Tree Processing App
• Apply “Gang of Four” (GoF) patterns to guide the development of a
framework of extensible classes.
• A framework is an integrated set of software components that collaborate
to provide a reusable architecture for a family of related applications.
• Frameworks exhibit three characteristics that differentiate them from other
forms of systematic reuse. Application-Specific Functionality
1. Inversion of control (IoC)
2. Domain-specific structure
& functionality
3. Semi-complete applications
Mobile
• Hook methods plug app Stock
Social Apps
Trading
logic into the framework Media
e.g., Java Runnable is an abstract interface providing basis for concrete variants.
OO Design of Expression Tree Processing App
• Integrate pattern-oriented language & library features with frameworks.
• Both an app-specific framework…
ExpressionTree tree = ...;
Visitor printVisitor = ...;
for(Iterator<ExpressionTree> iter =
[Link](traversalOrder);
[Link]();)
[Link]().accept(printVisitor);
Iterator
Composite
BinaryNode …
Composite
LevelOrder
Iterator
InOrder
Iterator
Java
Queue
PostOrder Java
Iterator Stack
PreOrder
Strategy Iterator
See [Link]/windows/software-complexity-bringing-order-to-ch/199901062
Overview of the Patterns Used
in the Expression Tree
Processing App
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize which GoF patterns the expression tree processing app uses.
See [Link]/wiki/Composite_pattern
Design Problems & GoF Pattern Solutions
Design Problem Pattern
Minimizing impact of variability Bridge
Bridge intent
• Separate an abstraction from its implementation(s) so the two can vary independently
See [Link]/wiki/Bridge_pattern
Design Problems & GoF Pattern Solutions
Design Problem Pattern
Scattered & fixed request implementations Command
Command intent
• Encapsulate the request for a service as an object
ConcreteCommand
See [Link]/wiki/Command_pattern
Design Problems & GoF Pattern Solutions
Design Problem Pattern
Inflexible creation of variabilities Factory Method
Factory Method intent
• Provide an interface for creating an object, but leave the choice of the object’s
concrete type to a subclass
See [Link]/wiki/Factory_method_pattern
Design Problems & GoF Pattern Solutions
Design Problem Pattern
Inflexible expression tree traversal Iterator
Iterator intent
• Access elements of an aggregate without exposing its representation
See [Link]/wiki/Iterator_pattern
Design Problems & GoF Pattern Solutions
Design Problem Pattern
Obtrusive behavior changes Strategy
Strategy intent
• Define a family of algorithms, encapsulate each one, & make them interchangeable to
let clients & algorithms vary independently
See [Link]/wiki/Strategy_pattern
Design Problems & GoF Pattern Solutions
Design Problem Pattern
Non-extensible tree operations Visitor
Visitor intent
• Centralize operations on an object structure so that they can vary independently, but
still behave polymorphically
See [Link]/wiki/Visitor_pattern
Design Problems & GoF Pattern Solutions
Design Problem Pattern
Incorrect user request ordering State
State intent
• Allow an object to alter its behavior when its internal state changes—the object will
appear to change its class
See [Link]/wiki/State_pattern
Design Problems & GoF Pattern Solutions
Design Problem Pattern
Non-extensible operating modes Template Method
Template Method intent
• Provide a skeleton of an algorithm in a method, deferring some steps to subclasses
See [Link]/wiki/Template_method_pattern
Design Problems & GoF Pattern Solutions
Design Problem Pattern
Inflexible expression input processing Interpreter
Interpreter intent
• Given a language, define a representation for its grammar, along with an interpreter
that uses the representation to interpret sentences in the language
See [Link]/wiki/Interpreter_pattern
Design Problems & GoF Pattern Solutions
Design Problem Pattern
Inflexible interpreter output Builder
Builder intent
• Separate the construction of a complex object from its representation
See [Link]/wiki/Builder_pattern
Design Problems & GoF Pattern Solutions
Design Problem Pattern
Minimizing global variable liabilities Singleton
Singleton intent
• Ensure a class only has one instance & provide a global point of access
See [Link]/wiki/Singleton_pattern
Design Problems & GoF Pattern Solutions
Design Problem Pattern
Non-extensible & error-prone designs Composite
Minimizing impact of variability Bridge
Inflexible expression input processing Interpreter
Inflexible interpreter output Builder
Scattered request implementations Command
Inflexible creation of variabilities Factory Method
Inflexible expression tree traversal Iterator
Obtrusive behavior changes Strategy
Non-extensible tree operations Visitor
Incorrect user request ordering State
Non-extensible operating modes Template Method
Minimizing global variable liabilities Singleton
Naturally, these patterns apply to more than expression tree processing apps!
The Composite Pattern
Motivating Example
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Composite pattern ComponentNode
can be applied to make the expression
tree object structure more uniform &
extensible. Composite
LeafNode
UnaryNode
CompositeBinary CompositeNegate
Node Node
Composite Composite
AddNode SubtractNode
Composite Composite
MultiplyNode DivideNode
Douglas C. Schmidt
Motivating the Need for
the Composite Pattern in
the Expression Tree App
A Pattern for Structuring the Expression Tree
Purpose: Define the key internal data structure for the expression tree.
ExpressionTree
ComponentNode
Composite
LeafNode
UnaryNode
CompositeBinary CompositeNegate
Node Node
Composite
Composite simplifies adding new types of nodes (& new node operations).
Context: OO Expression Tree Processing App
• The design of an expression tree should reflect its “physical” structure.
×
− +
5 3 4
Context: OO Expression Tree Processing App
• The design of an expression tree should reflect its “physical” structure.
• e.g., the tree structure should contain
binary/unary operators & operands. Binary
Nodes
×
− +
Unary
Node 5 3 4
Leaf
Nodes
Context: OO Expression Tree Processing App
• Adding new operations on tree nodes should require little/no modifications to
the tree’s structure & implementation.
Operation 2: Evaluate
Operation 1: Print all “yield” of nodes in tree
values of nodes in tree ×
− +
5 3 4
See lesson on “Evaluating the Algorithmic Decomposition of the Expression Tree Processing App”
Problem: Non-Extensible & Error-Prone Designs
• Tightly coupling expression tree typedef struct TreeNode {
data structures & functionality enum { NUM, UNARY, BINARY } tag_;
impedes extensibility. short use_;
union {
char op_[3]; int num_;
1 } o_;
Tree #define num_ o_.num_
Node #define op_ o_.op_
0|1|2 union {
struct TreeNode *unary_;
struct { struct TreeNode *l_,
*r_;} binary_;
} c_;
#define unary_ c_.unary_
#define binary_ c_.binary_
} TreeNode;
See lesson on “Evaluating the Algorithmic Decomposition of the Expression Tree Processing App”
Problem: Non-Extensible & Error-Prone Designs
• Differentiating operators & operands via type tags & switch statements is
tedious & error-prone to program & maintain.
See [Link]/?SwitchStatementsSmell
Solution: Recursive Object Structure
• Model an expression tree as a recursive collection of nodes
×
− +
5 3 4
Solution: Recursive Object Structure
• Model an expression tree as a recursive collection of nodes, e.g.,
• Structure nodes into a hierarchy that
captures the properties of each node ×
− +
5 3 4
Solution: Recursive Object Structure
• Model an expression tree as a recursive collection of nodes, e.g.,
• Structure nodes into a hierarchy that
captures the properties of each node, e.g.,
• Leaf nodes contain no children
×
− +
5 3 4
Leaf
Nodes
Solution: Recursive Object Structure
• Model an expression tree as a recursive collection of nodes, e.g.,
• Structure nodes into a hierarchy that
captures the properties of each node, e.g.,
• Leaf nodes contain no children
×
• Unary nodes recursively contain
one child node − +
Unary
Node
5 3 4
Solution: Recursive Object Structure
• Model an expression tree as a recursive collection of nodes, e.g.,
• Structure nodes into a hierarchy that Binary
captures the properties of each node, e.g., × Nodes
• Leaf nodes contain no children
• Unary nodes recursively contain
one child node − +
• Binary nodes recursively contain
two child nodes
5 3 4
Solution: Recursive Object Structure
• Treat operators & operands uniformly
• e.g., minimize the distinction between Binary
“one vs. many” to avoid special cases. × Nodes
− +
Unary
Node
5 3 4
Leaf
Nodes
ComponentNode Interface Overview
• Interface for composable expression tree node objects
Interface methods
int getItem()
ComponentNode getLeftChild()
ComponentNode getRightChild()
void accept(Visitor visitor)
ComponentNode Interface Overview
• Interface for composable expression tree node objects
These methods access relevant fields (may
Interface methods be no-ops for some implementations).
int getItem()
ComponentNode getLeftChild()
ComponentNode getRightChild()
void accept(Visitor visitor)
ComponentNode Interface Overview
• Interface for composable expression tree node objects
Interface methods
int getItem()
ComponentNode getLeftChild()
ComponentNode getRightChild()
void accept(Visitor visitor)
See upcoming lessons on “The Iterator Pattern” & “The Visitor Pattern.”
ComponentNode Interface Overview
• Interface for composable expression tree node objects
Interface methods
int getItem()
ComponentNode getLeftChild()
ComponentNode getRightChild()
void accept(Visitor visitor)
Composite
LeafNode
UnaryNode
CompositeUnaryNode is a
ComponentNode & also has
a ComponentNode. CompositeBinary CompositeNegate
Node Node
Composite Composite
AddNode SubtractNode
Composite
LeafNode
UnaryNode
CompositeBinary CompositeNegate
2 Node Node
This is another way to
design this type of
inheritance hierarchy. Composite Composite
AddNode SubtractNode
Composite Composite
MultiplyNode DivideNode
The Composite Pattern
Structure & Functionality
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Composite pattern can be applied to make the expression
tree more uniform & extensible.
• Understand the structure & functionality of the Composite pattern.
Douglas C. Schmidt
Structure & Functionality
of the Composite Pattern
Composite GoF Object Structural
Intent
ComponentNode
• Treat individual objects & multiple,
recursively-composed objects
uniformly
Composite
LeafNode
UnaryNode
CompositeBinary CompositeNegate
Node Node
Composite Composite
AddNode SubtractNode
Composite Composite
MultiplyNode DivideNode
See [Link]/wiki/Composite_pattern
Composite GoF Object Structural
Applicability
ComponentNode
• Objects must be composed
recursively
Composite
LeafNode
UnaryNode
CompositeBinary CompositeNegate
Node Node
Composite Composite
AddNode SubtractNode
Composite Composite
e.g., CompositeBinaryNode MultiplyNode DivideNode
Composite Composite
AddNode SubtractNode
Composite Composite
MultiplyNode DivideNode
e.g., LeafNodes & Composite
*Nodes all share the same API.
Composite GoF Object Structural
Applicability
ComponentNode
• Objects must be composed
recursively
• And no distinction between Composite
LeafNode
individual & composed UnaryNode
elements
• And objects in structure can CompositeBinary CompositeNegate
be treated uniformly Node Node
Composite Composite
AddNode SubtractNode
Composite Composite
MultiplyNode DivideNode
e.g., LeafNodes & Composite
*Nodes are (largely) treated the
same by operations on a tree.
See upcoming lessons on “The Iterator Pattern” & “The Visitor Pattern.”
Composite GoF Object Structural
Structure & participants
Composite GoF Object Structural
Structure & participants
CompositeUnaryNode,
CompositeBinaryNode,
CompositeAddNode, etc.
Composite GoF Object Structural
Structure & participants
LeafNode
The Composite Pattern
Implementation in Java
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Composite pattern can be applied to make the expression
tree more uniform & extensible.
• Understand the structure & functionality of the Composite pattern.
• Know how to implement the Composite pattern in Java.
Douglas C. Schmidt
Implementing the Composite
Pattern in Java
Composite GoF Object Structural
Composite example in Java
• Build an expression tree based on recursively composed objects.
ComponentNode l1 =
new LeafNode(5);
ComponentNode l2 =
new LeafNode(3);
ComponentNode l3 =
new LeafNode(4);
l1 l2 l3
Composite GoF Object Structural
Composite example in Java
• Build an expression tree based on recursively composed objects.
ComponentNode l1 =
new LeafNode(5);
ComponentNode l2 =
new LeafNode(3); u1 b1
ComponentNode l3 =
new LeafNode(4);
ComponentNode u1 =
new CompositeNegateNode(l1);
ComponentNode b1 = l1 l2 l3
new CompositeAddNode(l2, l3);
Composite GoF Object Structural
Composite example in Java
• Build an expression tree based on recursively composed objects.
ComponentNode l1 =
new LeafNode(5); b2
ComponentNode l2 =
new LeafNode(3); u1 b1
ComponentNode l3 =
new LeafNode(4);
ComponentNode u1 =
new CompositeNegateNode(l1);
ComponentNode b1 = l1 l2 l3
new CompositeAddNode(l2, l3);
ComponentNode b2 =
new CompositeMultiplyNode(u1, b1);
Composite GoF Object Structural
Composite example in Java
• Build an expression tree based on recursively composed objects.
ComponentNode l1 =
new LeafNode(5); b2
ComponentNode l2 =
new LeafNode(3); u1 b1
ComponentNode l3 =
new LeafNode(4);
ComponentNode u1 =
new CompositeNegateNode(l1);
ComponentNode b1 = l1 l2 l3
new CompositeAddNode(l2, l3);
ComponentNode b2 =
new CompositeMultiplyNode(u1, b1);
See [Link]/webfolder/technetwork/tutorials/obe/java/gc01/[Link]
Composite GoF Object Structural
Composite example in Java
• Build an expression tree based on recursively composed objects.
ComponentNode exprTree =
makeExpressionTree
("-5 * (3 + 4)");
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Composite pattern can be applied to make the expression
tree more uniform & extensible.
• Understand the structure & functionality of the Composite pattern.
• Know how to implement the Composite pattern in Java.
• Be aware of other considerations when applying the Composite pattern.
Douglas C. Schmidt
Other Considerations of
the Composite Pattern
Composite GoF Object Structural
Consequences ExpressionTree exprTree = ...;
+ Uniformity Visitor visitor = ...;
• Treat components the
same regardless of for (Iterator<ExpressionTree> iter =
complexity & behavior [Link]
(traversalOrder);
[Link]();)
[Link]().accept(visitor);
Eliminate type tags & switch statements when combined with other patterns.
Composite GoF Object Structural
Consequences ExpressionTree exprTree = ...;
+ Uniformity Visitor visitor = ...;
• Treat components the
same regardless of for (Iterator<ExpressionTree> iter =
complexity & behavior [Link]
(traversalOrder);
[Link]();)
[Link]().accept(visitor);
StreamUtils
.iteratorToStream(iter, false)
.forEach(exprTree ->
[Link](visitor));
See ExpressionTree/CommandLine/src/expressiontree/utils/[Link]
Composite GoF Object Structural
Consequences ExpressionTree exprTree = ...;
+ Uniformity Visitor visitor = ...;
• Treat components the
same regardless of for (Iterator<ExpressionTree> iter =
complexity & behavior [Link]
(traversalOrder);
[Link]();)
[Link]().accept(visitor);
StreamUtils
.iteratorToStream(iter, false)
.forEach(exprTree ->
[Link](visitor));
See [Link]/javase/8/docs/api/java/util/stream/[Link]#forEach
Composite GoF Object Structural
Consequences
+ Uniformity ComponentNode
+ Extensibility
• New component subclasses work Composite
UnaryNode
LeafNode
Composite Composite
AddNode SubtractNode
See ExpressionTree/CommandLine/src/expressiontree/nodes
Composite GoF Object Structural
Consequences
public interface ComponentNode {
+ Uniformity
+ Extensibility Only static fields & default “no-op” methods
+ Parsimony
default int getItem() {
• Classes & interfaces throw new
only include fields & UnsupportedOperationException
methods that they need ("method not implemented");
}
See [Link]/javase/tutorial/java/IandI/[Link]
Composite GoF Object Structural
Consequences
public class LeafNode
+ Uniformity implements ComponentNode {
+ Extensibility ...
private int mItem;
+ Parsimony
• Classes & interfaces int getItem()
Stores the Leaf
only include fields & { return mItem; }
Node’s value
methods that they need }
ComponentNode getRightChild()
{ return mRight; }
}
See ExpressionTree/CommandLine/src/expressiontree/nodes
Composite GoF Object Structural
Consequences
public class LeafNode
+ Uniformity implements ComponentNode {
+ Extensibility ...
private int mItem;
+ Parsimony
• Classes & interfaces int getItem()
only include fields & { return mItem; }
methods that they need }
ComponentNode getRightChild()
Reference to { return mRight; }
the right child. }
See ExpressionTree/CommandLine/src/expressiontree/nodes
Composite GoF Object Structural
Consequences
– Perceived complexity ComponentNode
1
Tree CompositeBinary CompositeNegate
Node vs. Node Node
0|1|2
Algorithmic Decomposition Composite Composite
AddNode SubtractNode
Composite Composite
MultiplyNode DivideNode
1
Tree CompositeBinary CompositeNegate
Node vs. Node Node
0|1|2
Algorithmic Decomposition Composite Composite
AddNode SubtractNode
Composite Composite
MultiplyNode DivideNode
int getItem()
ComponentNode getLeftChild()
ComponentNode getRightChild()
void accept(Visitor visitor)
See [Link]/wiki/Interface_bloat
Composite GoF Object Structural
Implementation considerations
• Do components know their parents?
• e.g., is there an explicit “parent”
pointer/reference?
Composite GoF Object Structural
Implementation considerations
• Uniform interface for both leaves &
composites?
• Trade-off between uniformity
& parsimony
ExpressionTree
ComponentNode
Composite
LeafNode
UnaryNode
CompositeBinary CompositeNegate
Node Node
Composite
Adding new types of nodes (& new operations on nodes) is greatly simplified.
The Bridge Pattern
Motivating Example
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Bridge pattern can be applied to make the expression
tree structure easier to access & evolve transparently.
ExpressionTree
ComponentNode
Composite
LeafNode
UnaryNode
Instrumented Synchronized
Expression Expression
Tree Tree
CompositeBinary CompositeNegate
Node Node
ExpressionTree
ComponentNode
Composite
LeafNode
UnaryNode
Instrumented Synchronized
Expression Expression
Tree Tree
CompositeBinary CompositeNegate
Node Node
Bridge Composite
Composite Composite
AddNode MultiplyNode …
Problem: Minimizing Impact of Variability
• Tightly coupling app components to a particular environment has drawbacks.
• Suboptimal implementations
for a given context
ComponentNode
ComponentNode node =
new CompositeAddNode Composite
LeafNode
UnaryNode
(new LeafNode(3),
new LeafNode(4)); CompositeBinary
Node
CompositeNegate
Node
vs. Composite
AddNode
Composite
MultiplyNode …
ComponentNode node =
new TreeNode ComponentNode
(′+′,
new TreeNode(3),
new TreeNode(4));
Problem: Minimizing Impact of Variability
• Tightly coupling app components to a particular environment has drawbacks.
• Suboptimal implementations
for a given context
ComponentNode
ComponentNode node =
new CompositeAddNode Composite
LeafNode
UnaryNode
(new LeafNode(3),
new LeafNode(4)); CompositeBinary
Node
CompositeNegate
Node
ComponentNode node =
new TreeNode ComponentNode
(′+′,
new TreeNode(3),
new TreeNode(4));
ExpressionTree
Solution: Separate Abstraction & Implementation
• Encapsulate variability behind a stable API that creates separate class
hierarchies for an abstraction & its implementations.
ExpressionTree
ComponentNode
Composite
LeafNode
UnaryNode
Synchronized Instrumented
Expression Expression
Tree Tree
CompositeBinary CompositeNegate
Node Node
Composite
LeafNode
UnaryNode
Synchronized Instrumented
Expression Expression
Tree Tree
CompositeBinary CompositeNegate
Node Node
ExpressionTree
ComponentNode
Composite
LeafNode
UnaryNode
Synchronized Instrumented
Expression Expression
Tree Tree
CompositeBinary CompositeNegate
Node Node
Variations in
what service is Composite Composite Composite Composite
provided by an AddNode MultiplyNode SubtractNode DivideNode
expression tree
Solution: Separate Abstraction & Implementation
• Encapsulate variability behind a stable API that creates separate class
hierarchies for an abstraction & its implementations.
• Client calls to the abstraction are forwarded to the corresponding
implementor subclass.
mRoot ComponentNode
ExpressionTree
accept(Visitor v) accept(Visitor v)
[Link](v);
…
LeafNode …
accept(Visitor v) accept(Visitor v)
… …
Solution: Separate Abstraction & Implementation
• Encapsulate variability behind a stable API that creates separate class
hierarchies for an abstraction & its implementations.
• Client calls to the abstraction are forwarded to the corresponding
implementor subclass.
• Subclass the abstraction class to enable different services without affecting
the implementor hierarchy.
mRoot ComponentNode
ExpressionTree
accept(Visitor v) accept(Visitor v)
…
Synchronized LeafNode …
synchronized(this)
ExpressionTree accept(Visitor v) accept(Visitor v)
{ [Link](v); }
accept(Visitor v) … …
Solution: Separate Abstraction & Implementation
• Encapsulate variability behind a stable API that creates separate class
hierarchies for an abstraction & its implementations.
• Client calls to the abstraction are forwarded to the corresponding
implementor subclass.
• Subclass the abstraction class to enable different services without affecting
the implementor hierarchy.
mRoot ComponentNode
ExpressionTree
accept(Visitor v) accept(Visitor v)
…
ExpressionTree(ComponentNode root)
boolean isNull()
int getItem()
ExpressionTree getLeftChild()
ExpressionTree getRightChild()
void accept(Visitor visitor)
Iterator
<ExpressionTree> iterator(String traversalOrder)
ExpressionTree(ComponentNode root)
boolean isNull()
int getItem()
ExpressionTree getLeftChild()
ExpressionTree getRightChild()
void accept(Visitor visitor)
Iterator
<ExpressionTree> iterator(String traversalOrder)
ExpressionTree Class Overview
• Defines an abstraction that shields clients from implementation details of
expression tree that may change at design-time or runtime
Class methods
Forward to
implementor
hierarchy ExpressionTree(ComponentNode root)
boolean isNull()
int getItem()
ExpressionTree getLeftChild()
ExpressionTree getRightChild()
void accept(Visitor visitor)
Iterator
<ExpressionTree> iterator(String traversalOrder)
ExpressionTree Class Overview
• Defines an abstraction that shields clients from implementation details of
expression tree that may change at design-time or runtime
Class methods
ExpressionTree(ComponentNode root)
boolean isNull()
int getItem() Plays essential role in the
ExpressionTree getLeftChild() Iterator & Visitor patterns.
ExpressionTree getRightChild()
void accept(Visitor visitor)
Iterator
<ExpressionTree> iterator(String traversalOrder)
See upcoming lessons on “The Iterator Pattern” & “The Visitor Pattern.”
ExpressionTree Class Overview
• Defines an abstraction that shields clients from implementation details of
expression tree that may change at design-time or runtime
Class methods
ExpressionTree(ComponentNode root)
boolean isNull()
int getItem()
ExpressionTree getLeftChild()
ExpressionTree getRightChild()
void accept(Visitor visitor)
Iterator
<ExpressionTree> iterator(String traversalOrder)
ExpressionTree(ComponentNode root)
boolean isNull()
int getItem()
ExpressionTree getLeftChild()
ExpressionTree getRightChild()
void accept(Visitor visitor)
Iterator
<ExpressionTree> iterator(String traversalOrder)
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Bridge pattern can be applied to make the expression
tree structure easier to access & evolve transparently.
• Understand the structure & functionality of the Bridge pattern.
Douglas C. Schmidt
Structure & Functionality
of the Bridge Pattern
Bridge GoF Object Structural
Intent
ExpressionTree
• Separate an abstraction from its
implementation(s) so the two
can vary independently
ComponentNode
Composite
LeafNode
UnaryNode
CompositeBinary CompositeNegate
Node Node
Composite Composite
AddNode SubtractNode
Composite Composite
MultiplyNode DivideNode
See [Link]/wiki/Bridge_pattern
Bridge GoF Object Structural
Applicability
ExpressionTree
• When the abstraction & extensible
implementation(s) can vary
independently
ComponentNode
CompositeBinary CompositeNegate
Node Node
Composite Composite
AddNode SubtractNode
Composite Composite
MultiplyNode DivideNode
Bridge GoF Object Structural
Applicability
ExpressionTree
• When the abstraction & extensible
implementation(s) can vary
independently
ComponentNode
• When there’s a need to change
implementor hierarchies at design-
time or runtime without breaking Composite
LeafNode
client code
UnaryNode
CompositeBinary CompositeNegate
Node Node
Composite Composite
MultiplyNode DivideNode
Bridge GoF Object Structural
Applicability
ExpressionTree
• When the abstraction & extensible
implementation(s) can vary
independently
ComponentNode
• When there’s a need to change
implementor hierarchies at design-
time or runtime without breaking Composite
LeafNode
client code
UnaryNode
CompositeBinary CompositeNegate
Node Node
Composite Composite
MultiplyNode DivideNode
Bridge GoF Object Structural
Structure & participants
operation() operationImp()
[Link]();
operationImp() operationImp()
Bridge GoF Object Structural
Structure & participants
ExpressionTree
operation() operationImp()
[Link]();
operationImp() operationImp()
Bridge GoF Object Structural
Structure & participants
ComponentNode
operation() operationImp()
[Link]();
operationImp() operationImp()
Bridge GoF Object Structural
Structure & participants
operation() operationImp()
[Link]();
operationImp() operationImp()
Bridge GoF Object Structural
Structure & participants
operation() operationImp()
[Link]();
operationImp() operationImp()
LeafNode, CompositeAddNode,
CompositeSubtractNode, etc.
Bridge GoF Object Structural
Structure & participants
operation() operationImp()
[Link]();
operationImp() operationImp()
SynchronizedExpressionTree,
InstrumentedExpressionTree, etc.
The Bridge Pattern
Implementation in Java
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Bridge pattern can be applied to make the expression
tree structure easier to access & evolve transparently.
• Understand the structure & functionality of the Bridge pattern.
• Know how to implement the Bridge pattern in Java.
Douglas C. Schmidt
Implementing the Bridge
Pattern in Java
Bridge GoF Object Structural
Bridge example in Java
• Separate expression tree abstraction from composite implementor hierarchy.
class ExpressionTree {
private ComponentNode mRoot;
...
public void accept(Visitor v) { [Link](v); }
See ExpressionTree/CommandLine/src/expressiontree/tree
Bridge GoF Object Structural
Bridge example in Java
• Separate expression tree abstraction from composite implementor hierarchy.
class ExpressionTree {
Stores root of composite
private ComponentNode mRoot; implementor hierarchy
...
public void accept(Visitor v) { [Link](v); }
}
Bridge GoF Object Structural
Bridge example in Java
• Separate expression tree abstraction from composite implementor hierarchy.
class ExpressionTree {
private ComponentNode mRoot;
...
public void accept(Visitor v) { [Link](v); }
}
Bridge GoF Object Structural
Bridge example in Java
• Separate expression tree abstraction from composite implementor hierarchy.
class ExpressionTree {
private ComponentNode mRoot;
...
public void accept(Visitor v) { [Link](v); }
Abstraction forwards to
}
implementor via mRoot
See [Link]/2015/10/[Link]
Bridge GoF Object Structural
Bridge example in Java
• Separate expression tree abstraction from composite implementor hierarchy.
class InstrumentedExpressionTree extends ExpressionTree {
public void accept(Visitor v) {
[Link]("starting accept() call" + ...);
[Link](v);
[Link]("finished accept() call" + ...);
}
...
mRoot ComponentNode
ExpressionTree
accept(Visitor v) accept(Visitor v)
…
LeafNode …
Synchronized
ExpressionTree accept(Visitor v) accept(Visitor v)
… …
accept(Visitor v)
Instrumented
ExpressionTree
accept(Visitor v)
Changes in service behavior don’t affect implementor hierarchy & vice versa.
Bridge GoF Object Structural
Bridge example in Java
• Encapsulate sources of variability in expression tree construction & use.
ExpressionTree exprTree
(new CompositeAddNode
(new LeafNode(3),
new LeafNode(4)));
Hide use of complex recursive
Composite internal structure
behind a stable Bridge API
Bridge GoF Object Structural
Bridge example in Java
• Encapsulate sources of variability in expression tree construction & use.
ExpressionTree exprTree
(new CompositeAddNode
(new LeafNode(3),
new LeafNode(4)));
ExpressionTree exprTree
(new TreeNode
(′+′,
new TreeNode(3),
new TreeNode(4)));
Bridge GoF Object Structural
Bridge example in Java
• Encapsulate sources of variability in expression tree construction & use.
ExpressionTree exprTree
(makeExpressionTree("3+4"));
We can apply a creational pattern
to reduce client dependencies on
implementation variability.
Factory Method, Composite, Iterator, Strategy, & Visitor are also relevant here.
The Bridge Pattern
Other Considerations
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Bridge pattern can be applied to make the expression
tree structure easier to access & evolve transparently.
• Understand the structure & functionality of the Bridge pattern.
• Know how to implement the Bridge pattern in Java.
• Be aware of other considerations when applying the Bridge pattern.
Douglas C. Schmidt
Other Considerations of
the Bridge Pattern
Bridge GoF Object Structural
Consequences
+ Abstraction & implementor Enable software to be open for extension
hierarchy are decoupled (via implementor hierarchy), but closed for
• Can evolve separately by modification (via stable abstraction API)
applying Open/Closed Principle
versus
ExpressionTree exprTree
(new TreeNode
(′+′,
new TreeNode(3),
new TreeNode(4)));
Bridge GoF Object Structural
Consequences
– “One-size-fits-all” abstraction
& implementor interfaces
See [Link]/wiki/Procrustes#Cultural_references
Bridge GoF Object Structural
Consequences
– “One-size-fits-all” abstraction
& implementor interfaces
• Can be alleviated via other patterns, e.g.,
• Adapter—makes existing classes work with others
without modifying code
request() specificRequest()
request() [Link]()
See [Link]/pub/sag/[Link]
Bridge GoF Object Structural
Implementation considerations
• Creating the right abstraction or implementor
• Often addressed by using Creational patterns
• e.g., Factory Method or Builder
We’ll cover Builder later & show how it creates composite expression trees.
Bridge GoF Object Structural
Implementation considerations
• Sharing implementors & reference counting
• e.g., C++11/Boost shared_ptr
ExpressionTree instances
+ +
Shared CompositeAddNode Reference Reference Reference
Count: 2 Count: 1 Count: 0
See [Link]/wiki/Smart_pointer#shared_ptr_and_weak_ptr
Bridge GoF Object Structural
Implementation considerations
• Dynamic uses of Bridge should be implemented via Decorator.
operation()
[Link]();
operation() operation()
addedBehavior();
addedBehavior()
operation()
[Link]();
operation() operation()
addedBehavior();
addedBehavior()
See [Link]/design_patterns/decorator
Bridge GoF Object Structural
Implementation considerations
• Dynamic uses of Bridge should be implemented via Decorator.
See [Link]/2016/11/27/Decorator-Pattern
Bridge GoF Object Structural
Known uses
• ET++ Window/WindowPort
• libg++ Set/{LinkedList, HashTable}
• ACE Reactor framework
Bridge is used more in C++ than in Java (which uses interfaces & factories).
Bridge GoF Object Structural
Known uses
• ET++ Window/WindowPort
• libg++ Set/{LinkedList, HashTable}
• ACE Reactor framework
• AWT Component/ComponentPeer
See [Link]/tik-76.278/group6/[Link]
Bridge GoF Object Structural
Known uses
• ET++ Window/WindowPort
• libg++ Set/{LinkedList, HashTable}
• ACE Reactor framework
• AWT Component/ComponentPeer
• Java Socket/SocketImpl Variations in how Socket is implemented
Socket SocketImpl
operation() operation()
See [Link]/javase/tutorial/networking/sockets
Bridge GoF Object Structural
Known uses
• ET++ Window/WindowPort
• libg++ Set/{LinkedList, HashTable}
• ACE Reactor framework Decouples synchronizer interface from
• AWT Component/ComponentPeer its implementation so fair & non-fair
semantics can be supported uniformly
• Java Socket/SocketImpl
• Java synchronizers
ReentrantLock Sync
FairSync NonFairSync
See [Link]/java-concurrent-locks
Summary of the Bridge Pattern
Bridge decouples the expression tree programming API from its
behavior & implementation to enable transparent extensibility.
ExpressionTree
ComponentNode
Composite
LeafNode
UnaryNode
Instrumented Synchronized
Expression Expression
Tree Tree
CompositeBinary CompositeNegate
Node Node
Bridge Composite
See [Link]/~schmidt/[Link]
Overview of
Pattern Collections
Douglas C. Schmidt
Learning Objectives in This Lesson
• Understand the need for pattern
relationships above & beyond
pattern collections.
Douglas C. Schmidt
Overview of
Pattern Collections
Overview of Pattern Collections
• Stand-alone patterns provide “point solutions” to relatively bounded problems
that arise within specific contexts.
Composite
pattern
Bridge
pattern
See earlier lessons on “The Composite Pattern” & “The Bridge Pattern.”
Overview of Pattern Collections
• A common way to group multiple
stand-alone patterns together is
the form of a “pattern collection.”
A pattern collection is an
intentionally organized
grouping of patterns
See [Link]/wiki/Design_Patterns.
Overview of Pattern Collections
• A common way to group multiple
stand-alone patterns together is
the form of a “pattern collection.”
• A collection may be ad hoc or
it may address a given domain,
problem, or level of abstraction.
Overview of Pattern Collections
• A common way to group multiple
stand-alone patterns together is
the form of a “pattern collection.”
• A collection may be ad hoc or
it may address a given domain,
problem, or level of abstraction.
• A collection’s organization may
be unstructured or structured.
Overview of Pattern Collections
• The Gang-of-Four, POSA1, & Pattern Languages of Program
Design (PLoPD) books are examples of pattern collections.
The pattern collections in the GoF & POSA1 books are well structured,
where as the pattern collections in the PLoPD books are less structured.
See [Link]/patterns/books
Overview of Pattern Collections
• In practice, however, stand-alone
“pattern islands” are unusual.
Overview of Pattern Collections
• In practice, however, stand-alone Extension Publisher-
“pattern islands” are unusual. Interface Domain
Subscriber
Object
• Any substantial software Bridge Active
design inevitably includes Object
Layers
many patterns. Remote
Operation Evictor
Component
Configurator
Thread-
Specific Interceptor
Storage
Adapter
Factory Interpreter
Interpreter Proxy
Method
Adapter
Facade Activator
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize the common types of
pattern relationships.
Overview of Pattern Relationships
• Collections of stand-alone patterns have certainly been used with success.
Design problems
• Document structure
• Formatting
• Embellishment
• Multiple look & feels
• Multiple window systems
• User operations
• Spelling checking
& hyphenation
• Etc.
See [Link]/wiki/Design_Patterns
Overview of Pattern Relationships
• Patterns are social, however, & like to work together.
Overview of Pattern Relationships
• Patterns commonly form various types of relationships
We’ll briefly summarize these types of relationships here & explore them later
Overview of Pattern Relationships
• Patterns commonly form various types of relationships, e.g.
1. Pattern complements, where:
• One pattern provides the missing
ingredient needed by another
See [Link]/~schmidt/PDF/[Link].
Summary
• A key challenge is to organize Publisher-
Extension
these patterns effectively. Interface Domain
Subscriber
Object
Bridge Active
Object
Layers
Remote Component
Operation Evictor Configurator
Thread-
Specific Interceptor
Storage
Adapter
Factory Interpreter
Interpreter Proxy
Method
Adapter
Facade Activator
Douglas C. Schmidt
Learning Objectives in This Lesson
• Know the common types of
pattern relationships:
• Pattern complements
• Pattern compounds
Factory
Method
Disposal
Method
delete object
Factory
Method
Disposal
Method
delete object
Factory
Method
Disposal
Method
delete object
create_iterator
Iterator
Batch Method
list
next_n
next_n
bind
next_one
unbind
destroy
Naming
BindingIterator Context
Douglas C. Schmidt
Summary
• Pattern complements & pattern compounds are initial steps towards moving
away from patterns as distinct islands of design to parts of an interwoven
whole.
Summary
• Pattern complements & pattern compounds are initial steps towards moving
away from patterns as distinct islands of design to parts of an interwoven
whole.
• A pattern complement completes the design of another pattern.
Factory
Method
Summary
• Pattern complements & pattern compounds are initial steps towards moving
away from patterns as distinct islands of design to parts of an interwoven
whole.
• A pattern complement completes the design of another pattern.
• A pattern compound names a commonly recurring, cohesive combination
of other patterns.
Summary
• Pattern complements & pattern compounds are initial steps towards moving
away from patterns as distinct islands of design to parts of an interwoven
whole.
• A pattern complement completes the design of another pattern.
• A pattern compound names a commonly recurring, cohesive combination
of other patterns.
• The POSA5 book provides in-depth discussion
of the key concepts that underlie pattern
complements & pattern compounds.
See [Link]/~schmidt/POSA/POSA5
The Command Pattern
Motivating Example
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Command pattern can be
applied to perform user-requested commands
ET_Command
UserCommand
ET_Command
consistently & extensibly in the expression
_Factory execute()
tree processing app.
ET_Command ET_CommandImpl
_FactoryImpl Expr
Format Command
Command Expr_
Format_ Command
Command Eval
Macro Command
Command Eval_
Macro_ Command
Command
Quit
Print Command
Quit_
Command
Print_ Command
Command
Douglas C. Schmidt
Motivating the Need for
the Command Pattern in
the Expression Tree App
A Pattern for Objectifying User Requests
Purpose: Define objectified actions that enable users to perform command
requests consistently & extensibly in the expression tree processing app.
InputHandler
*
UserCommand
Command
Format Expr
Command Command
Print Eval
Command Command
Macro Quit
Command Command
Verbose mode
Context: OO Expression Tree Processing App
• Succinct mode supports
macro commands
Succinct mode
Problem: Scattered/Fixed User Request Implementations
• It’s hard to maintain implementations of user-requested commands that are
scattered throughout the source code.
Problem: Scattered/Fixed User Request Implementations
• Hard-coding the program to handle only a fixed set of user commands
impedes the evolution that’s needed to support new requirements.
Operation
format
expr
set
print
eval
quit
Solution: Encapsulate User Requests as Commands
• Create a hierarchy of UserCommand
UserCommand
subclasses
execute()
Expr
Format Command
Command
Eval
Macro Command
Command
Quit
Print Command
Command
Solution: Encapsulate User Requests as Commands
• Create a hierarchy of UserCommand
UserCommand
subclasses, each containing:
execute()
• A command method (execute())
Expr
Format Command
Command
Eval
Macro Command
Command
Quit
Print Command
Command
Solution: Encapsulate User Requests as Commands
• Create a hierarchy of UserCommand
UserCommand
subclasses, each containing:
execute()
• A command method (execute())
• The state needed by the command
Expr
Format Command
Command
Eval
Macro Command
Command
Quit
Print Command
Command
Solution: Encapsulate User Requests as Commands
• A Command object may:
• Implement the command
Command
itself
performAction()
Solution: Encapsulate User Requests as Commands
• A Command object may:
• Implement the operation
Command
itself
• Or forward the command’s performAction()
implementation to other
object(s)
Command
[Link]()
The expression tree processing app applies this variant of the Command pattern
UserCommand Class Overview
• Defines an abstract super class that performs a user-requested command
on an expression tree when it’s executed
Class methods
void execute()
void printValidCommands()
UserCommand Class Overview
• Defines an abstract super class that performs a user-requested command
on an expression tree when it’s executed
Class methods
void execute()
void printValidCommands()
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Command pattern can be applied to perform user-
requested commands consistently & extensibly in the expression tree
processing app.
• Understand the structure & functionality of the Command pattern.
Douglas C. Schmidt
Structure & Functionality
of the Command Pattern
Command GoF Object Behavioral
Intent
• Encapsulate the request for a service UserCommand
as an object execute()
Expr
Format Command
Command
Eval
Macro Command
Command
Quit
Print Command
Command
See [Link]/wiki/Command_pattern
Command GoF Object Behavioral
Applicability
• Want to parameterize objects with an UserCommand
action to perform execute()
Expr
Format Command
Command
Eval
Macro Command
Command
Quit
Print Command
Command
Command GoF Object Behavioral
Applicability
• Want to parameterize objects with an UserCommand
action to perform execute()
• Want to specify, queue, & execute
requests at different times
Expr
Format Command
Command
Eval
Macro Command
Command
Quit
Print Command
Command
Command GoF Object Behavioral
Applicability
• Want to parameterize objects with an UserCommand
action to perform execute()
• Want to specify, queue, & execute
requests at different times
We need to add Expr
• Want to support multilevel an unexecute() Command
Format
undo/redo method here.
Command
Eval
Macro Command
Command
Quit
Print Command
Command
Command GoF Object Behavioral
Structure & participants
ConcreteCommand
Command GoF Object Behavioral
Structure & participants
InputHandler
ConcreteCommand
ConcreteCommand
Command GoF Object Behavioral
Structure & participants
FormatCommand,
ExprCommand,
PrintCommand,
EvalCommand,
MacroCommand,
QuitCommand, etc.
ConcreteCommand
Command GoF Object Behavioral
Structure & participants
TreeContext
ConcreteCommand
The UI
ConcreteCommand
Command GoF Object Behavioral
Structure & participants
ConcreteCommand
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Command pattern can be applied to perform user-
requested commands consistently & extensibly in the expression tree
processing app.
• Understand the structure & functionality of the Command pattern.
• Know how to implement the Command pattern in Java.
Douglas C. Schmidt
Implementing the Command
Pattern in Java
Command GoF Object Behavioral
Command example in Java public abstract class UserCommand {
protected TreeContext mTreeContext;
• Plays role of “Command” in
the Command pattern
• Defines an API for “Concrete
Command” implementations UserCommand(TreeContext
that perform an operation treeContext) {
on the expression tree when mTreeContext = treeContext;
it's executed }
See ExpressionTree/CommandLine/src/expressiontree/commands
Command GoF Object Behavioral
Command example in Java public abstract class UserCommand {
protected TreeContext mTreeContext;
• Plays role of “Command” in
the Command pattern Holds the expression tree
• Defines an API for “Concrete that’s the target of commands
Command” implementations UserCommand(TreeContext
that perform an operation treeContext) {
on the expression tree when mTreeContext = treeContext;
it's executed }
ExprCommand(TreeContext context,
String newexpr) {
super(context);
mExpr = newexpr;
}
execute()
execute()
See ExpressionTree/CommandLine/src/expressiontree/commands
Command GoF Object Behavioral
Command example in Java
• Encapsulate the execution of a sequence of commands as an object, which is
used to implement the “succinct mode.”
MacroCommand(TreeContext context,
List<UserCommand> macroCommand) {
super(context); mMacroCommand = macroCommand;
}
MacroCommand(TreeContext context,
List<UserCommand> macroCommand) {
super(context); mMacroCommand = macroCommand;
}
MacroCommand(TreeContext context,
List<UserCommand> macroCommand) {
super(context); mMacroCommand = macroCommand;
}
MacroCommand(TreeContext context,
List<UserCommand> macroCommand) {
super(context); mMacroCommand = macroCommand;
}
See [Link]/Command-Pattern-Using-Java-8-Lambda
The Command Pattern
Other Considerations
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Command pattern can be applied to perform user-
requested commands consistently & extensibly in the expression tree
processing app.
• Understand the structure & functionality of the Command pattern.
• Know how to implement the Command pattern in Java.
• Be aware of other considerations when applying the Command pattern.
Douglas C. Schmidt
Other Considerations of
the Command Pattern
Command GoF Object Behavioral
Consequences
+ Abstracts the executor of a
service
• Makes programs more
modular & flexible
Command GoF Object Behavioral
Consequences
+ Abstracts the executor of a
service
ConcreteCommand
• Makes programs more
modular & flexible, e.g.,
performAction()
• Can bundle state &
behavior into an object
Command GoF Object Behavioral
Consequences
+ Abstracts the executor of a
service
ConcreteCommand
• Makes programs more
modular & flexible, e.g.,
performAction()
• Can bundle state &
behavior into an object
• Can forward behavior
to other objects ConcreteCommand
[Link]()
See the next lesson on “The Factory Method Pattern” for UserCommandFactory.
Command GoF Object Behavioral
Consequences
+ Abstracts the executor of a void handleInput() {
service ...
UserCommand command =
• Makes programs more makeUserCommand(input);
modular & flexible, e.g.,
• Can bundle state &
behavior into an object
• Can forward behavior executeCommand(command);
to other objects
• Can extend behavior Call a hook method & pass
a command to execute
via subclassing
• Can pass a command
object as a parameter
execute()
execute()
Case study doesn’t use unexecute(), but it’s a common Command feature.
Command GoF Object Behavioral
Consequences
UserCommand
– Might result in lots of trivial
execute()
command subclasses
Expr
Format Command
Command
Eval
Macro Command
Command
Quit
Print Command
Command
See [Link]/2014/12/[Link]
Command GoF Object Behavioral
Consequences
– Excessive memory may
be needed to support Undo: Redo:
undo/redo operations unexecute() execute()
Command GoF Object Behavioral
Implementation considerations
• Copying a command before
putting it on a history list Undo: Redo:
unexecute() execute()
Command GoF Object Behavioral
Implementation considerations
• Avoiding error accumulation
during undo/redo Undo: Redo:
unexecute() execute()
Command GoF Object Behavioral
Implementation considerations
• Supporting transactions
Undo: Redo:
unexecute() execute()
Command GoF Object Behavioral
Known uses
• InterViews Actions
• MacApp, Unidraw
Commands
• JDK’s UndoableEdit,
AccessibleAction
• GNU Emacs
• Microsoft Office tools
• Java Runnable interface
See [Link]/javase/8/docs/api/java/lang/[Link]
Command GoF Object Behavioral
Known uses
• InterViews Actions
• MacApp, Unidraw
Commands
• JDK’s UndoableEdit,
AccessibleAction
• GNU Emacs
• Microsoft Office tools
• Java Runnable interface
• Runnable can also be used to implement the Command Processor pattern
See [Link]/~schmidt/[Link]
Summary of the Command Pattern
• Command ensures users interact with the expression tree processing app in a
consistent & extensible manner.
InputHandler
*
UserCommand
Command
Format Expr
Command Command
Print Eval
Command Command
Macro Quit
Command Command
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Factory Method pattern can
be applied to extensibly create variabilities in UserCommandFactory
<<creates>>
UserCommand
execute()
Expr
Format Command
Command
Eval
Macro Command
Command
Quit
Print Command
Command
Douglas C. Schmidt
Motivating the Need for
the Factory Method Pattern in the
Expression Tree App
A Pattern for Abstracting Object Creation
Purpose: Enable the extensible creation of variabilities,
such as commands, iterators, & visitors.
Factory Method
<<creates>>
* UserCommand
Command
1
MacroCommand PrintCommand SetCommand QuitCommand NullCommand
Factory Method decouples the creation of objects from their subsequent use.
Context: OO Expression Tree Processing App
• There are many points of variability in Visitor
the expression tree processing app.
• e.g., user commands, traversal
strategies, & visitor operations EvaluationVisitor PrintVisitor
Java Iterator
*
UserCommand
LevelOrder
Iterator
Format Expr
Command Command InOrder
Iterator
PreOrder
Macro Quit Iterator
Command Command
Context: OO Expression Tree Processing App
• There are many points of variability in Visitor
the expression tree processing app.
• e.g., user commands, traversal
strategies, & visitor operations EvaluationVisitor PrintVisitor ...
applied on an expression tree
Java Iterator
*
UserCommand
LevelOrder
Iterator
Format Expr
Command Command InOrder
Iterator
UserCommand command =
new PrintCommand();
Visitor visitor =
new EvaluationVisitor();
Iterator<ExpressionTree> it =
new PreOrderIterator();
Solution: Abstract Creation of Objects
• Define a UserCommandFactory class whose makeUserCommand()
factory method creates a UserCommand object.
UserCommandFactory
<<creates>>
User
makeUserCommand()
Command
Solution: Abstract Creation of Objects
• Have the makeUserCommand() factory method implement the appropriate
subclass of UserCommand
UserCommandFactory
<<creates>>
User
makeUserCommand() Command
Solution: Abstract Creation of Objects
• Have the makeUserCommand() factory method implement the appropriate
subclass of UserCommand, e.g.,
UserCommandFactory & override the factory method
• Subclass
makeUserCommand()
UserCommandFactory
<<creates>>
makeUserCommand()
User
Command
PrintCommandFactory Print
<<creates>> Command
makeUserCommand()
Solution: Abstract Creation of Objects
• Have the makeUserCommand() factory method implement the appropriate
subclass of UserCommand, e.g.,
UserCommandFactory & override the factory method
• Subclass
makeUserCommand()
UserCommandFactory
<<creates>>
makeUserCommand(Param)
User
* Command
1
MacroCommand PrintCommand SetCommand QuitCommand NullCommand
Class methods
Class methods
Class methods
HashMap<String, UserCommand
UserCommandFactoryCommand>
Command Factory
Name Command
"expr" execute() Expr
Format Command
"format" execute()
Command
"eval" execute() Eval
Macro Command
"macro" execute()
Command
"quit" execute() Quit
Print Command
"print" execute()
Command
UserCommandFactory Class Overview
• Create the command corresponding to the user input.
HashMap<String, UserCommand
Function<String, UserCommand>>
Command Factory
Name Command
"expr" apply() Expr
Format Command
"format" apply()
Command
"eval" apply() Eval
Macro Command
"macro" apply()
Command
"quit" apply() Quit
Print Command
"print" apply()
Command
See [Link]/javase/8/docs/api/java/util/function/[Link]
The Factory Method Pattern
Structure & Functionality
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Factory Method pattern can be applied to extensibly
create variabilities in the expression tree processing app.
• Understand the structure & functionality of the Factory Method pattern.
Douglas C. Schmidt
Structure & Functionality of the
Factory Method Pattern
Factory Method GoF Class Creational
Intent UserCommandFactory
• Provide an API for creating an makeUserCommand()
object, but leave the choice of
the object’s concrete type to
its subclass(es) UserCommand
execute()
…
FormatCommandFactory
Expr
makeUserCommand() Format Command
<<creates>>
Command
MacroCommandFactory Eval
Macro Command
makeUserCommand() Command
<<creates>>
PrintCommandFactory Quit
Print Command
makeUserCommand() Command
<<creates>>
See [Link]/wiki/Factory_method_pattern
Factory Method GoF Class Creational
Applicability UserCommandFactory
• When a class cannot anticipate makeUserCommand()
the objects it must create.
UserCommand
execute()
…
FormatCommandFactory
Expr
makeUserCommand() Format Command
<<creates>>
Command
MacroCommandFactory Eval
Macro Command
makeUserCommand() Command
<<creates>>
PrintCommandFactory Quit
Print Command
makeUserCommand() Command
<<creates>>
Factory Method GoF Class Creational
Applicability UserCommandFactory
• When a class cannot anticipate makeUserCommand()
the objects it must create.
• A class wants its subclasses to
specify the objects it creates. UserCommand
execute()
…
FormatCommandFactory
Expr
makeUserCommand() Format Command
<<creates>>
Command
MacroCommandFactory Eval
Macro Command
makeUserCommand() Command
<<creates>>
PrintCommandFactory Quit
Print Command
makeUserCommand() Command
<<creates>>
Factory Method GoF Class Creational
Applicability UserCommandFactory
• When a class cannot anticipate makeUserCommand()
the objects it must create.
• A class wants its subclasses to
specify the objects it creates. UserCommand
execute()
• This approach is optional.
…
FormatCommandFactory
Expr
makeUserCommand() Format Command
<<creates>>
Command
MacroCommandFactory Eval
Macro Command
makeUserCommand() Command
<<creates>>
PrintCommandFactory Quit
Print Command
makeUserCommand() Command
<<creates>>
Factory Method GoF Class Creational
Applicability UserCommandFactory
• When a class cannot anticipate makeUserCommand(Param) <<creates>>
the objects it must create.
• A class wants its subclasses to
specify the objects it creates. UserCommand
execute()
• This approach is optional.
• An alternative involves
passing a parameter to
the factory method.
Expr
Format Command
Command
Eval
Macro Command
Command
Quit
Print Command
Command
Factory Method GoF Class Creational
Applicability UserCommandFactory
• When a class cannot anticipate makeUserCommand(Param) <<creates>>
the objects it must create.
• A class wants its subclasses to
specify the objects it creates. UserCommand
execute()
• Or there’s a need to decouple
object creation from its
subsequent use.
Expr
Format Command
Command
Eval
Macro Command
Command
Quit
Print Command
Command
UserCommand
Factory Method GoF Class Creational
Structure & participants
UserCommandFactory
Factory Method GoF Class Creational
Structure & participants
EvalCommand, Print
Command, MacroCommand, etc.
Factory Method GoF Class Creational
Structure & participants
Unused
Our app passes a string to the factory method rather than using subclassing.
The Factory Method Pattern
Implementation in Java
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Factory Method pattern can be applied to extensibly
create variabilities in the expression tree processing app.
• Understand the structure & functionality of the Factory Method pattern.
• Know how to implement the Factory Method pattern in Java.
Douglas C. Schmidt
Implementing the Factory Method
Pattern in Java
Factory Method GoF Class Creational
Factory Method example in Java
• UserCommandFactory creates UserCommands based on user input.
public class UserCommandFactory {
See ExpressionTree/CommandLine/src/expressiontree/commands
Factory Method GoF Class Creational
Factory Method example in Java
• UserCommandFactory creates UserCommands based on user input.
public class UserCommandFactory { We first apply Command to
initialize UserCommandFactory.
private interface UserCommandFactoryCommand
{ UserCommand execute(String param); }
We apply the Command pattern to define a factory method that creates a command!
Factory Method GoF Class Creational
Factory Method example in Java
• UserCommandFactory creates UserCommands based on user input.
public class UserCommandFactory {
Java lambda expressions are more concise than anonymous inner classes!
Factory Method GoF Class Creational
Factory Method example in Java
• UserCommandFactory creates UserCommands based on user input.
public class UserCommandFactory {
The factory method
public UserCommand makeUserCommand (String inputString) {
String commandRequest = ... /* get command from inputString */
String parameters = ... /* get parameters from inputString */
UserCommandFactoryCommand command =
[Link](commandRequest);
if (command != null)
return [Link](parameters);
else
return new QuitCommand(mTreeContext);
...
The factory method uses a map to find/execute the command that makes a command.
Factory Method GoF Class Creational
Factory Method example in Java
• UserCommandFactory creates UserCommands based on user input.
public class UserCommandFactory {
if (command != null)
return [Link](parameters);
else
return new QuitCommand(mTreeContext);
...
Factory Method GoF Class Creational
Factory Method example in Java
• UserCommandFactory creates UserCommands based on user input.
public class UserCommandFactory {
if (command != null)
return [Link](parameters);
else
return new QuitCommand(mTreeContext);
...
Factory Method GoF Class Creational
Factory Method example in Java
• UserCommandFactory creates UserCommands based on user input.
public class UserCommandFactory {
UserCommandFactoryCommand command =
[Link](commandRequest);
If found, execute it to make a command
if (command != null)
return [Link](parameters);
else
return new QuitCommand(mTreeContext);
...
Factory Method GoF Class Creational
Factory Method example in Java
• UserCommandFactory creates UserCommands based on user input.
public class UserCommandFactory {
UserCommandFactoryCommand command =
[Link](commandRequest);
if (command != null)
return [Link](parameters);
else
return new QuitCommand(mTreeContext);
...
Otherwise, user gave an
unsupported request, so quit
The Factory Method Pattern
Other Considerations
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Factory Method pattern can be applied to extensibly
create variabilities in the expression tree processing app.
• Understand the structure & functionality of the Factory Method pattern.
• Know how to implement the Factory Method pattern in Java.
• Be aware of other considerations when applying the Factory Method pattern.
Douglas C. Schmidt
Other Considerations of the
Factory Method Pattern
Factory Method GoF Class Creational
Consequences
+ Decoupling
• Clients are more flexible Instead of:
since they needn’t specify the
class name of the concrete UserCommand command =
class & the details of its new PrintCommand();
creation.
Use:
UserCommand command
= userCommandfactory.
makeUserCommand
("print"));
where userCommandFactory is an
instance of UserCommandFactory
Factory Method GoF Class Creational
Consequences
Hard-codes a lexical
+ Decoupling dependency on
• Clients are more flexible PrintCommand
Instead of:
since they needn’t specify the
class name of the concrete UserCommand command =
class & the details of its new PrintCommand();
creation.
Use:
UserCommand command
= userCommandfactory.
makeUserCommand
("print");
where userCommandFactory is an
instance of UserCommandFactory
Factory Method GoF Class Creational
Consequences
+ Decoupling
• Clients are more flexible Instead of:
since they needn’t specify the
class name of the concrete UserCommand command =
class & the details of its new PrintCommand();
creation.
No lexical dependency
Use: on any concrete class
UserCommand command
= userCommandfactory.
makeUserCommand
("print");
where userCommandFactory is an
instance of UserCommandFactory
Factory Method GoF Class Creational
Consequences UserCommandFactory
− More classes makeUserCommand()
• Construction of objects may
require additional class(es).
UserCommand
execute()
…
FormatCommandFactory
Expr
makeUserCommand() Format Command
<<creates>>
Command
MacroCommandFactory Eval
Macro Command
makeUserCommand() Command
<<creates>>
PrintCommandFactory Quit
Print Command
makeUserCommand() Command
<<creates>>
Factory Method GoF Class Creational
Consequences UserCommandFactory
− More classes makeUserCommand(Param) <<creates>>
• Construction of objects may
require additional class(es).
UserCommand
• An alternative is to pass execute()
a param to the Creator
super class factory method.
Expr
Format Command
Command
Eval
Macro Command
Command
Quit
Print Command
Command
Factory Method GoF Class Creational
Implementation Considerations UserCommandFactory
• Must vs. may subclass makeUserCommand()
• The creator class is abstract, i.e.,
• It doesn’t implement factory UserCommand
methods & must be subclassed. execute()
…
FormatCommandFactory
Expr
makeUserCommand() Format Command
<<creates>>
Command
MacroCommandFactory Eval
Macro Command
makeUserCommand() Command
<<creates>>
PrintCommandFactory Quit
Print Command
makeUserCommand() Command
<<creates>>
Factory Method GoF Class Creational
Implementation Considerations UserCommandFactory
• Must vs. may subclass makeUserCommand() <<creates>>
• The creator class is abstract.
• The creator class is concrete, i.e., UserCommand
• It provides a default factory execute()
method & may be subclassed.
…
Expr
Format Command
Command
Eval
Macro Command
Command
Quit
Print Command
Command
Factory Method GoF Class Creational
Implementation Considerations UserCommandFactory
• Factory method creates variants makeUserCommand(Param) <<creates>>
• Pass a parameter to designate
the variant.
UserCommand
execute()
Expr
Format Command
Command
Eval
Macro Command
Command
Quit
Print Command
Command
Factory Method GoF Class Creational
Implementation Considerations UserCommandFactory
• Factory method creates variants makeUserCommand(Param) <<creates>>
• Pass a parameter to designate
the variant.
UserCommand
execute()
Eval
Macro Command
Command
Quit
Print Command
Command
See [Link]/articles/factory-pattern-using-lambda-expression-in-java-8
Factory Method GoF Class Creational
Implementation Considerations
• Constructor references in modern Java may reduce the tedium of creating
Product subclasses
class ShapeFactory {
private Map<String, Supplier<Shape>> map =
new HashMap<>() {{
put("CIRCLE", Circle::new);
put("RECTANGLE", Rectangle::new);
...
}}; Constructor references can be used to create desired shapes.
See [Link]/java-8/constructor-references-java-8-simplified-tutorial
Factory Method GoF Class Creational
Implementation Considerations
• Constructor references in modern Java may reduce the tedium of creating
Product subclasses
class ShapeFactory {
private Map<String, Supplier<Shape>> map =
new HashMap<>() {{
put("CIRCLE", Circle::new);
put("RECTANGLE", Rectangle::new);
...
}};
See [Link]/wiki/Abstract_factory_pattern
Factory Method GoF Class Creational
Known uses
• InterViews Kits
• ET++ WindowSystem
• AWT Toolkit
• BREW feature phone frameworks
• The ACE ORB (TAO)
• iterator() factory method in
the Java Collection interface
See [Link]/javase/8/docs/api/java/util/[Link]#iterator
Summary of the Factory Method Pattern
• Factory Method enables extensible creation of variabilities, such as iterators,
commands, & visitors.
Factory Method
<<creates>>
* UserCommand
Command
1
MacroCommand PrintCommand SetCommand QuitCommand NullCommand
Factory Method decouples the creation of objects from their subsequent use.
The Iterator Pattern
Motivating Example
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Iterator pattern can
be applied to access all nodes in an
expression tree flexibly & extensibly.
for(Iterator<ExpressionTree> it =
[Link]();
[Link]();) {
ExpressionTree node = [Link]();
doSomethingWithNode(node);
}
Douglas C. Schmidt
Motivating the Need for
the Iterator Pattern in
the Expression Tree App
A Pattern for Transparently Traversing Aggregates
Purpose: Create objects that traverse the Composite-based
expression tree & access each of its elements one at a time.
Bridge
ExpressionTree ComponentNode
Java Iterator
Composite
BinaryNode …
Iterator Composite
Operation Behavior
format Allows the user to select the format of the input expression
expr Allows the user to designate the current input expression
set Sets a variable that can be used in an expression
print Print the current input expression using the designated
traversal order
eval Evaluate the value of the current input expression
quit Exit the program
Problem: Inflexible Expression Tree Traversal
• Hard-coding the traversal logic into the expression tree itself is inflexible
“Post-order” traversal =
5-5+34
Solution: Encapsulate Traversal as an Object
• Create an iterator object that encapsulates
the traversal of an expression tree without
requiring clients to know how the tree is
structured internally.
“Post-order” traversal =
5 ~ 5+34
“Post-order” traversal =
5 ~ 3
Solution: Encapsulate Traversal as an Object
• Create an iterator object that encapsulates
the traversal of an expression tree without
requiring clients to know how the tree is
structured internally.
“Post-order” traversal =
5 ~ 3 4
Solution: Encapsulate Traversal as an Object
• Create an iterator object that encapsulates
the traversal of an expression tree without
requiring clients to know how the tree is
structured internally.
“Post-order” traversal =
5 ~ 3 4 +
Solution: Encapsulate Traversal as an Object
• Create an iterator object that encapsulates
the traversal of an expression tree without
requiring clients to know how the tree is
structured internally.
“Post-order” traversal =
5 ~ 3 4 +×
Solution: Encapsulate Traversal as an Object
• Define methods to:
1. Create an iterator (via factory method)
for(Iterator<ExpressionTree> it = [Link]();
[Link]();) {
ExpressionTree node = [Link]();
doSomethingWithNode(node);
}
See [Link]/wiki/Factory_method_pattern
Solution: Encapsulate Traversal as an Object
• Define methods to:
1. Create an iterator (via factory method)
2. Check to see if it’s finished
for(Iterator<ExpressionTree> it = [Link]();
[Link]();) {
ExpressionTree node = [Link]();
doSomethingWithNode(node);
}
Solution: Encapsulate Traversal as an Object
• Define methods to:
1. Create an iterator (via factory method)
2. Check to see if it’s finished
3. Access & process each element
if it’s not finished
for(Iterator<ExpressionTree> it = [Link]();
[Link]();) {
ExpressionTree node = [Link]();
doSomethingWithNode(node);
}
Java Iterator Interface Overview
• Defines a generic interface for traversing an aggregate data structure
Interface methods
boolean hasNext()
E next()
void remove()
default void forEachRemaining()
Interface methods
Returns true if
iterator has boolean hasNext()
more elements E next()
void remove()
default void forEachRemaining()
Java Iterator Interface Overview
• Defines a generic interface for traversing an aggregate data structure
boolean hasNext()
E next()
void remove()
default void forEachRemaining()
Java Iterator Interface Overview
• Defines a generic interface for traversing an aggregate data structure
Interface methods
Interface methods
boolean hasNext()
E next()
void remove()
default void forEachRemaining()
Performs the given action
for each remaining element
Java Iterator Interface Overview
• Defines a generic interface for traversing an aggregate data structure
Interface methods
boolean hasNext()
E next()
void remove()
default void forEachRemaining()
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Iterator pattern can be applied to access all nodes in an
expression tree flexibly & extensibly.
• Understand the structure & functionality of the Iterator pattern.
Douglas C. Schmidt
Structure & Functionality
of the Iterator Pattern
Iterator GoF Object Behavioral
Intent
• Access elements of an aggregate
without exposing its representation
ExpressionTree
Iterator GoF Object Behavioral
Structure & participants
Java Iterator
Iterator GoF Object Behavioral
Structure & participants
PreOrderIterator,
PostOrderIterator, etc.
Iterator GoF Object Behavioral
Structure & participants
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Iterator pattern can be applied to access all nodes in an
expression tree flexibly & extensibly.
• Understand the structure & functionality of the Iterator pattern.
• Know how to implement the Iterator pattern in Java.
Iterator GoF Object Behavioral
Iterator example in Java
• A Stack implements a non-recursive “pre-order” algorithm for tree traversal.
class PreOrderIterator implements Iterator<ExpressionTree> {
private Stack <ExpressionTree> mStack =
new Stack<>();
See ExpressionTree/CommandLine/src/expressiontree/iterators
Iterator GoF Object Behavioral
Iterator example in Java
• A Stack implements a non-recursive “pre-order” algorithm for tree traversal.
class PreOrderIterator implements Iterator<ExpressionTree> {
private Stack <ExpressionTree> mStack =
new Stack<>();
PreOrderIterator implements
the Iterator interface
See [Link]/javase/8/docs/api/java/util/[Link]
Iterator GoF Object Behavioral
Iterator example in Java
• A Stack implements a non-recursive “pre-order” algorithm for tree traversal.
class PreOrderIterator implements Iterator<ExpressionTree> {
private Stack <ExpressionTree> mStack =
new Stack<>();
Advance iterator
...
public ExpressionTree next() {
ExpressionTree result = [Link]();
if(![Link]()) {
ExpressionTree temp = [Link]();
if(![Link]().isNull())
[Link]([Link]());
if(![Link]().isNull())
[Link]([Link]());
}
return result;
}
...
...
public ExpressionTree next() {
ExpressionTree result = [Link]();
if(![Link]()) {
Remove the next
ExpressionTree temp = [Link]();
item from the stack
if(![Link]().isNull())
[Link]([Link]());
if(![Link]().isNull())
[Link]([Link]());
}
return result;
}
...
Iterator GoF Object Behavioral
Iterator example in Java
• A Stack implements a non-recursive “pre-order” algorithm for tree traversal.
class PreOrderIterator implements Iterator<ExpressionTree> {
...
public ExpressionTree next() {
ExpressionTree result = [Link]();
if(![Link]()) {
ExpressionTree temp = [Link]();
if(![Link]().isNull())
[Link]([Link]());
Update the stack
if(![Link]().isNull())
[Link]([Link]());
}
return result;
}
...
Iterator GoF Object Behavioral
Iterator example in Java
• A Stack implements a non-recursive “pre-order” algorithm for tree traversal.
class PreOrderIterator implements Iterator<ExpressionTree> {
...
public ExpressionTree next() {
ExpressionTree result = [Link]();
if(![Link]()) {
ExpressionTree temp = [Link]();
if(![Link]().isNull())
[Link]([Link]());
if(![Link]().isNull())
[Link]([Link]());
}
return result; Return the next item
}
...
Iterator GoF Object Behavioral
Iterator example in Java
• Implement the iterator() factory method in the ExpressionTree
class to return a new PreOrderIterator.
class ExpressionTree {
...
public Iterator<ExpressionTree> iterator() {
return new PreOrderIterator(this);
} This is an application of the
Factory Method pattern.
}
[Link]("Tree contents:");
for (Iterator<ExpressionTree> it =
[Link]();
[Link]();
) {
ExpressionTree treeNode = [Link]();
if ([Link]() instanceof LeafNode)
[Link]((int)[Link]() + " ");
else
[Link]((char)[Link]() + " ");
}
Iterator GoF Object Behavioral
Iterator example in Java
• Use PreOrderIterator to print expression tree contents.
ExpressionTree exprTree = ...;
[Link]("Tree contents:");
for (Iterator<ExpressionTree> it =
[Link]();
[Link]();
) {
ExpressionTree treeNode = [Link]();
if ([Link]() instanceof LeafNode)
[Link]((int)[Link]() + " ");
else
[Link]((char)[Link]() + " ");
}
×
Iterator GoF Object Behavioral
Iterator example in Java
• Use PreOrderIterator to print expression tree contents.
ExpressionTree exprTree = ...;
[Link]("Tree contents:");
for (Iterator<ExpressionTree> it =
[Link]();
[Link]();
) {
ExpressionTree treeNode = [Link]();
if ([Link]() instanceof LeafNode)
[Link]((int)[Link]() + " ");
else
[Link]((char)[Link]() + " ");
}
×−
Iterator GoF Object Behavioral
Iterator example in Java
• Use PreOrderIterator to print expression tree contents.
ExpressionTree exprTree = ...;
[Link]("Tree contents:");
for (Iterator<ExpressionTree> it =
[Link]();
[Link]();
) {
ExpressionTree treeNode = [Link]();
if ([Link]() instanceof LeafNode)
[Link]((int)[Link]() + " ");
else
[Link]((char)[Link]() + " ");
}
×−5
Iterator GoF Object Behavioral
Iterator example in Java
• Use PreOrderIterator to print expression tree contents.
ExpressionTree exprTree = ...;
[Link]("Tree contents:");
for (Iterator<ExpressionTree> it =
[Link]();
[Link]();
) {
ExpressionTree treeNode = [Link]();
if ([Link]() instanceof LeafNode)
[Link]((int)[Link]() + " ");
else
[Link]((char)[Link]() + " ");
}
×−5+
Iterator GoF Object Behavioral
Iterator example in Java
• Use PreOrderIterator to print expression tree contents.
ExpressionTree exprTree = ...;
[Link]("Tree contents:");
for (Iterator<ExpressionTree> it =
[Link]();
[Link]();
) {
ExpressionTree treeNode = [Link]();
if ([Link]() instanceof LeafNode)
[Link]((int)[Link]() + " ");
else
[Link]((char)[Link]() + " ");
}
×−5+3
Iterator GoF Object Behavioral
Iterator example in Java
• Use PreOrderIterator to print expression tree contents.
ExpressionTree exprTree = ...;
[Link]("Tree contents:");
for (Iterator<ExpressionTree> it =
[Link]();
[Link]();
) {
ExpressionTree treeNode = [Link]();
if ([Link]() instanceof LeafNode)
[Link]((int)[Link]() + " ");
else
[Link]((char)[Link]() + " ");
}
×−5+34
Iterator GoF Object Behavioral
Iterator example in Java
• Use PreOrderIterator to print expression tree contents.
ExpressionTree exprTree = ...;
[Link]("Tree contents:");
for (Iterator<ExpressionTree> it =
[Link]();
[Link]();
) {
ExpressionTree treeNode = [Link]();
if ([Link]() instanceof LeafNode)
[Link]((int)[Link]() + " ");
else
[Link]((char)[Link]() + " ");
}
Later we’ll show how the Visitor pattern can eliminate the use of downcasts!
The Iterator Pattern
Other Considerations
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Iterator pattern can be applied to access all nodes in an
expression tree flexibly & extensibly.
• Understand the structure & functionality of the Iterator pattern.
• Know how to implement the Iterator pattern in Java.
• Be aware of other considerations when applying the Iterator pattern.
Iterator GoF Object Behavioral
Consequences
+ Flexibility
• Aggregate & traversal objects are
decoupled & can (co-)evolve
separately ExpressionTree ComponentNode
Composite LeafNode
UnaryNode
Composite
BinaryNode …
Java Iterator
PreOrder
Iterator …
Iterator GoF Object Behavioral
Consequences
+ Flexibility
• Aggregate & traversal objects are
decoupled & can (co-)evolve
separately ExpressionTree ComponentNode
Composite LeafNode
UnaryNode
Adding new traversal
algorithms shouldn’t affect
the expression tree elements. Composite
BinaryNode …
Java Iterator
PreOrder
Iterator …
Iterator GoF Object Behavioral
Consequences
+ Flexibility
• Aggregate & traversal objects are
decoupled & can (co-)evolve
separately ExpressionTree ComponentNode
Composite LeafNode
UnaryNode
Composite
BinaryNode …
Java Iterator
Adding new subclasses of
CompositeBinaryNode
shouldn’t affect the iterators.
PreOrder
Iterator …
Iterator GoF Object Behavioral
Consequences
+ Multiplicity
• Supports multiple iterators &
multiple traversal algorithms
Later we’ll apply the Strategy pattern to support multiple traversal algorithms.
Iterator GoF Object Behavioral
Consequences
– Overhead
Significant overhead can occur
• Additional communication between
if there is a distribution or
iterator & aggregate user/kernel boundary crossing.
Composite LeafNode
UnaryNode
Composite
BinaryNode …
Java Iterator
PreOrder
Iterator …
Iterator GoF Object Behavioral
Consequences
– Dependencies
• The iterator implementation may
depend on the aggregate’s
implementation ExpressionTree ComponentNode
Composite LeafNode
UnaryNode
Composite
BinaryNode …
Java Iterator
PreOrder
… Adding a new subclass for
Iterator
CompositeTernaryNode
may affect the iterators.
Iterator GoF Object Behavioral
Implementation considerations
• Iterator style
• Java iterators vs. GoF iterators
• Java iterators are similar—but not identical to—GoF iterators, e.g.,
for(Iterator<ExpressionTree> it = [Link]();
[Link]();)
doSomethingWithIterator([Link]());
See [Link]/javase/8/docs/api/java/util/[Link]
Iterator GoF Object Behavioral
Implementation considerations
• Iterator style
• Java iterators vs. GoF iterators
• Java iterators are similar—but not identical to—GoF iterators, e.g.,
for(Iterator<ExpressionTree> it = [Link]();
[Link]();)
doSomethingWithIterator([Link]());
• Here’s the equivalent Java code for GoF-style iterators
for(GoFIterator it = [Link]();
![Link]();
[Link]())
doSomethingWithIterator([Link]());
Iterator GoF Object Behavioral
Implementation considerations
• Iterator style
• Java iterators vs. C++11 STL iterators
• C++ Standard Template Library (STL) iterators mimic native C/C++
pointer arithmetic syntax/semantics
for (auto it = expr_tree.begin ();
it != expr_tree.end ();
++it)
do_something_with_iterator (*it);
See [Link]/iterators-c-stl
Iterator GoF Object Behavioral
Implementation considerations
• Iterator style
• Java iterators vs. C++11 STL iterators
• C++ Standard Template Library (STL) iterators mimic native C/C++
pointer arithmetic syntax/semantics
for (auto it = expr_tree.begin ();
it != expr_tree.end ();
++it)
do_something_with_iterator (*it);
for(Spliterator<ExpressionTree> s = [Link]();
[Link](action);)
doSomethingWithSpliterator(s);
Create a spliterator
for an expression tree
See [Link]/javase/8/docs/api/java/util/[Link]
Iterator GoF Object Behavioral
Implementation considerations
• Iterator style
• Java iterators vs. C++11 STL iterators
• Modern Java also supports a “Spliterator” (splitable iterator)
Consumer<ExpressionTree> action;
for(Spliterator<ExpressionTree> s = [Link]();
[Link](action);)
doSomethingWithSpliterator(s);
tryAdvance() combines
hasNext() & next()
Iterator GoF Object Behavioral
Implementation considerations
• Internal iterators vs.
List<URL> newUrls = urlList
external iterators
.stream()
.filter(s -> [Link]("[Link]"))
.map(s -> [Link]("[Link]",
"[Link]"))
.map(rethrowFunction(URL::new))
.collect(toList());
List<URL> newUrls =
new ArrayList<URL>();
...
for (Iterator<List> i = [Link](); [Link](); ) {
String url = [Link]();
if () continue;
else
[Link](new URL([Link]("[Link]",
"[Link]")));
}
See [Link]/java-8/java-8-internal-iterators-vs-external-iterators
Iterator GoF Object Behavioral
Implementation considerations
• Internal iterators vs.
List<URL> newUrls = urlList
external iterators
.stream()
.filter(s -> [Link]("[Link]"))
.map(s -> [Link]("[Link]",
"[Link]"))
.map(rethrowFunction(URL::new))
.collect(toList());
See [Link]/publications/print_versions/pdf/[Link]
Iterator GoF Object Behavioral
Implementation considerations
• Violating the aggregate’s private class Itr
implements Iterator<E> {
encapsulation
int cursor
int lastRet = -1;
int expectedModCount = modCount;
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData =
[Link];
[Link]() hard-codes a
dependency on the if (i >= [Link])
ArrayList implementation. throw new
ConcurrentModificationException();
cursor = i + 1;
return (E)elementData[lastRet = i];
}
See share/classes/java/util/[Link]
Iterator GoF Object Behavioral
Implementation considerations Fail Fast Fail Safe Iterator
• Overhead & behavior in Iterator
concurrent programs Throw Yes No
Concurrent
Modification
Exception
Clone No Yes
object
Memory No Yes
overhead
See [Link]/2014/04/[Link]
Iterator GoF Object Behavioral
Implementation considerations
• Batching in programs that
cross distribution or user/
kernel boundaries
Batch Iterator
See [Link]/~schmidt/[Link]
Iterator GoF Object Behavioral
Known uses
• Unidraw Iterator
• C++ STL iterators
• C buffered I/O
• C++11 range-based for
loops & Java for-each
loops
• JDK Iterator, Iterable,
& Spliterator
Summary of the Iterator Pattern
• Iterator creates objects that traverse the Composite-based expression tree &
access each of its elements one at a time.
Bridge
ExpressionTree ComponentNode
Java Iterator
Composite
BinaryNode …
Iterator Composite
We’ll combine Iterator with other patterns to further improve our app design.
The Strategy Pattern
Motivating Example
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Strategy pattern can be Java Iterator
applied in the expression tree processing next()
app to encapsulate variability of algorithm hasNext()
remove()
& platform behaviors via common APIs.
LevelOrder
Iterator
InOrder
Iterator
PostOrder
Iterator
PreOrder
Iterator
Douglas C. Schmidt
Motivating the Need for
the Strategy Pattern in
the Expression Tree App
A Pattern for Changing Behaviors Transparently
Purpose: Encapsulate variability of behaviors via a common API whose
implementations can be changed transparently with respect to clients.
Bridge
ExpressionTree ComponentNode
Java Iterator
Iterator
Composite
BinaryNode …
Composite
LevelOrder
Iterator
InOrder
Iterator
Java
Queue
PostOrder Java
Iterator Stack
PreOrder
Strategy Iterator
class ExpressionTree {
...
public
Iterator<ExpressionTree>
iterator() {
return new
PreOrderIterator
(this);
}
...
Problem: Obtrusive Behavior Changes
• Hard-coding certain implementations of these behaviors is problematic since
obtrusive changes would be needed to support alternatives, e.g.,
• Adding new traversal algorithms
InOrder
Iterator
PostOrder
Iterator
PreOrder
Iterator
InOrder
Iterator
PostOrder
Define an interface for creating Iterator
an object, but let implementation
PreOrder
decide which class to instantiate. Iterator
See [Link]/wiki/Factory_method_pattern
Strategy Hierarchy Overview
• The root of the hierarchy is based on the Java Iterator
Iterator pattern & Java Iterator interface. next()
hasNext()
remove()
Strategy Hierarchy Overview
• Implementations of the Java Iterator Java Iterator
interface define various iterator next()
strategies. hasNext()
remove()
• e.g., pre-order, post-order, level-order,
& in-order iterators
LevelOrder
Iterator
InOrder
Iterator
PostOrder
Iterator
PreOrder
Iterator
Strategy Hierarchy Overview
• Implementations of the Java Iterator Java Iterator
interface define various iterator next()
strategies. hasNext()
remove()
• e.g., pre-order, post-order, level-order,
& in-order iterators
LevelOrder
Iterator
InOrder
Iterator
Java
Queue PostOrder
Iterator
Java Stack & Queue objects
Java PreOrder
track the state needed to perform Stack Iterator
non-recursive tree traversals.
Strategy Hierarchy Overview
• Implementations of the Java Iterator Java Iterator
interface define various iterator next()
strategies. hasNext()
remove()
• e.g., pre-order, post-order, level-order,
& in-order iterators
LevelOrder
Iterator
InOrder
Iterator
Java
Queue PostOrder
Iterator
Java PreOrder
Stack Iterator
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Strategy pattern can be applied in the expression tree
processing app to encapsulate variability of algorithm & platform behaviors
via common APIs.
• Understand the structure & functionality of the Strategy pattern.
Douglas C. Schmidt
Structure & Functionality
of the Strategy Pattern
Strategy GoF Object Behavioral
Intent Java Iterator
• Define a family of algorithms, encapsulate next()
each one, & make them interchangeable to hasNext()
remove()
let clients & algorithms vary independently
LevelOrder
Iterator
InOrder
Iterator
PostOrder
Iterator
PreOrder
Iterator
See [Link]/wiki/Strategy_pattern
Strategy GoF Object Behavioral
Applicability Java Iterator
• When an object should be configurable next()
hasNext()
with one of many algorithms remove()
LevelOrder
Iterator
InOrder
Iterator
PostOrder
Iterator
PreOrder
Iterator
Strategy GoF Object Behavioral
Applicability Java Iterator
• When an object should be configurable next()
hasNext()
with one of many algorithms remove()
• And all algorithms can be encapsulated
LevelOrder
Iterator
InOrder
Iterator
PostOrder
Iterator
PreOrder
Iterator
Strategy GoF Object Behavioral
Applicability Java Iterator
• When an object should be configurable next()
hasNext()
with one of many algorithms remove()
• And all algorithms can be encapsulated
• And one interface covers all
LevelOrder
encapsulations Iterator
InOrder
Iterator
PostOrder
Iterator
PreOrder
Iterator
Strategy GoF Object Behavioral
Structure & participants
Strategy GoF Object Behavioral
Structure & participants
Java Iterator
Strategy GoF Object Behavioral
Structure & participants
PreOrderIterator, PostOrderIterator,
LevelOrderIterator, InOrderIterator, etc.
Strategy GoF Object Behavioral
Structure & participants
Unused
Context is primarily useful if some strategies need more than the common API.
Strategy GoF Object Behavioral
Structure & participants
Strategy
Bridge
Strategy
Bridge
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Strategy pattern can be applied in the expression tree
processing app to encapsulate variability of algorithm & platform behaviors
via common APIs.
• Understand the structure & functionality of the Strategy pattern.
• Know how to implement the Strategy pattern in Java.
Strategy GoF Object Behavioral
Strategy example in Java
• The iterator() factory method in the ExpressionTree class returns
the requested iterator strategy.
class ExpressionTree {
...
public Iterator<ExpressionTree> iterator
(String traversalOrderRequest) {
return [Link](this,
traversalOrderRequest);
}
}
See ExpressionTree/CommandLine/src/expressiontree/tree
Strategy GoF Object Behavioral
Strategy example in Java
• The iterator() factory method in the ExpressionTree class returns
the requested iterator strategy.
class ExpressionTree {
...
public Iterator<ExpressionTree> iterator
(String traversalOrderRequest) {
return [Link](this,
traversalOrderRequest);
}
} This Factory Method forwards
to an internal factory.
Strategy GoF Object Behavioral
Strategy example in Java
• The iterator() factory method in the ExpressionTree class returns
the requested iterator strategy.
class ExpressionTree {
...
public Iterator<ExpressionTree> iterator
(String traversalOrderRequest) {
return [Link](this,
traversalOrderRequest);
}
}
This
See OO design & implementation exhibits high-pattern density!
ExpressionTree/CommandLine/src/expressiontree/iterators
Strategy GoF Object Behavioral
Strategy example in Java
• The [Link]() factory method dynamically
allocates the appropriate Iterator strategy.
IteratorFactory Iterator
Command
execute()
InOrder PostOrder
Iterator
HashMap<String, IteratorFactoryCommand> Iterator
See [Link]/java-8/constructor-references-java-8-simplified-tutorial
Strategy GoF Object Behavioral
Strategy example in Java
• The [Link]() factory method dynamically
allocates the appropriate Iterator strategy.
Function<Iterator<ExpressionTree>,
ExpressionTree> Iterator
apply()
HashMap<String,
Function<Iterator<ExpressionTree>, InOrder PostOrder
Iterator
ExpressionTree> Iterator
See [Link]/javase/8/docs/api/java/util/function/[Link]
Strategy GoF Object Behavioral
Strategy example in Java
• The [Link]() factory method dynamically
allocates the appropriate Iterator strategy.
public class IteratorFactory {
IteratorFactory() {
[Link]("in-order", new IteratorFactoryCommand(){
Iterator<ExpressionTree> execute(ExpressionTree tree)
{ return new InOrderIterator(tree); }});
...
}
} ...
See ExpressionTree/CommandLine/src/expressiontree/iterators
Strategy GoF Object Behavioral
Strategy example in Java
• The [Link]() factory method dynamically
allocates the appropriate Iterator strategy.
public class IteratorFactory { We first apply Command to
initialize IteratorFactory.
private interface IteratorFactoryCommand
{ Iterator<ExpressionTree> execute(ExpressionTree tree); }
IteratorFactory() {
[Link]("in-order", new IteratorFactoryCommand(){
Iterator<ExpressionTree> execute(ExpressionTree tree)
{ return new InOrderIterator(tree); }});
...
}
} ...
Strategy GoF Object Behavioral
Strategy example in Java
• The [Link]() factory method dynamically
allocates the appropriate Iterator strategy.
public class IteratorFactory { Command interface
IteratorFactory() {
[Link]("in-order", new IteratorFactoryCommand(){
Iterator<ExpressionTree> execute(ExpressionTree tree)
{ return new InOrderIterator(tree); }});
...
}
} ...
IteratorFactory() {
[Link]("in-order", new IteratorFactoryCommand(){
Iterator<ExpressionTree> execute(ExpressionTree tree)
{ return new InOrderIterator(tree); }});
...
}
} ...
Strategy GoF Object Behavioral
Strategy example in Java
• The [Link]() factory method dynamically
allocates the appropriate Iterator strategy.
public class IteratorFactory {
IteratorFactory() {
[Link]("in-order",
InOrderIterator::new);
...
} Java lambda that creates
} ... an InOrderIterator via
a constructor reference
Strategy GoF Object Behavioral
Strategy example in Java
• The [Link]() factory method dynamically
allocates the appropriate Iterator strategy.
The factory method
public class IteratorFactory { ...
public Iterator<ExpressionTree> iterator(ExpressionTree tree,
String traversalOrderRequest) {
IteratorFactoryCommand command =
[Link](traversalOrderRequest);
if (command != null)
return [Link](tree);
else
throw new IllegalArgumentException
(traversalOrderRequest
+ " is not a supported traversal order");
...
}
The factory method uses a map to find/execute the command that makes an iterator.
Strategy GoF Object Behavioral
Strategy example in Java
• The [Link]() factory method dynamically
allocates the appropriate Iterator strategy.
public class IteratorFactory { ...
public Iterator<ExpressionTree> iterator(ExpressionTree tree,
String traversalOrderRequest) {
if (command != null)
return [Link](tree);
else
throw new IllegalArgumentException
(traversalOrderRequest
+ " is not a supported traversal order");
...
}
Strategy GoF Object Behavioral
Strategy example in Java
• The [Link]() factory method dynamically
allocates the appropriate Iterator strategy.
public class IteratorFactory { ...
public Iterator<ExpressionTree> iterator(ExpressionTree tree,
String traversalOrderRequest) {
IteratorFactoryCommand command =
[Link](traversalOrderRequest);
If found, execute it to make an iterator.
if (command != null)
return [Link](tree);
else
throw new IllegalArgumentException
(traversalOrderRequest
+ " is not a supported traversal order");
...
}
Strategy GoF Object Behavioral
Strategy example in Java
• The [Link]() factory method dynamically
allocates the appropriate Iterator strategy.
public class IteratorFactory { ...
public Iterator<ExpressionTree> iterator(ExpressionTree tree,
String traversalOrderRequest) {
IteratorFactoryCommand command =
[Link](traversalOrderRequest);
if (command != null)
return [Link](tree);
else
throw new IllegalArgumentException
(traversalOrderRequest
+ " is not a supported traversal order");
... Otherwise, user gave an unsupported
} request, so throw an exception.
The Strategy Pattern
Other Considerations
Douglas C. Schmidt
Learning Objectives in This Lesson
• Recognize how the Strategy pattern can be applied in the expression tree
processing app to encapsulate variability of algorithm & platform behaviors
via common APIs.
• Understand the structure & functionality of the Strategy pattern.
• Know how to implement the Strategy pattern in Java.
• Be aware of other considerations when applying the Strategy pattern.
Strategy GoF Object Behavioral
Consequences
+ Greater flexibility & reuse
• e.g., by strategizing runtime platform I/O
mechanisms, most code can be reused across
the Android GUI variant & the command-line
variant of the expression tree processing app.
Strategy GoF Object Behavioral
Consequences
+ Behaviors can change dynamically
class ExpressionTree {
public Iterator<ExpressionTree> iterator
(String traversalOrderRequest) {
return [Link](this,
traversalOrderRequest);
... The [Link]() method enables
transparent replacement of different iterator
strategies at runtime without breaking client code.
for(Iterator<ExpressionTree> it = [Link]("in-order");
[Link]();) {
ExpressionTree node = [Link]();
doSomethingWithNode(node);
}
Strategy GoF Object Behavioral
Consequences
+ Behaviors can change dynamically
class ExpressionTree {
public Iterator<ExpressionTree> iterator
(String traversalOrderRequest) {
return [Link](this,
traversalOrderRequest);
... The [Link]() method enables
transparent replacement of different iterator
strategies at runtime without breaking client code.
for(Iterator<ExpressionTree> it = [Link]("post-order");
[Link]();) {
ExpressionTree node = [Link]();
doSomethingWithNode(node);
}
e.g., can change from “in-order” to “post-order”
traversal simply by changing this parameter
Strategy GoF Object Behavioral
Consequences
– Overhead of strategy creation & communication
• Strategy can increase the number of classes/objects created in a program.
Java Iterator
next()
hasNext()
remove()
LevelOrder
Iterator
InOrder
Iterator
PostOrder
Iterator
PreOrder
Iterator
Strategy GoF Object Behavioral
Consequences
– Overhead of strategy creation & communication
• Strategy can increase the number of classes/objects created in a program.
Java Iterator
next()
hasNext()
remove()
LevelOrder
Iterator
InOrder
Iterator
See [Link]/articles/strategy-pattern-using-lambda
Strategy GoF Object Behavioral
Consequences
– Overhead of strategy creation & communication
• Strategy can increase the number of classes/objects created in a program.
• Dynamically bound implementations of Strategy may incur additional
virtual method call overhead.
See [Link]/blog/2015/black-magic-method-dispatch
Strategy GoF Object Behavioral
Consequences
– Inflexible strategy interface
See [Link]/wiki/Procrustes#Cultural_references
Strategy GoF Object Behavioral
Consequences
– Inflexible strategy interface
• Motivates need for Context, which stores values beyond one-size-fits-all
interface
Strategy GoF Object Behavioral
Consequences in args
– Semantic incompatibility of
OBJ operation()
Client REF Object (Servant)
out args +
return
multiple strategies used
together inconsistently
IDL
SKEL
IDL ORB
STUBS INTERFACE Object Adapter
Null-lock
synchronization
strategy
Thread pool
concurrency Reactive event
strategy demuxing strategy
See [Link]/~schmidt/PDF/[Link]
Strategy GoF Object Behavioral
Consequences in args
– Semantic incompatibility of
OBJ operation()
Client REF Object (Servant)
out args +
return
multiple strategies used
together inconsistently
• May require other patterns, IDL
SKEL
such as Abstract Factory IDL
STUBS
ORB
INTERFACE Object Adapter
Null-lock
synchronization
strategy
Thread pool
concurrency Reactive event
strategy demuxing strategy
See [Link]/wiki/Abstract_factory_pattern
Strategy GoF Object Behavioral
Implementation considerations
• Exchanging information between a strategy & its context
...
std::vector<int> v ({1, 6, 2, 8, 3, 9});
Comparison
strategy (functor)
Java’s support for garbage collection often obviates the need for Bridge.
Strategy GoF Object Behavioral
Known uses
• InterViews text formatting
• RTL register allocation & scheduling strategies
• ET++SwapsManager calculation engines
• The ACE ORB (TAO) real-time object request broker middleware
in args
Client
OBJ operation() Request demuxing
Object (Servant)
(De)marshaling REF out args + strategy
return
strategy
Request transport
IDL strategy
Connection SKEL
management strategy IDL ORB
STUBS INTERFACE Object Adapter
See [Link]/wiki/Function_object#In_C_and_C++
Strategy GoF Object Behavioral
Known uses
• InterViews text formatting
• RTL register allocation & scheduling strategies
• ET++SwapsManager calculation engines
• The ACE ORB (TAO) real-time object request broker middleware
• C++ Standard Template Library (STL)
• Java JDK class libraries
[Link](nameArray, String::compareToIgnoreCase);
Comparison strategy
(method reference)
See [Link]/wiki/Function_object#In_Java
Summary of the Strategy Pattern
• Strategy encapsulates the variability of behaviors via a common API whose
implementations can be changed transparently with respect to clients.
Bridge
ExpressionTree ComponentNode
Java Iterator
Iterator
Composite
BinaryNode …
Composite
LevelOrder
Iterator
InOrder
Iterator
Java
Queue
PostOrder Java
Iterator Stack
PreOrder
Strategy Iterator
Douglas C. Schmidt
Learning Objectives in This Lesson
• Understand how to develop an algorithmic decomposition of the expression
tree processing app.
Start
Initialize
Prompt User
Read Expr
Build Tree
Process Tree
No
EOF?
Yes
End
Douglas C. Schmidt
Lesson Introduction
Lesson Introduction
• Algorithmic decomposition is a historically popular design Start
method that structures the software based on the actions
performed by the system. Initialize
Prompt User
Read Expr
Build Tree
Process Tree
B
No
[Link]/windows/software-complexity- EOF?
bringing-order-to-ch/199901062 contains more Yes
information on algorithmic decomposition. End
Lesson Introduction
• Algorithmic decomposition is a historically popular design Start
method that structures the software based on the actions
performed by the system. Initialize
specific actions. No A
Verbose
Prompt
Read Expr
Succinct
Prompt Build Tree
B
Process Tree
Yes
Print?
No Print Tree
B
Yes No
Eval? EOF?
No Eval Tree Yes
End
See [Link]/16.355/[Link]
Lesson Introduction
• Algorithmic decomposition is a historically popular design
method that structures the software based on the actions
performed by the system.
• It iteratively & recursively
decomposes general actions
in an algorithm into more
specific actions.
• The design components in
an algorithmic decomposition
often correspond to the
processing steps in an
execution sequence.
Lesson Introduction
• Algorithmic decomposition is a historically popular design
method that structures the software based on the actions
performed by the system.
• It iteratively & recursively typedef struct TreeNode {
decomposes general actions ...
} TreeNode;
in an algorithm into more
specific actions.
• The design components in void prompt_user(int verbose);
an algorithmic decomposition char *read_expr(FILE *fp);
often correspond to the TreeNode *build_tree
processing steps in an (const char *expr);
execution sequence. void process_tree
(TreeNode *root, FILE *fp);
• These steps are typically void eval_tree
implemented via functions. (TreeNode *root, FILE *fp);
void print_tree
(TreeNode *root, FILE *fp);
...
Lesson Introduction
• Algorithmic decomposition is a historically popular design
method that structures the software based on the actions
performed by the system.
• It iteratively & recursively typedef struct TreeNode {
decomposes general actions ...
} TreeNode;
in an algorithm into more
specific actions. We’ll explore this shortly.
• The design components in void prompt_user(int verbose);
an algorithmic decomposition char *read_expr(FILE *fp);
often correspond to the TreeNode *build_tree
processing steps in an (const char *expr);
execution sequence. void process_tree
(TreeNode *root, FILE *fp);
• These steps are typically void eval_tree
implemented via functions. (TreeNode *root, FILE *fp);
void print_tree
(TreeNode *root, FILE *fp);
...
We’ll explore this shortly.
Douglas C. Schmidt
Algorithmic Decomposition
of an Expression Tree
Algorithmic Decomposition of an Expression Tree
• A typical algorithmic decomposition for implementing expression trees
would use a C struct/union to represent the main data structure.
Douglas C. Schmidt
Learning Objectives in This Lesson
• Understand how to develop an algorithmic decomposition of the expression
tree processing app.
Start
• Evaluate the benefits & limitations
of algorithmic decomposition. Initialize
Prompt User
Read Expr
Build Tree
Process Tree
No
EOF?
Yes
End
B
Prompt User
Yes
Print?
No A
Print Tree
Yes Read Expr
Eval?
No Eval Tree
Build Tree
A
Yes Process Tree
Verbose?
No
B
Verbose
Prompt No
EOF?
Succinct
Yes
Prompt
End
Benefits of Algorithmic Decomposition
• Algorithmic steps map clearly onto typedef struct TreeNode {
relatively straightforward & efficient ...
language features found in second & } TreeNode;
third generation programming
languages.
void prompt_user(int verbose);
• e.g., structs & functions char *read_expr(FILE *fp);
in C/C++ TreeNode *build_tree
(const char *expr);
void process_tree
(TreeNode *root, FILE *fp);
void eval_tree
(TreeNode *root, FILE *fp);
void print_tree
(TreeNode *root, FILE *fp);
...
Benefits of Algorithmic Decomposition
• No need to incur the overhead void print_tree(TreeNode *root,
of virtual function call in this FILE *fp) {
implementation switch(root->tag_) {
case NUM: fprintf(fp, "%d",
root->num_);
break;
case UNARY:
fprintf(fp, "(%s", root->op_[0]);
print_tree(root->unary_, fp);
fprintf(fp, ")"); break;
case BINARY:
fprintf(fp, "(");
print_tree(root->binary_.l_, fp);
fprintf(fp, "%s", root->op_[0]);
print_tree(root->binary_.r_, fp);
fprintf(fp, ")"); break;
...
}
Douglas C. Schmidt
Limitations With
Algorithmic Decomposition
Limitations With Algorithmic Decomposition
• Complexity resides in (variable) algorithms rather than (stable) structure
void print_tree(TreeNode *root, FILE *fp) {
switch(root->tag_) {
case NUM: fprintf(fp, "%d", root->num_); TreeNode data
break; structure is “passive”
case UNARY: & functions do all
fprintf(fp, "(%s", root->op_[0]); the real work.
print_tree(root->unary_, fp);
fprintf(fp, ")"); break;
case BINARY:
fprintf(fp, "(");
print_tree(root->binary_.l_, fp);
fprintf(fp, "%s", root->op_[0]);
print_tree(root->binary_.r_, fp);
fprintf(fp, ")"); break;
...
}
Limitations With Algorithmic Decomposition
• Complexity resides in (variable) algorithms rather than (stable) structure
void print_tree(TreeNode *root, FILE *fp) {
switch(root->tag_) {
case NUM: fprintf(fp, "%d", root->num_);
break;
case UNARY:
fprintf(fp, "(%s", root->op_[0]);
print_tree(root->unary_, fp);
fprintf(fp, ")"); break;
case BINARY:
fprintf(fp, "(");
It’s all too easy to
print_tree(root->binary_.l_, fp);
make mistakes when
fprintf(fp, "%s", root->op_[0]);
switching on type tags.
print_tree(root->binary_.r_, fp);
fprintf(fp, ")"); break;
...
}
Limitations With Algorithmic Decomposition
• Incomplete/inefficient modeling of application domain
typedef struct TreeNode {
enum { NUM, UNARY, BINARY } tag_;
short use_;
union {
char op_[3];
int num_;
} o_;
#define num_ o_.num_
#define op_ o_.op_
union {
struct TreeNode *unary_;
struct { struct TreeNode *l_,
*r_;} binary_;
} c_;
#define unary_ c_.unary_
#define binary_ c_.binary_
} TreeNode;
Limitations With Algorithmic Decomposition
• Incomplete/inefficient modeling of application domain
typedef struct TreeNode {
enum { NUM, UNARY, BINARY } tag_;
short use_;
union {
char op_[3]; Tight coupling between
int num_; nodes/edges in union
} o_;
#define num_ o_.num_
#define op_ o_.op_
union {
struct TreeNode *unary_;
struct { struct TreeNode *l_,
*r_;} binary_;
} c_;
#define unary_ c_.unary_
#define binary_ c_.binary_
} TreeNode;
Limitations With Algorithmic Decomposition
• Incomplete/inefficient modeling of application domain tag_
typedef struct TreeNode {
use_
enum { NUM, UNARY, BINARY } tag_;
short use_;
op_
union {
char op_[3];
num_
int num_;
} o_;
#define num_ o_.num_
#define op_ o_.op_ unary_
union {
struct TreeNode *unary_;
struct { struct TreeNode *l_,
*r_;} binary_; binary_
} c_;
#define unary_ c_.unary_
#define binary_ c_.binary_
Wastes space by making
} TreeNode;
worst-case assumptions with
respect to structs & unions
Wasted space is very problematic for “NUM” nodes, which are more than 1/2.
Limitations With Algorithmic Decomposition
• Little/no encapsulation
typedef struct TreeNode { Implementation details
enum { NUM, UNARY, BINARY } tag_; available to clients since all
short use_; fields are public in a struct!
union {
char op_[3];
int num_;
} o_;
#define num_ o_.num_
#define op_ o_.op_
union {
struct TreeNode *unary_;
struct { struct TreeNode *l_,
*r_;} binary_;
} c_;
#define unary_ c_.unary_
#define binary_ c_.binary_
} TreeNode;
Limitations With Algorithmic Decomposition
• Little/no encapsulation
typedef struct TreeNode {
enum { NUM, UNARY, BINARY } tag_;
short use_;
union {
char op_[3];
int num_;
} o_;
#define num_ o_.num_
#define op_ o_.op_
union {
struct TreeNode *unary_;
struct { struct TreeNode *l_,
*r_;} binary_; Use of macros pollutes
} c_; global namespace.
#define unary_ c_.unary_
#define binary_ c_.binary_
} TreeNode;
Limitations With Algorithmic Decomposition
• Changes ripple through the entire program
typedef struct TreeNode {
enum { NUM, UNARY, BINARY, TERNARY } tag_;
union {
char op_[4];
int num_;
} o_;
...
union { The TreeNode data structure
... must be modified, which will
struct { affect many parts of the app.
Tree_Node *l_,
*m_,
*r_;
} ternary_;
} c_;
#define ternary_ c_.ternary_
} TreeNode;
Limitations With Algorithmic Decomposition
• Changes ripple through the entire program
void print_tree(TreeNode *root, FILE *fp) {
switch(root->tag_) {
...
case TERNARY: All functions that switch on tag_ must be modified.
fprintf(fp, "(");
print_tree(root->ternary_.l_, fp);
fprintf(fp, "%s", root->op_[0]);
print_tree(root->binary_.m_, fp);
fprintf(fp, "%s", root->op_[1]);
print_tree(root->binary_.r_, fp);
fprintf(fp, ")"); break;
...
}
Douglas C. Schmidt
Putting All the
Pieces Together
Putting All the Pieces Together
• An algorithmic decomposition yields a top-down design Start
based on the actions performed by the system.
Initialize
A Prompt User
Yes
Verbose?
A
No
Verbose
Read Expr
Prompt
Bridge
ExpressionTree ComponentNode
rethinking modeling, design, << create >>
& implementation. Composite LeafNode
UnaryNode
Java Iterator
Iterator
Composite
BinaryNode …
Composite
LevelOrder
Iterator
InOrder
Iterator
Java
Queue
PostOrder Java
Iterator Stack
PreOrder
Strategy Iterator
Evaluating the Object-Oriented
Design of the Expression Tree
Processing App
Douglas C. Schmidt
Learning Objectives in This Lesson
• Evaluate the pros & cons of OO design relative to
algorithmic decomposition.
ExpressionTree
ComponentNode
Composite
LeafNode
UnaryNode
CompositeBinary CompositeNegate
Node Node
Composite Composite
AddNode SubtractNode
Composite Composite
MultiplyNode DivideNode
Learning Objectives in This Lesson
• Evaluate the pros & cons of OO design relative to
algorithmic decomposition.
• Put all the pieces together.
Douglas C. Schmidt
Benefits of Object-
Oriented Design
Benefits of Object-Oriented Design
• More accurate modeling of the application domain
Composite
LeafNode
UnaryNode
CompositeBinary CompositeNegate
Node Node
Composite Composite
AddNode SubtractNode
Composite Composite
MultiplyNode DivideNode
Benefits of Object-Oriented Design
• More effective encapsulation
ExpressionTree
Composite
LeafNode
UnaryNode
CompositeBinary CompositeNegate
Node Node
Composite Composite
AddNode SubtractNode
Composite Composite
MultiplyNode DivideNode
Benefits of Object-Oriented Design
• Straightforward to extend the app to add new types of nodes
ExpressionTree
CompositeBinary CompositeNegate
Node Node
Composite Composite
AddNode SubtractNode
Interpreter
Composite Composite
LeafNode NumberExpr BinaryExpr UnaryExpr
BinaryNode UnaryNode
<<build>>
Composite Composite Composite
AddExpr SubtractExpr NegateExpr
AddNode SubtractNode NegateNode
Composite Composite
MultiplyExpr DivideExpr
MultiplyNode DivideNode <<build>>
Limitations With Object-Oriented Design
• The solution may be overly rich in classes & associated structures.
<< use >>
ExpressionTree TreeContext InterpreterContext
Interpreter
Composite Composite
LeafNode NumberExpr BinaryExpr UnaryExpr
BinaryNode UnaryNode
<<build>>
Composite Composite Composite
AddExpr SubtractExpr NegateExpr
AddNode SubtractNode NegateNode
Composite Composite
MultiplyExpr DivideExpr
MultiplyNode DivideNode <<build>>
See [Link]/wiki/Configuration_management
Limitations With Object-Oriented Design
• The solution may be overly rich in classes & associated structures.
<< use >>
ExpressionTree TreeContext InterpreterContext
Interpreter
Composite Composite
LeafNode NumberExpr BinaryExpr UnaryExpr
BinaryNode UnaryNode
<<build>>
Composite Composite Composite
AddExpr SubtractExpr NegateExpr
AddNode SubtractNode NegateNode
Composite Composite
MultiplyExpr DivideExpr
MultiplyNode DivideNode <<build>>
See [Link]/blog/2015/black-magic-method-dispatch
Douglas C. Schmidt
Putting All the
Pieces Together
Putting All the Pieces Together
• OO designs are characterized by structuring software architectures around
objects & classes in specific domains.
ExpressionTree ComponentNode
Visitor
<< accept >>
<< create >>
Composite LeafNode
UnaryNode
LevelOrder
Iterator
InOrder
Iterator
Java
Queue
PostOrder Java
Iterator Stack
PreOrder
Iterator
Putting All the Pieces Together
• OO designs are characterized by structuring software architectures around
objects & classes in specific domains. Start
• Rather than on actions performed
by the software Initialize
Prompt User
Read Expr
Build Tree
Process Tree
No
EOF?
Yes
End
Putting All the Pieces Together
• OO designs are characterized by structuring software architectures around
objects & classes in specific domains.
• Systems evolve & functionality changes,
ExpressionTree
Composite
LeafNode
UnaryNode
CompositeBinary CompositeNegate
Node Node
Composite Composite
AddNode SubtractNode
Composite Composite
MultiplyNode DivideNode
Putting All the Pieces Together
• OO designs are characterized by structuring software architectures around
objects & classes in specific domains.
• Systems evolve & functionality changes,
ExpressionTree
Composite Composite
AddNode SubtractNode
Composite Composite
MultiplyNode DivideNode
Iterator
Composite
BinaryNode …
Composite
LevelOrder
Iterator
InOrder
Iterator
Java
Queue
PostOrder Java
Iterator Stack
PreOrder
Strategy Iterator