Search code examples
rubysingletonclass-variables

Singleton classes with inheritance - Ruby ( I think)


I'm trying to use Ruby classes that are never instantiated, but still have the concept of inheritance.So looking at the code below, I have class "Room" that allows access to variables without instantiating the class (I have them as instance variables, but I'm not sure that's correct).

But I want to be able to further constrain the "Room" class into different types of room. And then I want each subclass to have its own variables (@log, @occpants). How would I do this?

If I use class variables, they would be overwritten for each class each time one was changed.

class Room
  @log = []
  @occupants = []

  def self.occupants
    @occupants
  end

  def self.log
    @log
  end

  def self.log_entry(person)
    if @occupants << person
      @log << "#{person.name} entered Office: #{Time.now}"
    end
  end  

  def self.log_exit(person)
    if @occupants.delete(person)
      @log << "#{person.name} exited Office: #{Time.now}"
    end
  end
end

class Office < Room
end

class Kitchen < Room
end

Solution

  • From what I have understood, you are actually trying to create an Abstract class that will hold the implementations of few common attributes and behaviors of different types of Rooms. Yes, I mentioned it as Abstract instead of Singleton because you want to use Room without instantiating it, but in the case of Singleton there will be exactly one instance of Room.

    And by declaring variables inside the class level scope, like this :

    class Room
      @log = []
      @occupants = []
      ...
    end
    

    You are setting up 'class instance variables' rather than 'class variables' (the ones that has the '@@' prefix). Class instance variables are unique to that class, and they will not get inherited when sub-classed.

    But using class variables also will not work in this case, because each room should have its own set of occupants and logs. If you use class variables the parent class and all its sub-classes will have the same common class variables.

    I recommend implementing the common stuffs as instance methods and use instance variables instead.

    class Room
      def initialize
        @log = []
        @occupants = []
      end
    
      def occupants
        @occupants
      end
    
      def log
        @log
      end
    
      def log_entry(person)
        if @occupants << person
          @log << "#{person.name} entered Office: #{Time.now}"
        end
      end  
    
      def log_exit(person)
        if @occupants.delete(person)
          @log << "#{person.name} exited Office: #{Time.now}"
        end
      end
    end
    
    class Office < Room
    end
    
    class Kitchen < Room
    end
    

    EDIT : Btw, you should replace the 'Office' in the entered and exited messages of the logs with #{self.class}.