Menu
Coddy logo textTech

Singleton Deseni

Coddy'nin Ruby Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 42 / 57.

Tasarım kalıbı, yaygın bir tasarım sorununa yönelik kanıtlanmış bir çözümdür. Singleton kalıbı, bir sınıfın tam olarak bir örneğe sahip olmasını ve bu örneğe her yerden erişilebilmesini sağlar. Ruby'nin standart kitaplığında bu özellik yerleşik olarak bulunur: require 'singleton' ve include Singleton, sınıfa bir sınıf yöntemi olan instance ekler:

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)

Çıktı:

dark
true

include Singleton ayrıca new yöntemini gizli yapar; böylece ikinci bir örnek oluşturulamaz. Programın instance isteyen her bölümü aynı nesneyi alır:

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

Çıktı:

3
private method `new' called for class Counter

Aynı fikir elle yazıldığında, ilk kullanımda örneği oluşturan bir sınıf yöntemi ve özel bir new içerir. Bu, modülün sizin için ne yaptığını gösterir:

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

Çıktı:

3

Singleton’ları ölçülü kullanın. Bir singleton global durumdur: herhangi bir kod onu değiştirebilir ve testler temiz bir kopyayla başlayamaz. Logger veya yapılandırma gibi program başına gerçekten yalnızca bir kez var olan şeyler için uygundurlar; bir nesneyi parametre olarak geçirmek genellikle daha anlaşılırdır:

# test etmesi daha kolay: logger içeriye geçirilir
def process(order, log)
  log.write("processing #{order.id}")
end
challenge icon

Görev

Kolay

AppLogger singleton'ını include Singleton ile tamamla. Bir giriş dizisi tutar ve log(message, level) metoduna sahiptir; bu metot [INFO] message veya [ERROR] message (büyük harflerle level), entries ve error_count değerlerini saklar. functions.rb içindeki handle_info(message) ve handle_error(message) yardımcılarının her ikisi de AppLogger.instance üzerinden günlük kaydı tuttuğu için aynı nesneye ulaşırlar.

Sağlanan kod info,message veya error,message satırlarını okur, bunları yardımcılar üzerinden gönderir, her girişi ve errors: 1 ifadesini yazdırır ve AppLogger.new kullanımının reddedildiğini kontrol eder.

Kodun app_logger.rb ve functions.rb dosyalarına yazılmalıdır. main.rb sağlanan girdi/çıktı kodunu içerir ve düzenlenemez.

Kendin dene

require_relative 'app_logger'
require_relative 'functions'

# Sağlanan girdi/çıktı kodu: olduğu gibi bırakın
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 iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler

Kendi başına pratik yap: Online Ruby derleyicisi