153
Design Patterns + Ruby

Ruby - Design patterns tdc2011

Embed Size (px)

DESCRIPTION

Apresentação Sobre Design Patterns na trilha de Ruby/Python do TDC 2011 Floripa

Citation preview

Page 1: Ruby - Design patterns tdc2011

Design Patterns + Ruby

Page 3: Ruby - Design patterns tdc2011

Por que Ruby?

Page 4: Ruby - Design patterns tdc2011

1995

Page 5: Ruby - Design patterns tdc2011

Erich Gamma, Richard Helm, Raph Johnson, John Vlissides

Page 6: Ruby - Design patterns tdc2011
Page 7: Ruby - Design patterns tdc2011

“Gang of Four”

Page 8: Ruby - Design patterns tdc2011

Design Patterns

Page 9: Ruby - Design patterns tdc2011

Template Method

Page 10: Ruby - Design patterns tdc2011
Page 11: Ruby - Design patterns tdc2011

class Relatorio def generate output_head output_body output_footer end def output_head end def output_body end def output_footer endend

Page 12: Ruby - Design patterns tdc2011

class Relatorio def generate output_head output_body output_footer end def output_head end def output_body end def output_footer endend

Page 13: Ruby - Design patterns tdc2011

class Relatorio def generate output_head output_body output_footer end def output_head end def output_body end def output_footer endend

Template Method

Page 14: Ruby - Design patterns tdc2011

class HTMLRelatorio < Relatorio def output_head

puts "<html><head><title>Relatório HTML</title></head>"

end def output_body puts "<body>...</body>" end def output_footer puts "</html>" endend

Page 15: Ruby - Design patterns tdc2011

class HTMLRelatorio < Relatorio def output_head

puts "<html><head><title>Relatório HTML</title></head>"

end def output_body puts "<body>...</body>" end def output_footer puts "</html>" endend

Page 16: Ruby - Design patterns tdc2011

class HTMLRelatorio < Relatorio def output_head

puts "<html><head><title>Relatório HTML</title></head>"

end def output_body puts "<body>...</body>" end def output_footer puts "</html>" endend

Page 17: Ruby - Design patterns tdc2011

relatorio = HTMLRelatorio.newrelatorio.generate

Page 18: Ruby - Design patterns tdc2011

relatorio = HTMLRelatorio.newrelatorio.generate

Page 19: Ruby - Design patterns tdc2011

relatorio = HTMLRelatorio.newrelatorio.generate

class Relatorio def generate output_head output_body output_footer end end

Page 20: Ruby - Design patterns tdc2011

relatorio = HTMLRelatorio.newrelatorio.generate

<html> <head><title>...</title></head> <body> ... </body></html>

Page 21: Ruby - Design patterns tdc2011

Strategy

Page 22: Ruby - Design patterns tdc2011

Delegar ao invés de herdar

Page 23: Ruby - Design patterns tdc2011

class Formatter def format(text)

endend

Page 24: Ruby - Design patterns tdc2011

class Formatter def format(text)

raise "Abstract method" endend

Page 25: Ruby - Design patterns tdc2011

class HTMLFormatter < Formatter def format(text)

puts "<html> " puts "<head> " puts "<title>...</title></head> " puts "<body>#{text}</body></html>"

endend

Page 26: Ruby - Design patterns tdc2011

class HTMLFormatter < Formatter def format(text)

puts "<html> " puts "<head> " puts "<title>...</title></head> " puts "<body>#{text}</body></html>"

endend

Page 27: Ruby - Design patterns tdc2011

class HTMLFormatter def format(text)

puts "<html> " puts "<head> " puts "<title>...</title></head> " puts "<body>#{text}</body></html>"

endend

Page 28: Ruby - Design patterns tdc2011

class HTMLFormatter def format(text)

puts "<html> " puts "<head> " puts "<title>...</title></head> " puts "<body>#{text}</body></html>"

endend

Duck Typing

Page 29: Ruby - Design patterns tdc2011

class Relatorio def initialize(formatter)

@formatter = formatter end def generate(text)

@formatter.format(text) endend

Page 30: Ruby - Design patterns tdc2011

class Relatorio def initialize(formatter)

@formatter = formatter end def generate(text)

@formatter.format(text) endend

Page 31: Ruby - Design patterns tdc2011

class Relatorio def initialize(formatter)

@formatter = formatter end def generate(text)

@formatter.format(text) endend

Page 32: Ruby - Design patterns tdc2011

