Understanding Abstraction in OOP

Hello, fellow coder! Today, we'll decode Ruby's Abstraction principle, a powerful tool in Object-Oriented Programming. Abstraction is our superhero against the seemingly overwhelming complexity, revealing only the necessary details. Are you ready for the fun?

Imagine Abstraction as a superboat, stripping away the complexities and giving you just the essentials to operate effectively. It’s not about understanding all the intricate details; it is about focusing on what truly matters. Consider it this way — to drive a car, you only engage with its external controls while the complex workings beneath remain hidden.

Abstraction in Ruby

In Ruby, objects are defined through classes. Every class serves as a preliminary blueprint for an object. It stipulates both the data (attributes) and their potential behaviors (methods). Similar to a car’s control panel, an object's class provides a user-friendly interface, concealing the complex mechanics within.

For example, when utilizing a Ruby array, you employ methods like push, delete, and sort. You do so without needing to comprehend how Ruby manages the array's memory space. The internal workings are abstracted.

Ruby's Approach to Abstraction

While Ruby does not have built-in abstract classes like some other languages, abstraction can be achieved using modules or by raising exceptions in methods that should be overridden in subclasses.

Consider this simple example:

class AbstractExample
  def do_something
    raise NotImplementedError, "This method must be overridden in a subclass"
  end
end

frame = AbstractExample.new
frame.do_something

As you can see, you cannot call an unimplemented method in a class meant to be abstract, as it's just a skeleton for the future class that will be derived from it. The NotImplementedError is raised to ensure that subclasses provide specific implementations.

Real-world Example of Abstraction in Ruby

For instance, when crafting a doodling app that handles shapes, you would define a class called Shape. It would have area and perimeter methods that raise NotImplementedError, indicating they need to be implemented in subclasses:

class Shape
  def area
    raise NotImplementedError, "Subclass must define area"
  end

  def perimeter
    raise NotImplementedError, "Subclass must define perimeter"
  end
end

class Rectangle < Shape
  def initialize(width, height)
    @width = width
    @height = height
  end

  def area
    @width * @height
  end

  def perimeter
    2 * (@width + @height)
  end
end

class Circle < Shape
  def initialize(radius)
    @radius = radius
  end

  def area
    3.14 * (@radius**2)
  end

  def perimeter
    2 * 3.14 * @radius
  end
end

rectangle = Rectangle.new(2, 3) # A rectangle with sides 2 and 3
circle = Circle.new(5)         # A circle with a radius of 5

puts rectangle.area
puts rectangle.perimeter

puts circle.area
puts circle.perimeter
# Prints: 
# 6
# 10
# 78.5
# 31.4

Shape classes provide an abstraction layer, reducing the knowledge you require to calculate the area and perimeter.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal