PAT T E R N S , PAT T E R N S
E V E RY W H E R E
@ A R N VA L D , A R R R R C A M P 2 0 1 4
Slide 2
Slide 2 text
D E S I G N
PAT T E R N ?
W H AT I S A
Slide 3
Slide 3 text
2 0 Y E A R S
L AT E R
• are GoF design patterns
still used today?
• are they useful in dynamic
languages?
• is it worth to learn them?
• is it worth to read GoF
book?
Slide 4
Slide 4 text
“ G A N G O F F O U R ” PAT T E R N S
adapter
chain of responsibility
visitor
mediator
proxy
flyweight
command
singleton
builder bridge
abstract factory
factory method
template method
prototype
observer
composite
strategy
decorator
facade
iterator
memento
interpreter
state
Slide 5
Slide 5 text
PAT T E R N
S T R U C T U R E
• description (intent,
applicability etc.)
• implementation (example
code, class diagram etc.)
Slide 6
Slide 6 text
C O M M A N D
Encapsulate a request as an
object, thereby letting you
parameterize clients with
different requests, queue or
log requests, and support
undoable operations.
Slide 7
Slide 7 text
C O M M A N D -
U S E C A S E
• I’m writing a text editor
• I want to implement
“copy” and “paste”
buttons
Slide 8
Slide 8 text
C O M M A N D - C O D E
class Button
def initialize(command); @command = command; end
def on_click; @command.call; end
end
class Copy
def call; clipboard.text = @page.marked_text; end
end
class Paste
def call
@page.text[@cursor.position] += @clipboard.text
end
end
copy_button = Button.new(Copy.new)
paste_button = Button.new(Paste.new)
Slide 9
Slide 9 text
C O M M A N D - C O D E
class Button
def initialize(&blk); @command = blk; end
def on_click; @command.call; end
end
copy_button = Button.new do
clipboard.text = @page.marked_text
end
paste_button = Button.new do
page.text[cursor.position] += clipboard.text
end
Slide 10
Slide 10 text
C O M M A N D
Encapsulate a request as an
object, thereby letting you
parameterize clients with
different requests, queue or
log requests, and support
undoable operations.
Slide 11
Slide 11 text
C O M M A N D - VA R I A N T S
class Paste
def call
@start_position = cursor.position
@text = clipboard
page.text[@start_position] += @text
end
def undo
text.slice!(@start_position, @text.length)
end
end
Slide 12
Slide 12 text
C O M M A N D
• workaround for language
missing feature
• still useful in some cases
Slide 13
Slide 13 text
D E C O R AT O R
Attach additional
responsibilities to an object
dynamically. Decorators
provide a flexible alternative
to subclassing for extending
functionality.
Slide 14
Slide 14 text
D E C O R AT O R -
U S E C A S E
• I’m writing a text editor
• I want to implement
preview in html format
Slide 15
Slide 15 text
class Text
def render; @body; end
end
class TextDecorator
def initialize(text); @text = text; end
def render; @text.render; end
end
class ItalicTextDecorator < TextDecorator
def render; "#{super}"; end
end
D E C O R AT O R - C O D E
Slide 16
Slide 16 text
text = Text.new("this is text")
decoratedText = BoldTextDecorator.new(
ItalicTextDecorator.new(text)
)
decoratedText.render # => this is text
D E C O R AT O R - C O D E
Slide 17
Slide 17 text
D E C O R AT O R - A LT E R N AT I V E
module ItalicTextDecorator
def render; "#{super}"; end
end
module BoldTextDecorator
def render; "#{super}"; end
end
text = Text.new("this is text")
text.extend(ItalicTextDecorator)
text.extend(BoldTextDecorator)
text.render # => this is text
Slide 18
Slide 18 text
D E C O R AT O R
• workaround for missing
feature (extending objects
during runtime)
• name still used, despite
going beyond traditional
definition
Slide 19
Slide 19 text
I T E R AT O R
Provide a way to access
the elements of an
aggregate object
sequentially without
exposing its underlying
representation.
Slide 20
Slide 20 text
I T E R AT O R -
U S E C A S E
• I’m writing a text editor
• I want to implement
opening multiple files
• for each file a new window
should open that will print
text on the screen
Slide 21
Slide 21 text
def open_files(paths)
paths.each { |path| open_file(path) }
end
def open_file(path)
Window.new do |window|
file = File.open(path)
while !file.eof?
window.text << file.readline
end
end
end
I T E R AT O R - C O D E
Slide 22
Slide 22 text
I T E R AT O R
• made it to cores or
standard libraries of many
languages
Slide 23
Slide 23 text
S I N G L E T O N
Ensure a class only has
one instance, and
provide a global point
of access to it.
Slide 24
Slide 24 text
S I N G L E T O N -
U S E C A S E
• I’m writing a text editor
• I want to implement
settings
• I want to be sure there’s
just one place settings are
stored
Slide 25
Slide 25 text
class Settings
class << self
private :new
def instance
@instance ||= new
end
end
end
S I N G L E T O N - C O D E
Slide 26
Slide 26 text
require 'singleton'
class Settings
include Singleton
end
Settings.new # => raises an error
Settings.instance #
Settings.instance #
Settings.instance #
S I N G L E T O N - C O D E
Slide 27
Slide 27 text
Settings.instance #
Settings.send(:new) #
S I N G L E T O N - C O D E
Slide 28
Slide 28 text
Settings = Object # some warnings here
Settings.new #
S I N G L E T O N - C O D E
Slide 29
Slide 29 text
require 'ostruct'
$settings = OpenStruct.new
S I N G L E T O N - C O D E
Slide 30
Slide 30 text
S I N G L E T O N
• available in standard
library
• considered anti-pattern
• Ruby’s features make it
very similar to any global
variable
Slide 31
Slide 31 text
O B S E R V E R
Define a one-to-many
dependency between
objects so that when
one object changes
state, all its dependents
are notified and
updated automatically.
Slide 32
Slide 32 text
O B S E R V E R -
U S E C A S E
• I’m writing a text editor
• I want to implement styles
• All pieces of text having
specific style should
change when this style
changes
Slide 33
Slide 33 text
class Style
def update(attrs)
attrs.each { |k,v| send(:"#{k}=", v) }
notify_observers
end
def notify_observers
@observers.each { |o| o.notify(self) }
end
def add_observer(observer)
@observers << observer
end
end
O B S E R V E R - C O D E
Slide 34
Slide 34 text
class Paragraph
def apply_style(style)
style.add_observer(self)
end
def notify(style)
update_formatting(style)
end
end
O B S E R V E R - C O D E
Slide 35
Slide 35 text
class Style
include Observable
def update(attrs)
attrs.each { |k,v| send(:"#{k}=", v) }
changed
notify_observers
end
end
O B S E R V E R - C O D E
Slide 36
Slide 36 text
O B S E R V E R
• available in standard
library
• sometimes considered
anti-pattern (coupling)
• publisher-subscriber
preferred
Slide 37
Slide 37 text
T E M P L AT E
M E T H O D
Define the skeleton of an
algorithm in an operation,
deferring some steps to
subclasses. Template
Method lets subclasses
redefine certain steps of
an algorithm without
changing the algorithm's
structure.
Slide 38
Slide 38 text
T E M P L AT E
M E T H O D
• used very commonly
• nobody uses this name
Slide 39
Slide 39 text
A D A P T E R
Convert the interface of
a class into another
interface clients expect.
Adapter lets classes
work together that
couldn't otherwise
because of
incompatible interfaces.
Slide 40
Slide 40 text
A D A P T E R
• used very commonly
• well-known name
Slide 41
Slide 41 text
B R I D G E
Decouple an abstraction
from its implementation
so that the two can vary
independently.
Slide 42
Slide 42 text
B R I D G E
• used commonly
• nobody uses this name
Slide 43
Slide 43 text
FA C A D E
Provide a unified
interface to a set of
interfaces in a
subsystem. Facade
defines a higher-level
interface that makes the
subsystem easier to use.
Slide 44
Slide 44 text
FA C A D E
• used very commonly
• nobody uses this name
Slide 45
Slide 45 text
D E S I G N
PAT T E R N S ?
W H Y D O N ’ T W E L I K E
Slide 46
Slide 46 text
C O N T R O V E R S Y
• solutions to non-existent
problems
• remind of static languages
• overused
Slide 47
Slide 47 text
D E S I G N PAT T E R N S
2 0 Y E A R S L AT E R
• considered harmful
(Singleton, Observer)
• useless in languages with
certain features (Abstract
Factory)
• deprecated (Observer)
• useful in rare cases
(Command, Builder)
Slide 48
Slide 48 text
D E S I G N PAT T E R N S
2 0 Y E A R S L AT E R
• core features (Iterator)
• standard library (Observer,
Singleton)
• commonly used (Adaptor,
Decorator)
• used for communication
purpose (Iterator,
Decorator, Observer)
Slide 49
Slide 49 text
M O R E
PAT T E R N S
W E N E E D
Slide 50
Slide 50 text
( N O T S O ) N E W
PAT T E R N S
• null object
• dependency injection
• extension object
• type object
Slide 51
Slide 51 text
M I S S I N G PAT T E R N S
( P R A C T I C E S ? )
• meta-programming
• DSLs
Slide 52
Slide 52 text
R E S O U R C E S
• R. Olsen “Design Patterns in
Ruby”
• E. Gamma et al. “Design
Patterns: Elements of
Reusable Object-Oriented
Software”
• C. Haynes “Design Patterns
and the Proper Cultivation
Thereof” (talk)
• http://c2.com/cgi/wiki
Slide 53
Slide 53 text
PAT T E R N S , PAT T E R N S
E V E RY W H E R E
@ A R N VA L D , A R R R R C A M P 2 0 1 4