Private Klassen in Ruby

Konstanten können explizit private gesetzt werden (Private Konstanten in Ruby). Das Gleiche gilt auch für Klassen.

Warum privat?

Machmal macht es Sinn, auch Klassen auf private zu setzen. Zum Beispiel, wenn bestimmte Logik in eine Klasse extrahiert werden soll, um sie explizit zu kapseln. Es ist nicht immer erforderlich, dass diese Klasse public ist.
Als Beispiel soll hier eine Klasse Product gelten. Jedes Produkt ist gekennzeichnet durch seine spezifische Seriennummer.
Da die Logik für die Erstellung der Seriennummer nicht in der Verantwortung der Product Klasse liegt, macht es Sinn, sie in einer eigenen Klasse Serial zu kapseln. Erst Recht, wenn weiteres Verhalten an der Seriennummer hängt:

class Product
  class Serial
    def initialize
      @date = Date.today
    end

    def code
      "#{@date}/#{object_id}"
    end
  end

  attr_reader :serial

  def initialize
    @serial = Serial.new
  end

  def code
    serial.code
  end
end

Ein neues Produkt mit Seriennummer:

Product.new.code # => "2016-06-19/32713960"

Allerdings ist die Klasse Serial unnötigerweise von außen zugreifbar:

Product::Serial.new # => #<Product::Serial:0x00000002be1548 ... >

Es gilt immer: so wenig wie möglich, soviel wie nötig public.

Darum privat!

class Product
  class Serial
    def initialize
      @date = Date.today
    end

    def code
      "#{@date}/#{object_id}"
    end
  end

  # explizit privat:
  private_constant :Serial

  attr_reader :serial

  def initialize
    @serial = Serial.new
  end

  def code
    serial.code
  end
end

Mit Module#private_constant wurde Serial auf private gesetzt. Deshalb kann sie nun nicht mehr direkt instantiiert werden:

Product::Serial.new
# => NameError: private constant Product::Serial referenced