O que você NÃO
aprendeu sobre
Orientação a
Objetos
Danilo Sato
@dtsato
Danilo Sato
@dtsato - www.dtsato.com
Desenvolvedor, Arquiteto, Coach, DevOps, Treinador
Como
aprendemos OO?
Orientação a Objetos é:
Herança +
Polimorfismo +
Encapsulamento
Orientação a Objetos é:
Modelar o Mundo Real
“A execução de um programa é considerada um
modelo físico, simulando o comportamento de
uma parte real ou imaginária do mundo."
-- Kristen Nygaard
“Programação orientada a objetos é uma
péssima ideia, que só poderia ter nascido na
Califórnia."
-- Edsger W. Dijkstra
“Programação orientada a objetos é uma
péssima ideia, que só poderia ter nascido na
Califórnia."
-- Edsger W. Dijkstra
“Na Ciência da Computação, arrogância é
medida em nano-Dijkstras"
-- Alan Kay
Inventou o termo “Orientação a
Objetos”
Inventou o termo “Orientação a
Objetos”
Smalltalk
Células
Inventou o termo “Orientação a
Objetos”
Inventou o termo “Orientação a
Objetos”
“OO significa passagem de mensagem,
retenção local, proteção e ocultação do estado
de um processo, e associação tardia de tudo"
Inventou o termo “Orientação a
Objetos”
“OO significa passagem de mensagem,
retenção local, proteção e ocultação do estado
de um processo, e associação tardia de tudo"
“A grande ideia é passagem de mensagem"
Inventou o termo “Orientação a
Objetos”
“OO significa passagem de mensagem,
retenção local, proteção e ocultação do estado
de um processo, e associação tardia de tudo"
“A grande ideia é passagem de mensagem"
“OO é um modelo computacional, não um
paradigma de programação"
“...(Erlang) é a única linguagem orientada a
objetos e talvez eu tenha sido prematuro em
dizer o que era orientação a objetos"
-- Joe Armstrong
Orientação a Objetos:
Programa?
Linguagem?
Paradigma?
Modelo Computacional?
Orientação a Objetos:
Programa?
Linguagem?
Paradigma?
Modelo Computacional?
Ninguém Concorda
Esta palestra
é sobre oo
Esta palestra
Não é sobre oo
Esta palestra
é sobre DESIGNDESIGN
O que é ?DESIGN
DESIGN Código==
DESIGN Código==
Estrutura
Organização
Flexibilidade
Testabilidade
Legibilidade
Coesão
Acoplamento
Dependências
BOM reduz o
custo da mudança
DESIGN
DESIGN
Hipótese da
stamina do DESIGN
Funcionalidades
Tempo
Funcionalidades
Tempo
Sem Design
Funcionalidades
Tempo
Bom Design
Sem Design
Funcionalidades
Tempo
Bom Design
Sem Design
Onde o design
se paga
2004!
Design foi esquecido
Rails
Design foi esquecido
Rails
Model
View
Controller
Helper
Mailer
...
Model
View
Controller
Zero
Design
Design
Ágil
Up-front
Design
DESIGN É BOM
Design “ativo”
DESIGN É BOM
Design “passivo”
DESIGN É BOM
Design ágil == Design evolutivo
DESIGN É BOM
Design ágil == Design evolutivo
TUDO É UM
OBJETO!
TUDO É UM
OBJETO?
TUDO É UM
OBJETO?
class?
TUDO É UM
OBJETO?
if?
class?
TUDO É UM
OBJETO?
while?
if?
class?
Smalltalk
WARNING!
O código que você está prestes a ler foi escrito
com o propósito educacional. Não faça isso em
casa ou coloque código parecido em produção.
class TrueClass
def if_true(is_true, otherwise: -> {})
is_true.call
end
def if_false(is_false, otherwise: -> {})
otherwise.call
end
end
class FalseClass
def if_true(is_true, otherwise: -> {})
otherwise.call
end
def if_false(is_false, otherwise: -> {})
is_false.call
end
end
Condições
2.0.0 > (2 > 1).if_true -> {
2.0.0?> puts "sim"
2.0.0?> }, otherwise: -> {
2.0.0?> puts "não"
2.0.0?> }
sim
=> nil
2.0.0 > (1 > 2).if_true -> {
2.0.0?> puts "sim"
2.0.0?> }, otherwise: -> {
2.0.0?> puts "não"
2.0.0?> }
não
=> nil
Condições
class Proc
def while_true(&blk)
self.call.if_true -> {
blk.call
while_true(&blk)
}
end
end
2.0.0?> i = 0
2.0.0?> -> {i < 3}.while_true do
2.0.0?> puts i
2.0.0?> i += 1
2.0.0?> end
0
1
2
=> nil
Loops
Herança
Herança
“É um”
Ave
Pato Pinguim
+ voa()
+ voa() + voa()
class Bird
def fly
puts "flap, flap, flap"
end
end
class Penguin < Bird
def fly
raise "I don't know how to fly"
end
end
flock = [Bird.new, Bird.new, Bird.new]
flock.each { |bird| bird.fly }
# >> flap, flap, flap
# >> flap, flap, flap
# >> flap, flap, flap
class Bird
def fly
puts "flap, flap, flap"
end
end
class Penguin < Bird
def fly
raise "I don't know how to fly"
end
end
flock = [Penguin.new, Penguin.new,
Penguin.new]
flock.each { |bird| bird.fly }
# ~> -:9:in `fly': I don't know how to fly
(RuntimeError)
# ~> from -:14:in `block in <main>'
# ~> from -:14:in `each'
Princípio de Substituição
de Liskov
Se S é um subtipo de T, então os
objetos do tipo T podem ser
substituídos pelos objetos de tipo
S em qualquer lugar do programa
Isto não é uma ave.Isto não é uma ave.
Herança
“É um”
Herança
“É um”
Herança
Herança
?
Herança
class Book < ActiveRecord::Base
def initialize(attributes = nil, options = {})
super
@my_cache = {}
end
def number_of_pages
@my_cache[:number_of_pages] ||= 10000
end
end
Book.create(
:title => "Lord of the Rings").number_of_pages
# => 10000
Book.find_by(
:title => "Lord of the Rings").number_of_pages
# ~> -:8:in `number_of_pages': undefined method
`[]' for nil:NilClass (NoMethodError)
class Book < ActiveRecord::Base
def after_initialize
@my_cache = {}
end
def number_of_pages
@my_cache[:number_of_pages] ||= 10000
end
end
Book.create(
:title => "Lord of the Rings").number_of_pages
# => 10000
Book.find_by(
:title => "Lord of the Rings").number_of_pages
# => 10000
Herança:
Preciso entender o
que a(s) classe(s)
Pai faz(em)!
class Deck < Array
def initialize
suits = %w(S H C D)
indexes = %w(A 2 3 4 5 6 7 8 9 10 J Q K)
cards = indexes.product(suits)
super(cards)
end
def draw(n)
self.pop(n)
end
end
deck = Deck.new
deck.shuffle!.draw(5) # => [["6", "H"], ["Q",
"H"], ["3", "C"], ["6", "S"], ["K", "C"]]
deck << ["A", "S"] << ["A", "S"]
deck.count { |card| card[0] == "A"} # => 6 aces?
Não use herança
se não usar todo
o comportamento
do(s) pais(s)
Herança é perigoso
Herança é perigoso
Herança é perigoso
Herança é perigoso
Herança é perigoso
Use Herança
quando há
especialização
Prefira
hierarquias
rasas
BigDecimal RationalComplexFloatInteger
Fixnum Bignum
Numeric
Agregação e
composição
Agregação Composição
“Tem um”
Agregação
Agregação
Agregação
composição
composição
composição
class Deck
def initialize
suits = %w(S H C D)
indexes = %w(A 2 3 4 5 6 7 8 9 10 J Q K)
@cards = indexes.product(suits)
end
def count(&blk); @cards.count(&blk) end
def <<(card)
@cards << card unless @cards.include?(card)
self
end
end
deck = Deck.new
deck << ["A", "S"] << ["A", "S"]
deck.count { |card| card[0] == "A"} # => 4
Prefira
composição ao
invés de Herança
Delegação
Delegação
require 'forwardable'
class Deck
extend Forwardable
def_delegator :@cards, :pop, :draw
def_delegators :@cards, :count
def initialize
suits = %w(S H C D)
indexes = %w(A 2 3 4 5 6 7 8 9 10 J Q K)
@cards = indexes.product(suits)
end
def <<(card)
@cards << card unless @cards.include?(card)
self
end
end
deck = Deck.new
deck.draw(5) # => [["Q", "D"], ["K", "S"], ["K",
"H"], ["K", "C"], ["K", "D"]]
polimorfismo
polimorfismo
polimorfismo
1. Herança
1. Herança
2. Duck Typing
1. Herança
2. Duck Typing
3. Mixins
permite separar
abstração da
concretização
permite separar
“O que” do
“Como”
Princípio “Open-Closed”
Entidades de software como
classes, módulos e funções devem
ser abertas para extensão, mas
fechadas para modificação
-- Bertrand Meyer
MITO: Modelar OO é
modelar o mundo real
Actor
Ghost Pacman
center, direction
+ collidesWith(Actor)
+ advance(millis)
+ getNextDirection()
Actor
Ghost
Strategy
Pacman
Strategy
MovementStrategy
+ getNextDirection()
Actor
Random
Strategy
UserControl
Strategy
MovementStrategy
+ getNextDirection()
Actor
Random
Strategy
UserControl
Strategy
MovementStrategy
+ getNextDirection()
TargetChasing
Strategy
+ getTarget()
o design evolui
Conforme o
entendimento do
domínio evolui
[ ] Metallica (10)
[ ] Iron Maiden (5)
[ ] AC/DC (15)
[ ] ...
[ ] Black Album (5)
[ ] Master of
Puppets (5)
[ ] Killers (5)
[ ] ...
[x] Rock (50)
[ ] Clássico (100)
[ ] Jazz (80)
Filtros
Artista
Album
Estilo
class Song < ActiveRecord::Base
searchable do
string :title
string :album { album.title }
string :artist { album.artist.name }
...
end
def self.build_with_filters(p={})
search = Sunspot.new_search(Song)
search.build do
title = with(:title, p[:title]) if p[:title].present?
artist = with(:artist, p[:artist]) if p[:artist].present?
album = with(:album, p[:album]) if p[:album].present?
...
facet :artist, exclude: artist
facet :album, exclude: album
end
search
end
end
class Song < ActiveRecord::Base
...
def self.build_with_filters(p={})
search = Sunspot.new_search(Song)
if p[:artist]
to_reject = p[:artist_album].map do |artist_album|
JSON.parse(artist_album)['album']
end
p[:album].reject! do |element|
to_reject.include?(element)
end
p[:album] = [{}] if p[:album].empty?
end
search.build do
...
end
search
end
end
o domínio
não é música
o domínio
é busca
require 'forwadable'
module Search
class SongDocument
extend Forwardable
def_delegators :@song, :title
def initialize(song)
@song = song
end
def album
@song.album.title
end
def artist
@song.artist.name
end
...
end
end
module Search
class SongDocument
def self.search_filters(p={})
[
Search::OptionalFilter.new(:artist, p),
Search::AlbumFilter.new(:artist, :artist_album, p),
Search::OptionalFilter.new(:title, p)
]
end
def self.build_with_filters(filters, p={})
Sunspot.new_search(Song).tap do |search|
filters.each do |filter|
filter.apply_to(search)
end
Search::Faceter.new(filters, p).apply_to(search)
end
end
end
end
Busca
Música
Document
Filter
Facet
Indexer
Song
Album
Artist
Contextos
Delimitados
Busca
Música
Document
Filter
Facet
Indexer
Song
Album
Artist
Mapa de
Contextos
Busca
Música
“Todos os modelos estão errados,
alguns modelos são úteis"
-- George Box
MITO: Modelar OO é
modelar o mundo real
MITO: Modelar OO é
modelar o mundo real
Resumindo...
OO é passagem
de mensagem
Herança
agregação
Composição
delegação
polimorfismo
DESIGN É BOM
Zero
Design
Design
Ágil
Up-front
Design
Design ágil == Design evolutivo
DESIGN É BOM
Zero
Design
Design
Ágil
Up-front
Design
Design ágil == Design evolutivo
Não modele o
mundo real
modele o
seu domínio
aprenda o
seu domínio
evolua o
seu domínio
se divirta!
Obrigado!
Danilo Sato
@dtsato - www.dtsato.com
Desenvolvedor, Arquiteto, Coach, DevOps, Treinador
Referências
• “Practical Object-Oriented Design in Ruby” Sandi Metz
• “Domain-Driven Design: Tackling Complexity in the Heart of
Software” Eric Evans
• “Analysis Patterns: Reusable Object Models” Martin Fowler
• “Patterns of Enterprise Application Architecture” Martin Fowler
• “Design Patterns: Elements of Reusable Object-Oriented
Software” Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides
• “Growing Object-Oriented Software, Guided by Tests” Steve
Freeman , Nat Pryce
• “Object-Oriented Software Construction” Bertrand Meyer
Livros:

O que você NÃO aprendeu sobre Programação Orientada a Objetos