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?
“ 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
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.
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)
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
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.
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
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.
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
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
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
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
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
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
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
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.
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
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
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.
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.
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.
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)
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)
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