Menu
CoddyTech

Pola Singleton

Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan Ruby di Coddy. Pelajaran 42 dari 57.

design pattern adalah solusi teruji untuk masalah desain yang umum. Pattern singleton memastikan sebuah class hanya memiliki satu instance, yang dapat diakses dari mana saja. Standard library Ruby sudah menyediakan fitur ini: require 'singleton' dan include Singleton menambahkan class method 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)

Output:

dark
true

include Singleton juga membuat new menjadi private, sehingga tidak ada instance kedua yang dapat dibuat. Setiap bagian program yang meminta instance mendapatkan object yang sama:

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

Output:

3
private method `new' called for class Counter

Gagasan yang sama jika ditulis secara manual adalah method class yang membuat instance saat pertama kali digunakan dan new yang bersifat privat. Ini menunjukkan apa yang dilakukan module untukmu:

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

Output:

3

Gunakan singleton secara terbatas. Singleton adalah state global: kode apa pun dapat mengubahnya, dan pengujian tidak dapat dimulai dari salinan yang bersih. Singleton cocok untuk hal-hal yang memang hanya ada satu dalam setiap program, seperti logger atau konfigurasi; sering kali, meneruskan object sebagai parameter lebih jelas:

# lebih mudah diuji: logger diberikan sebagai argumen
def process(order, log)
  log.write("processing #{order.id}")
end
challenge icon

Tantangan

Mudah

Lengkapi singleton AppLogger dengan include Singleton. Singleton ini menyimpan array berisi entri dan memiliki log(message, level), yang menyimpan [INFO] message atau [ERROR] message (level dalam huruf kapital), entries, dan error_count. Fungsi pembantu handle_info(message) dan handle_error(message) di functions.rb sama-sama mencatat melalui AppLogger.instance, sehingga keduanya menjangkau object yang sama.

Kode yang disediakan membaca baris info,message atau error,message, mengirimkannya melalui fungsi pembantu, mencetak setiap entri dan errors: 1, lalu memeriksa bahwa pemanggilan AppLogger.new ditolak.

Letakkan kodemu di app_logger.rb dan functions.rb. main.rb berisi kode input/output yang disediakan dan tidak boleh diedit.

Coba sendiri

require_relative 'app_logger'
require_relative 'functions'

# Kode input/output yang disediakan: biarkan apa adanya
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
quiz iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Objek

Latihan sendiri: Compiler Ruby online