class Relatorio def initialize(formatter)

@formatter = formatter end def generate(text)

@formatter.format(text) endend

Delegate

Page 33: Ruby - Design patterns tdc2011

relatorio = Relatorio.new(HTMLFormatter.new)relatorio.generate("Muitas e muitas coisas")

Page 34: Ruby - Design patterns tdc2011

relatorio = Relatorio.new(HTMLFormatter.new)relatorio.generate("Muitas e muitas coisas")

Page 35: Ruby - Design patterns tdc2011

relatorio = Relatorio.new(HTMLFormatter.new)relatorio.generate("Muitas e muitas coisas")

Page 36: Ruby - Design patterns tdc2011

Observer

Page 37: Ruby - Design patterns tdc2011

Manter-se informado sobre determinadas mudanças em objetos

Page 38: Ruby - Design patterns tdc2011

class NotaFiscal def pagar

... endend

Page 39: Ruby - Design patterns tdc2011

class FluxoCaixa def atualizar

... endend

Page 40: Ruby - Design patterns tdc2011

class FluxoCaixa def atualizar

... endend

Consulta no banco de dados todas as

notas pagas e atualiza o fluxo de

caixa

Page 41: Ruby - Design patterns tdc2011

NotaFiscal FluxoCaixa

pagar

Page 42: Ruby - Design patterns tdc2011

class NotaFiscal def pagar

... endend

Page 43: Ruby - Design patterns tdc2011

class NotaFiscal def pagar (fluxo)

...fluxo.atualizar

endend

Page 44: Ruby - Design patterns tdc2011

class NotaFiscal def initialize (...)

...@observers = []

end def pagar

... endend

Page 45: Ruby - Design patterns tdc2011

class NotaFiscal def add_observer (observer)

@observers << observer end def notify_observers

@observers.each do |o| o.update(self)

end endend

Page 46: Ruby - Design patterns tdc2011

class FluxoCaixa def atualizar

... end def update (nota_fiscal)

... endend

Page 47: Ruby - Design patterns tdc2011

fluxo_caixa = FluxoCaixa.newnota_fiscal = NotaFiscal.newnota_fiscal.add_observer fluxo_caixa

nota_fiscal.pagar

Page 48: Ruby - Design patterns tdc2011

require "observer" class NotaFiscal

include Observable

def pagar...changednotify_observers(self)

endend

Page 49: Ruby - Design patterns tdc2011

require "observer" class NotaFiscal

include Observable

def pagar...changednotify_observers(self)

endend

Page 50: Ruby - Design patterns tdc2011

require "observer" class NotaFiscal

include Observable

def pagar...changednotify_observers(self)

endend

Page 51: Ruby - Design patterns tdc2011

require "observer" class NotaFiscal

include Observable

def pagar...changednotify_observers(self)

endend

Page 52: Ruby - Design patterns tdc2011

require "observer" class NotaFiscal

include Observable

def pagar...changednotify_observers(self)

endend

@changed = true

Page 53: Ruby - Design patterns tdc2011

require "observer" class NotaFiscal

include Observable

def pagar...changednotify_observers(self)

endend

@observers.each { |o| o.update(object) } if @changed

Page 54: Ruby - Design patterns tdc2011

class FluxoCaixa def atualizar

... end def update (nota_fiscal)

... endend

Page 55: Ruby - Design patterns tdc2011

fluxo_caixa = FluxoCaixa.newnota_fiscal = NotaFiscal.newnota_fiscal.add_observer fluxo_caixa

nota_fiscal.pagar

Page 56: Ruby - Design patterns tdc2011

fluxo_caixa = FluxoCaixa.newnota_fiscal = NotaFiscal.newnota_fiscal.add_observer fluxo_caixa

nota_fiscal.pagar

nota_fiscal fluxo_caixa

notifica

Page 57: Ruby - Design patterns tdc2011

Factory

Page 58: Ruby - Design patterns tdc2011

Fornecer uma interface para a criação de objetos, sem especificar a classe concreta

Page 59: Ruby - Design patterns tdc2011

HTMLReader.new

Page 60: Ruby - Design patterns tdc2011

PDFReader.new

Page 61: Ruby - Design patterns tdc2011

class ReaderFactory def initialize (format)

@reader_class = self.class.const_get("#{format}Reader")

end def reader

@reader_class.new endend

Page 62: Ruby - Design patterns tdc2011

class ReaderFactory def initialize (format)

@reader_class = self.class.const_get("#{format}Reader")

