Part 2: The big picture of OOP

Photo by Dan DeAlmeida on Unsplash

This is the second in a series of two articles that provide an introduction about what object oriented programming (OOP) is. In the first article, we discussed classes, objects, attributes, behaviors, instance variables, and instance methods.

We also created a Book class and instantiated a few Book objects that will be referenced in this article. You can read the first article here.

The four pillars of OOP

Abstraction

Abstraction is the idea that defining classes and grouping behaviors and attributes within them allows users to work with objects made from those classes without having to get bogged down in implementation details that someone else has already taken the time to understand and approach.

Abstraction allows programmers to work at new levels of a problem. For example — with a Book class written and ready to go, another programmer might begin work on a Library class that interacts with Book objects in some way. The programmer working with the Library class might not know every detail of the Book class, because they don’t need to.

One metaphor that comes to mind for abstraction is the idea of a heart.

Photo by Nicola Fioravanti on Unsplash

This is an abstraction of a heart. A heart does not look like this. But it’s a simple, effective way of communicating about this complex organ that we cannot see.

Encapsulation

Encapsulation is a form of data protection. We can expose only the data and functionalities that we want users to have. In our Book class, we allow read and write access for @pages while we only allow read access for @title and author. We determine what a user can see and do with an object. Additionally, we can even use methods ( Module#public, private, and protected ) within our classes to determine what methods we want to be available to be called on objects outside of the class definition.

Photo by Susan Holt Simpson on Unsplash

Encapsulation is also the idea of grouping data and functionalities together. In the context of our Book class, we group a set of attributes and behaviors that will be available for each object we instantiate from the Book class. There are many levels of encapsulation within OOP. Series of instructions are grouped together in methods. Bundles of data are grouped together in objects. Methods and data are grouped together in classes.

Modules, which are similar to classes with the exception that the ::new method cannot be called on them, are a sort of toolbox. They act as containers , or namespaces, for classes, constants, and methods. Modules can be included in a class to give classes access to additional functionalities.

A purse is kind of like a module.

Inheritance

It’s something that’s so natural for humans to do. For example, I’m looking at a laptop screen right now, so let’s work with that.

Let’s say that my laptop, austins_laptop, is an instance of a Laptop class, which is a type of Computer. You could say that Laptop is a subclass of the Computer class.

In other words, the Laptop class inherits from the Computer class, which might inherit from an Electronics class, which might inherit from a Machine class.

Computers, phones, headphones, and watches are all types of machines.

In Ruby, all classes inherit from classes and modules until they reach the primordial BasicObject. Inheritance signifies the order in which Ruby will search different containers for the methods that you call. If Ruby finds the method, it will stop searching and use it. If it doesn’t it will keep searching until there is nowhere else to look and return a NoMethodError.

For example, if you have an Array object and call not_a_real_method on it, Ruby will first look in Array, then Enumerable, then Object, then Kernel, then BasicObject and then return a NoMethodError. You can always find the order that Ruby will search for methods (known as the method lookup chain or method lookup path) by calling the class method ::ancestors on the class in question.

Ruby is a single inheritance language, which means that a class can only directly inherit from one superclass (while modules can be mixed into classes to provide additional functionality). Ruby allows for class inheritance and interface inheritance. Both Enumerable and Kernel are examples of modules. Enumerable is mixed in to the Array class, while Kernel is mixed in to the Object class.

Let’s take a step back and re-examine our Book class we defined in the first article.

class Book
def initialize(title, author, pages)
@title = title
@author = author
@pages = pages
end
def title
@title
end
def author
@author
end
def pages
@pages
end
def pages=(new_pages)
if new_pages.instance_of?(Integer)
@pages = new_pages
else
puts 'Sorry, please enter a number'
end
end
end

Let’s create a class that inherits from Book.

class Novella < Book; end

We can instantiate a Novella object the same way we instantiate a Book object. Novella inherits all the methods defined in the Book class, including the initialize method.

sad_story = Novella.new('Flowers for Algernon', 'Daniel Keyes', 23)

All the behaviors available for Book objects are now available for the object bound to sad_story, despite the emptiness of Novella. Subclasses can either override or extend the functionalities available in superclasses. Let’s extend the functionalities of our Novella class.

class Novella < Book
def binge_read
puts "I read it all in one night!"
end
end

With binge_read, we now have an available action we can take on Novella objects that we cannot use with Book objects. We have defined more specific behaviors for our subclass. Let’s define one more class and give it some unique functionality before we move on.

class Dictionary < Book 
def learn_new_word
puts ['tenable', 'crepuscular', 'petrichor'].sample
end
end

Then we can create a Dictionary object.

websters = Dictionary.new('1978 Edition', 'Webster Team', 14_542)

We now have two classes, Novella and Dictionary, that inherit from the superclass Book. Both novellas and dictionaries are types of books that have authors, page numbers, and titles. However, in this example, we cannot learn a new word from a Novella object, nor can we binge_read a dictionary object. These specific behaviors are only available for the particular subclasses for which they are relevant.

Inheritance helps programmers re-use their code when needed and extract common, repeated code between classes and move it to a superclass. Rather than re-write the Book getter and setter methods for the Novella and Dictionary classes, we can simply have the two classes inherit from the Book class.

Additionally, inheritance allows programmers to extend or override the behaviors of superclasses within subclasses.

Polymorphism

class Dictionary < Book 
def learn_new_word
puts ['tenable', 'crepuscular', 'petrichor'].sample
end

def binge_read
puts "Zzzzzzzz"
end
end

Our Dictionary#binge_read method has a different implementation than our Novella#binge_read method. We can call binge_read on objects made from both of these classes, and the return values of each call will be different.

[sad_story, websters].each { |book| book.binge_read }

Methods with the same name can be defined in unrelated classes or overridden in a subclass to have a different implementation than a superclass.

The benefits of OOP

Concrete thinking

New levels of abstraction

Reduced Dependencies

Flexible code

DRYer code

Better-organized code

In conclusion

I hope that you have found this useful in some way. If you have any questions about OOP or programming in general, or any feedback or suggestions, please feel free to leave a comment. If you’re a Launch School student, please feel free to reach out to me directly in Slack.

Additionally — a huge thank you to inspiring fellow Launch School student Leena and esteemed Launch School instructor *superchilled for both reading through these articles and providing immensely valuable constructive feedback.

Thank you.

Research analyst turned aspiring web developer. Learning the fundamentals with Launch School. Lives in Denver, CO.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store