Паттерн «Одиночка»
Часть раздела Объектно-ориентированное программирование путешествия по Ruby на Coddy. Урок 42 из 57.
Шаблон проектирования — это проверенное решение распространённой задачи проектирования. Шаблон одиночка гарантирует, что у класса будет ровно один экземпляр, доступный из любого места. Стандартная библиотека Ruby поддерживает его из коробки: require 'singleton' и include Singleton добавляют метод класса 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)Результат:
dark
trueinclude Singleton также делает new закрытым, поэтому второй экземпляр создать нельзя. Каждая часть программы, которая запрашивает instance, получает один и тот же объект:
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
endВывод:
3
private method `new' called for class CounterТа же идея, написанная вручную, представляет собой метод класса, который создаёт экземпляр при первом использовании, и закрытый new. Это показывает, что модуль делает за вас:
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.levelВывод:
3Используйте одиночки умеренно. Одиночка — это глобальное состояние: любой код может его изменить, и тесты не могут начинаться с чистой копии. Они подходят для вещей, которые действительно существуют в единственном экземпляре на программу, например для логгера или конфигурации; часто понятнее передавать объект в качестве параметра:
# легче тестировать: логгер передаётся
def process(order, log)
log.write("processing #{order.id}")
endЗадание
ЛегкоЗавершите реализацию одиночки AppLogger с помощью include Singleton. Он хранит массив записей и имеет log(message, level), который сохраняет [INFO] message или [ERROR] message (уровень в верхнем регистре), а также entries и error_count. Вспомогательные функции handle_info(message) и handle_error(message) в functions.rb обе записывают данные через AppLogger.instance, поэтому обращаются к одному и тому же объекту.
Предоставленный код считывает строки info,message или error,message, передаёт их через вспомогательные функции, выводит каждую запись и errors: 1, а также проверяет, что создание AppLogger.new запрещено.
Ваш код должен находиться в app_logger.rb и functions.rb. В main.rb содержится предоставленный код ввода/вывода, и его нельзя редактировать.
Попробуйте сами
require_relative 'app_logger'
require_relative 'functions'
# Предоставленный код ввода/вывода: оставьте его как есть
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
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Классы и объекты
Работа с файламиОпределение классовПеременные экземпляраМетоды и selfto_s и inspectПовторение — читательский билет4Инкапсуляция
Приватные методыЗащищённые методыПриватные сеттерыЗащита состоянияПовторение — торговый автомат7Полиморфизм и утиная типизация
ПолиморфизмУтиная типизацияАбстрактные методыcase и классыПовторение — способы оплаты10Шаблоны проектирования, часть 2
Делегирование с помощью ForwardableШаблон декоратораШаблон строителяШаблон состояния2Аксессоры и self
Чтение и записьПользовательские сеттерыself в методахИдентичность и равенствоПовторение — список контактов5Наследование
ПодклассыПереопределение методовВызов superis_a? и предкиПовторение — расчёт зарплаты сотрудников8Специальные методы
Равенство и хешированиеМетоды операторовИндексация и добавлениеПользовательские коллекцииПовторение — дроби11Проект: Управление библиотекой
Книги и читателиВыдача книг3Методы и переменные классов
Методы классовПеременные экземпляра классаКонстантыФабричные методыПовторение — коды купонов6Модули и примеси
Модули и includeРасширение объектовМодуль ComparableМодуль EnumerableПовторение — спортивная лига9Паттерны проектирования. Часть 1
Паттерн «Одиночка»Фабричный паттернПаттерн «Наблюдатель»Паттерн «Стратегия»Потренируйтесь самостоятельно: Онлайн-компилятор Ruby