end def reader

@reader_class.new endend

Page 63: Ruby - Design patterns tdc2011

class ReaderFactory def initialize (format)

@reader_class = self.class.const_get("#{format}Reader")

end def reader

@reader_class.new endend

Page 64: Ruby - Design patterns tdc2011

class ReaderFactory def initialize (format)

@reader_class = self.class.const_get("#{format}Reader")

end def reader

@reader_class.new endend

Page 65: Ruby - Design patterns tdc2011

html_reader = ReaderFactory.new("HTML").reader

Page 66: Ruby - Design patterns tdc2011

pdf_reader = ReaderFactory.new("PDF").reader

Page 67: Ruby - Design patterns tdc2011

class ReaderFactory def self.pdf_reader

ReaderFactory.new("PDF").reader end def self.html_reader

ReaderFactory.new("HTML").reader endend

Page 68: Ruby - Design patterns tdc2011

html_reader = ReaderFactory.html_reader

Page 69: Ruby - Design patterns tdc2011

Active Record Factory

Page 70: Ruby - Design patterns tdc2011

class Base ...

end

Page 71: Ruby - Design patterns tdc2011

class Base def self.mysql_connection

... endend

Page 72: Ruby - Design patterns tdc2011

class Base def self.postgresql_connection

... endend

Page 73: Ruby - Design patterns tdc2011

adapter = "mysql"method_name = "#{adapter}_connection"Base.send(method_name, config)

Page 74: Ruby - Design patterns tdc2011

Builder

Page 75: Ruby - Design patterns tdc2011

Criar objetos complexos de forma legível, passo a passo

Page 76: Ruby - Design patterns tdc2011

class Pizza attr_accessor :massa, :molho, :coberturaend

Page 77: Ruby - Design patterns tdc2011

class PizzaBuilder attr_reader :pizza def initialize

@pizza = Pizza.new endend

Page 78: Ruby - Design patterns tdc2011

class CalabresaBuilder < PizzaBuilder def molho

@pizza.molho = "Tomate" end def massa

@pizza.massa = "Pão" end def cobertura

@pizza.cobertura = "queijo, calabresa" endend

Page 79: Ruby - Design patterns tdc2011

builder = CalabresaBuilder.newbuilder.molhobuilder.coberturabuilder.massapizza = builder.pizza

Page 80: Ruby - Design patterns tdc2011

pizza = CalabresaBuilder.new.molho.cobertura.massa.pizza

Page 81: Ruby - Design patterns tdc2011

class CalabresaBuilder < PizzaBuilder def molho

@pizza.molho = "Tomate"self

end def massa

@pizza.massa = "Pão"self

end def cobertura

@pizza.cobertura = "queijo, calabresa"self

endend

Page 82: Ruby - Design patterns tdc2011

builder = CalabresaBuilder.newbuilder.molho_and_coberturapizza = builder.pizza

Page 83: Ruby - Design patterns tdc2011

class PizzaBuilder def method_missing(name, *args)

methods = name.to_s.split("_")return super(name, *args) unless methods[1] == "and"

methods.each do |method|next if method == "and"send(method)

end

endend

Page 84: Ruby - Design patterns tdc2011

builder.molho_and_cobertura

Page 85: Ruby - Design patterns tdc2011

builder.massa_and_cobertura

Page 86: Ruby - Design patterns tdc2011

builder.molho_and_cobertura_and_massa

Page 87: Ruby - Design patterns tdc2011

Adapter

Page 88: Ruby - Design patterns tdc2011

Conectar objetos que não tem uma interface comum

Page 89: Ruby - Design patterns tdc2011
Page 90: Ruby - Design patterns tdc2011

class Padrao1 def conectar (cabo)

cabo.energizar endend

Page 91: Ruby - Design patterns tdc2011

class Padrao1 def conectar (cabo)

cabo.energizar endend

Page 92: Ruby - Design patterns tdc2011

class CaboPadrao1 def energizar

... endend

Page 93: Ruby - Design patterns tdc2011

class Padrao2 def conectar (cabo)

cabo.executar endend

Page 94: Ruby - Design patterns tdc2011

class Padrao2 def conectar (cabo)

cabo.executar endend

Page 95: Ruby - Design patterns tdc2011

class CaboPadrao2 def executar

... endend

Page 96: Ruby - Design patterns tdc2011

class CaboPadrao2 def executar

... endend

Page 97: Ruby - Design patterns tdc2011

