Lesson 2
Understanding Abstraction in OOP with Ruby
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:

Ruby
1class AbstractExample 2 def do_something 3 raise NotImplementedError, "This method must be overridden in a subclass" 4 end 5end 6 7frame = AbstractExample.new 8frame.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:

Ruby
1class Shape 2 def area 3 raise NotImplementedError, "Subclass must define area" 4 end 5 6 def perimeter 7 raise NotImplementedError, "Subclass must define perimeter" 8 end 9end 10 11class Rectangle < Shape 12 def initialize(width, height) 13 @width = width 14 @height = height 15 end 16 17 def area 18 @width * @height 19 end 20 21 def perimeter 22 2 * (@width + @height) 23 end 24end 25 26class Circle < Shape 27 def initialize(radius) 28 @radius = radius 29 end 30 31 def area 32 3.14 * (@radius**2) 33 end 34 35 def perimeter 36 2 * 3.14 * @radius 37 end 38end 39 40rectangle = Rectangle.new(2, 3) # A rectangle with sides 2 and 3 41circle = Circle.new(5) # A circle with a radius of 5 42 43puts rectangle.area 44puts rectangle.perimeter 45 46puts circle.area 47puts circle.perimeter 48# Prints: 49# 6 50# 10 51# 78.5 52# 31.4

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

Lesson Summary and Practice

Kudos! We've examined the principle of Abstraction in Ruby, revealing the hidden beauty of intricate software systems. However, hands-on practice is key to solidifying your understanding. So, prepare for the upcoming hands-on exercises and explore the power of code abstraction! Let's code!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.