Padrão Strategy
Parte da seção Programação orientada a objetos do Journey de Ruby da Coddy. Lição 45 de 57.
O padrão de estratégia coloca uma parte de um algoritmo em seu próprio objeto e permite que o objeto principal delegue a ele. Trocar a estratégia altera o comportamento sem alterar a classe principal:
class Standard
def cost(kg)
5 + kg * 1.5
end
end
class Express
def cost(kg)
15 + kg * 3
end
end
class Shipment
attr_writer :strategy
def initialize(kg, strategy)
@kg = kg
@strategy = strategy
end
def cost
@strategy.cost(@kg)
end
end
s = Shipment.new(2, Standard.new)
puts s.cost
s.strategy = Express.new
puts s.costSaída:
8.0
21As estratégias compartilham apenas um nome de método, portanto qualquer objeto com cost funciona: duck typing novamente. Adicionar uma nova forma de envio significa adicionar uma classe, não outro ramo dentro de Shipment:
class Pickup
def cost(_kg)
0
end
end
shipment.strategy = Pickup.new # Shipment permanece inalteradoEm Ruby, uma estratégia geralmente é uma lambda. Qualquer coisa que responda a call pode ser armazenada e invocada, seja uma lambda, um objeto de método ou um objeto da sua própria classe:
class TextFormatter
def initialize(strategy)
@strategy = strategy
end
def format_all(words)
words.map { |w| @strategy.call(w) }.join(" ")
end
end
class Censor
def call(word)
word.size > 3 ? "*" * word.size : word
end
end
words = %w[ruby is great]
puts TextFormatter.new(->(w) { w.upcase }).format_all(words)
puts TextFormatter.new(:capitalize.to_proc).format_all(words)
puts TextFormatter.new(Censor.new).format_all(words)Saída:
RUBY IS GREAT
Ruby Is Great
**** is *****Escolha a estratégia em vez de subclasses quando um objeto precisar mudar seu comportamento enquanto o programa estiver em execução, ou quando a variação for uma única etapa. Uma subclasse fixa o comportamento durante toda a vida do objeto:
# subclassing: fixo na criação
ExpressShipment.new(2)
# strategy: pode mudar depois
shipment = Shipment.new(2, Standard.new)
shipment.strategy = Express.newDesafio
FácilComplete as estratégias de envio e ShippingCalculator. Standard#cost(kg) é 5 mais 1.50 por kg, Express#cost(kg) é 15 mais 3 por kg, e Pickup#cost(kg) é 0. O calculador é criado com uma estratégia, pode alterá-la com strategy=, e quote(kg) retorna 2.5 kg by Express: 22.50, usando o nome da classe da estratégia.
O código fornecido começa com Standard e lê os comandos use express, use pickup, use standard ou quote 2.5, imprimindo cada cotação.
Seu código deve ficar em standard.rb, express.rb, pickup.rb e shipping_calculator.rb. main.rb contém o código fornecido de entrada/saída e não pode ser editado.
Experimente você mesmo
require_relative 'standard'
require_relative 'express'
require_relative 'pickup'
require_relative 'shipping_calculator'
# Código de entrada/saída fornecido: mantenha-o como está
input = []
while (line = gets)
input << line.chomp
end
strategies = { "standard" => Standard, "express" => Express, "pickup" => Pickup }
calc = ShippingCalculator.new(Standard.new)
input.each do |line|
cmd, arg = line.split
if cmd == "use"
calc.strategy = strategies[arg].new
else
puts calc.quote(arg.to_f)
end
end
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação orientada a objetos
1Classes e Objetos
Trabalhando com ArquivosDefinindo ClassesVariáveis de InstânciaMétodos e selfto_s e inspectRevisão - Cartão da Biblioteca4Encapsulamento
Métodos privadosMétodos protegidosSetters privadosProtegendo o estadoRevisão - Máquina de venda automática7Polimorfismo e Duck Typing
PolimorfismoDuck TypingMétodos Abstratoscase e ClassesRevisão - Métodos de Pagamento2Acessores e self
Leitores e GravadoresSetters Personalizadosself nos MétodosIdentidade e IgualdadeRecapitulação - Lista de Contatos5Herança
SubclassesSobrescrita de métodosChamando superis_a? e ancestraisRevisão - Folha de pagamento da equipe8Métodos Especiais
Igualdade e hashMétodos de OperadoresIndexação e AdiçãoColeções PersonalizadasRevisão - Frações11Projeto: Gerenciamento de Biblioteca
Livros e MembrosEmpréstimo de LivrosPratique por conta própria: Compilador de Ruby online