Padrão Singleton
Parte da seção Programação orientada a objetos do Journey de Ruby da Coddy. Lição 42 de 57.
Um padrão de projeto é uma solução comprovada para um problema comum de projeto. O padrão singleton garante que uma classe tenha exatamente uma instância, acessível de qualquer lugar. A biblioteca padrão do Ruby já o inclui: require 'singleton' e include Singleton adicionam um método de classe instance:
require 'singleton'
class Settings
include Singleton
attr_accessor :theme
def initialize
@theme = "light"
end
end
Settings.instance.theme = "dark"
puts Settings.instance.theme
puts Settings.instance.equal?(Settings.instance)Saída:
dark
trueinclude Singleton também torna new privado, portanto nenhuma segunda instância pode ser criada. Toda parte do programa que solicita instance obtém o mesmo objeto:
require 'singleton'
class Counter
include Singleton
attr_reader :hits
def initialize
@hits = 0
end
def hit
@hits += 1
end
end
def page_a
Counter.instance.hit
end
def page_b
2.times { Counter.instance.hit }
end
page_a
page_b
puts Counter.instance.hits
begin
Counter.new
rescue NoMethodError => e
puts e.message
endSaída:
3
private method `new' called for class CounterA mesma ideia escrita manualmente é um método de classe que cria a instância no primeiro uso e um new privado. Isso mostra o que o módulo faz por você:
class Config
def self.instance
@instance ||= new
end
private_class_method :new
attr_accessor :level
def initialize
@level = 1
end
end
Config.instance.level = 3
puts Config.instance.levelSaída:
3Use singletons com moderação. Um singleton é um estado global: qualquer código pode alterá-lo, e os testes não podem começar com uma cópia limpa. Eles são adequados para coisas que realmente existem uma única vez por programa, como um logger ou a configuração; passar um objeto como parâmetro costuma ser mais claro:
# mais fácil de testar: o logger é passado
def process(order, log)
log.write("processing #{order.id}")
endDesafio
FácilComplete o singleton AppLogger com include Singleton. Ele mantém um array de entradas e possui log(message, level), que armazena [INFO] message ou [ERROR] message (o nível em letras maiúsculas), entries e error_count. Os auxiliares handle_info(message) e handle_error(message) em functions.rb registram ambos por meio de AppLogger.instance, portanto chegam ao mesmo objeto.
O código fornecido lê linhas info,message ou error,message, envia-as pelos auxiliares, imprime cada entrada e errors: 1 e verifica se AppLogger.new é recusado.
Seu código deve estar em app_logger.rb e functions.rb. main.rb contém o código fornecido de entrada/saída e não pode ser editado.
Experimente você mesmo
require_relative 'app_logger'
require_relative 'functions'
# Código de entrada/saída fornecido: mantenha-o como está
input = []
while (line = gets)
input << line.chomp
end
input.each do |line|
level, message = line.split(",", 2)
level == "error" ? handle_error(message) : handle_info(message)
end
AppLogger.instance.entries.each { |e| puts e }
puts "errors: #{AppLogger.instance.error_count}"
begin
AppLogger.new
puts "new is allowed"
rescue NoMethodError
puts "new is private"
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