class CaboPadrao2 def executar

... endend

tomada = Padrao2.newtomada.conectar CaboPadrao2.new

Page 98: Ruby - Design patterns tdc2011

class CaboPadrao2 def executar

... endend

tomada = Padrao1.newtomada.conectar CaboPadrao2.new

Page 99: Ruby - Design patterns tdc2011

class CaboPadrao2 def executar

... endend

tomada = Padrao1.newtomada.conectar CaboPadrao2.new

Page 100: Ruby - Design patterns tdc2011
Page 101: Ruby - Design patterns tdc2011

class AdapterPadrao2 def initialize(cabo_padrao2)

@cabo = cabo_padrao2 end def energizar

@cabo.executar endend

Page 102: Ruby - Design patterns tdc2011

class AdapterPadrao2 def initialize(cabo_padrao2)

@cabo = cabo_padrao2 end def energizar

@cabo.executar endend

Page 103: Ruby - Design patterns tdc2011

class AdapterPadrao2 def initialize(cabo_padrao2)

@cabo = cabo_padrao2 end def energizar

@cabo.executar endend

Page 104: Ruby - Design patterns tdc2011

adapter = AdapterPadrao2.new(CaboPadrao2.new)tomada = Padrao1.newtomada.conectar(adapter)

Page 105: Ruby - Design patterns tdc2011

adapter = AdapterPadrao2.new(CaboPadrao2.new)tomada = Padrao1.newtomada.conectar(adapter)

Page 106: Ruby - Design patterns tdc2011

adapter = AdapterPadrao2.new(CaboPadrao2.new)tomada = Padrao1.newtomada.conectar(adapter)

tomada adapter cabo

Page 107: Ruby - Design patterns tdc2011

Proxy

Page 108: Ruby - Design patterns tdc2011
Page 109: Ruby - Design patterns tdc2011

class ContaBancaria def initialize(saldo)

@saldo = saldo end def depositar!(valor)

@saldo += valor end def sacar!(valor)

@saldo -= valor end def some_method endend

Page 110: Ruby - Design patterns tdc2011

class ContaBancariaProxy def initialize(conta_bancaria)

@conta_bancaria = conta_bancaria end def depositar!(valor)

@conta_bancaria.depositar! valor end def sacar!(valor)

@conta_bancaria .sacar! valor endend

Page 111: Ruby - Design patterns tdc2011

Protection Proxy

Page 112: Ruby - Design patterns tdc2011

class ContaBancariaProxy def initialize(conta_bancaria)

@conta_bancaria = conta_bancaria end def depositar!(valor)

@conta_bancaria.depositar! valor end def sacar!(valor)

@conta_bancaria .sacar! valor endend

Page 113: Ruby - Design patterns tdc2011

class ContaBancariaProxy def initialize(conta_bancaria, owner)

@conta_bancaria = conta_bancaria@owner = owner

end protected def check_access

raise "Illegal Access" unless User. login == @owner

endend

Page 114: Ruby - Design patterns tdc2011

class ContaBancariaProxy def depositar!(valor) check_access

@conta_bancaria.depositar! valor end def sacar!(valor) check_access

@conta_bancaria .sacar! valor endend

Page 115: Ruby - Design patterns tdc2011

Decorator

Page 116: Ruby - Design patterns tdc2011
Page 117: Ruby - Design patterns tdc2011

class Coffee def price

@price end def ingredients

@ingredients endend

Page 118: Ruby - Design patterns tdc2011

class MilkDecorator def initialize (coffee)

@coffee = coffee end def price

coffee.price + 0.5 end def ingredients

coffee.ingredients + ", Leite" endend

Page 119: Ruby - Design patterns tdc2011

class MilkDecorator def initialize (coffee)

@coffee = coffee end def price

coffee.price + 0.5 end def ingredients

coffee.ingredients + ", Leite" endend

Page 120: Ruby - Design patterns tdc2011

class MilkDecorator def initialize (coffee)

@coffee = coffee end def price

coffee.price + 0.5 end def ingredients

coffee.ingredients + ", Leite" endend

Page 121: Ruby - Design patterns tdc2011

class MilkDecorator def initialize (coffee)

@coffee = coffee end def price

coffee.price + 0.5 end def ingredients

coffee.ingredients + ", Leite" endend

Page 122: Ruby - Design patterns tdc2011

coffee = Coffee.new(1.5, "Café, Água")puts coffee.ingredients

Page 123: Ruby - Design patterns tdc2011

