In this post, I'll share how to implement the Abstract Class Pattern in Ruby.
Abstract Class on c2.com:
- cannot create instance
- provide interface
Ruby doesn't have the native support of Interface and Abstract Class. But we can still (sort of) implement it.
Suppose our base class is called Family
:
class Family
def initialize(_env)
raise "Subclass must overwrite initialize"
end
end
Set is an idiomatic way to store unique objects. We override the initialize
so cannot create an instance of this base class.
class Family
...
def self.hungry?
raise "You need to include a function for #{self} for hungry?"
end
end
We add a method in the base class (“interface”) that raises when the child class trying to call but not implemented it.
require "set"
class Family
def self.inherited(child_class)
child_classes.add child_class
end
def self.child_classes
@child_classes ||= Set.new
end
...
end
The inherited is called when a subclass is created, let us keep track of child classes.
Here we use class instance variable (@child_classes
) instead of class variable (@@child_classes
):
A class variable (
@@
) is shared among the class and all of its descendants. A class instance variable (@
) is not shared by the class's descendants.
:bulb: Difference between class variables and class instance variables?
And there seems no good use of class variables, so please try to avoid it.
With this, we will be able to find out who is hungry?
:
hungry_kids = Family.child_classes.select(&:hungry?)
Yes! I learned from the codebase of danger/danger:
That's it.
Thanks for reading! :heart: