The Template Method Pattern and Function Objects

Another Decoupling Problem
• Example: Design a component that will
approximate the definite integral of an
arbitrary real-to-real function.
• Challenge: How can you decouple the
code that implements the integration
algorithm (e.g., trapezoidal rule, Simpson’s
rule, etc.) from the function to be
integrated, and especially from the code
that evaluates the function to be
integrated?
Solution #1: Abstract Classes
• An abstract class is just like any other
class, except that you do not provide code
to implement one or more methods
• You must extend an abstract class and
provide implementations for all abstract
in Java, both the class and the
methods in order to methods
use it in
client
code
with
no bodies
are
declared with the keyword abstract
The Template Method Pattern
• You can use an abstract class to address
the decoupling problem in the example:
• Design an Integrator component that has an
integral method
• Implement this method in an abstract class, in
which the integral code calls an abstract
method f that computes the function to be
integrated
• Implement f in an extension of the abstract
class
Template Method Pattern UML
<<interface>>
IRealToRealIntegrator
f is the template method:
f its
in this
extension
computes
body
is here, i.e.,
in an
a different
so itclass
is
extension
of function,
the abstract
decoupled from integral
+ f (double): double
+ integral (double, double):
double
f is the hook method:
it is called by integral
RealToRealIntegrator_1_<<partially
but has no body here
Cosine
implements>>
<<abstract>>
RealToRealIntegrator_1
+ abstract f (double): double
+ integral (double, double):
double
+ f (double): double
RealToRealIntegrator_1_Square
+ f (double): double
Evaluation
• Two drawbacks:
• It complicates matters by using an abstract
class, which is "neither fish nor fowl" — not an
interface, yet not really like other classes
• The extends between the class that evaluates
f and the (abstract) class that implements
integral is still class-to-class coupling, so
changing the integration method requires
copying and slightly modifying the function
evaluation class
Solution #2: System Thinking
• You could:
• Consider the function to be integrated as a
"system", describe it from the client view using
an interface, implement it in various ways in
different classes — standard OO practice
• Still have an Integrator component that has an
integral method, but now also pass a function
object as a parameter to integral
Function Objects UML
eval in this class evaluates
<<interface>>
a<<interface>>
different function, so it is
IRealToRealIntegrator
IRealToRealFunction
decoupled from integral
what
would
you do if you
+ integral
(IRealToReal+ eval (double): double
Function,
wanted
todouble,
introduce an
double):
interface
withdouble
a contract saying
that this eval returns
x^2?
RealToRealFunctionobject of
this type is
Cosine_1
a function object
RealToRealIntegrator_1
+ integral (IRealToRealFunction, double,
double): double
+ eval (double): double
RealToRealFunctionSquare_1
+ eval (double): double
Evaluation
• The function object approach has two
relative advantages:
• It is faithful to the conceptual model of
systems that we would like to observe
• There is no class-to-class coupling, so there is
complete mix-and-match flexibility to change:
• the integration algorithm
• function being integrated
• the algorithm for evaluating that function