coffee = Coffee.new(1.5, "Café, Água")puts coffee.ingredients Café, Água

Page 124: Ruby - Design patterns tdc2011

coffee = Coffee.new(1.5, "Café, Água")coffee = MilkDecorator.new coffeeputs coffee.ingredientsputs coffee.price

Page 125: Ruby - Design patterns tdc2011

coffee = Coffee.new(1.5, "Café, Água")coffee = MilkDecorator.new coffeeputs coffee.ingredientsputs coffee.price

Café, Água, Leite

Page 126: Ruby - Design patterns tdc2011

coffee = Coffee.new(1.5, "Café, Água")coffee = MilkDecorator.new coffeeputs coffee.ingredientsputs coffee.price 2.0

Page 127: Ruby - Design patterns tdc2011

class ChocolateDecorator def initialize (coffee)

@coffee = coffee end def price

coffee.price + 1.0 end def ingredients

coffee.ingredients + ", Chocolate" endend

Page 128: Ruby - Design patterns tdc2011

coffee = Coffee.new(1.5, "Café, Água")coffee = ChocolateDecorator.new coffeeputs coffee.ingredients

Page 129: Ruby - Design patterns tdc2011

coffee = Coffee.new(1.5, "Café, Água")coffee = ChocolateDecorator.new coffeeputs coffee.ingredients

Café, Água, Chocolate

Page 130: Ruby - Design patterns tdc2011

coffee = Coffee.new(1.5, "Café, Água")coffee = ChocolateDecorator.new coffeeputs coffee.ingredients

Page 131: Ruby - Design patterns tdc2011

coffee = Coffee.new(1.5, "Café, Água")coffee = ChocolateDecorator.new coffee

Page 132: Ruby - Design patterns tdc2011

coffee = Coffee.new(1.5, "Café, Água")coffee = ChocolateDecorator.new coffeecoffee = MilkDecorator.new coffee

Page 133: Ruby - Design patterns tdc2011

coffee = Coffee.new(1.5, "Café, Água")coffee = ChocolateDecorator.new coffeecoffee = MilkDecorator.new coffeeputs coffee.ingredients

Café, Água, Chocolate, Leite

Page 134: Ruby - Design patterns tdc2011

Singleton

Page 135: Ruby - Design patterns tdc2011

Garantir que só haja uma instancia de determinado objeto

Page 136: Ruby - Design patterns tdc2011

@count

Page 137: Ruby - Design patterns tdc2011

@count@@count

Page 138: Ruby - Design patterns tdc2011

class CountTester @@count = 0 def initialize

@count = 0 end def self.increment

@@count++ end def increment

@count++ endend

Page 139: Ruby - Design patterns tdc2011

class CountTester @@count = 0 def initialize

@count = 0 end def self.increment

@@count++ end def increment

@count++ endend

Variável Global

Page 140: Ruby - Design patterns tdc2011

class CountTester @@count = 0 def initialize

@count = 0 end def self.increment

@@count++ end def increment

@count++ endend

Variável Local

Page 141: Ruby - Design patterns tdc2011

class CountTester @@count = 0 def initialize

@count = 0 end def self.increment

@@count++ end def increment

@count++ endend

Metódo Estático

Page 142: Ruby - Design patterns tdc2011

class CountTester @@count = 0 def initialize

@count = 0 end def self.increment

@@count++ end def increment

@count++ endend

Metódo de Instância

Page 143: Ruby - Design patterns tdc2011

class CountTester COUNT = 0end

Variável Global

Page 144: Ruby - Design patterns tdc2011

class Logger @@instance = Logger.new

def self.instance@@instance

endend

Page 145: Ruby - Design patterns tdc2011

logger1 = Logger.instancelogger2 = Logger.instance

Page 146: Ruby - Design patterns tdc2011

logger = Logger.new

Page 147: Ruby - Design patterns tdc2011

class Logger @@instance = Logger.new

def self.instance@@instance

end

end

Page 148: Ruby - Design patterns tdc2011

class Logger @@instance = Logger.new

def self.instance@@instance

end

private_class_method :newend

Page 149: Ruby - Design patterns tdc2011

require "singleton"class Logger

include Singletonend

Page 150: Ruby - Design patterns tdc2011

logger = Logger.new

Page 151: Ruby - Design patterns tdc2011

logger = Logger.new

private method ‘new’ called for Logger::Class

Page 152: Ruby - Design patterns tdc2011

logger = Logger.instance