The Basics of Object Oriented Programming

On the road to becoming a software engineer, the building blocks of programming are detrimental to your success. Understanding the concepts of Object Oriented Programming, or OOP, will help you gain a deeper understanding of the code you read and write. In this blog I will be reviewing the four core concepts of OOP, encapsulation, abstraction, inheritance, and polymorphism. There are many Object Oriented languages, but I will be using the Ruby language in this blog.

What Is Object Oriented Programming?

OOP is a way to organize programs around objects instead of functions allowing for reusable, scalable, and efficient code. Ruby treats every bit of data as an object, even strings, numbers, and classes, allowing us to manipulate data and call methods on classes. We will begin by diving into the concepts of OOP, starting with encapsulation, to give a much clearer understanding on what OOP is and how we use it.

Encapsulation

Let’s say for our example we are looking at an object representing a pet dog. A dog would have qualities like a name, an age, and a breed. We can create a dog class and initialize it with these attributes, as well as define a function in it that will print out these attributes. With encapsulation, we wrap all of this data, the info related to the dog and the function that prints that info, into that one dog instance. Thus, we can only access these functions in relation to objects created using the dog class.

Create a Dog class with a show_dog() method

If we were to run this file with:

ruby encapsulation.rb

We would see the following in our terminal:

My name is Sammy
I am 8 years old
I am a golden retriever

What we have done with encapsulation here is create a reusable class to create as many dog objects as we want that we can edit if we need to add more attributes or methods to our dog. We are also hiding data from the user because we are passing the values, name, age and breed, to our setter method and initializing them with those values. Data cannot be changed or corrupted outside of the Dog class, objects can only call public methods. I have previously written a blog about the initialize method in Ruby that you can read here if you want more insight on its purpose and usage.

Abstraction

This is the process of hiding unnecessary functionality details and representing important details. In software engineering in general, abstraction is a best practice. To put it in plain english, imagine driving to work. You walk out to your car, turn the key, and now your car is started and you can drive to work. Although you may have mechanical knowledge of how the engine works, it is not necessary to drive an automobile. You do not need to know what happens from the key turn to the engine starting to drive a car, as long as the car is running you can drive. This is the concept of abstraction, separating details from usage.

Abstraction using a public and a private method

If we run the code as is, we will run into an error:

16:32 $ ruby abstraction.rb
Traceback (most recent call last):
abstraction.rb:25:in `<main>': private method `get_area' called for #<Rectangle:0x00007fc31484e638 @length=5, @width=5> (NoMethodError)

That is because we are trying to call a private method get_area() directly from our object on line 18. If we comment out or erase line 18, we will get the following in our console when we run our code:

16:33 $ ruby abstraction.rb
My area is length * width
My area is 25

This is because the private method can only be accessed from within the class itself. As you can see, we are calling the private method inside our public method, and therefore we have printed both the area of our rectangle and how we got it.

This concept helps only expose methods and data relevant to other objects. In our example, the method to calculate the area of a rectangle will never change and therefore does not need to be public, we just have to call it in our show_area() function to access the variable.

Inheritance

Many times in programming, objects are similar and share some logic, but are not exactly the same. Using inheritance, we can create a child of a class that comes from a parent, and therefore can inherit some of its methods and logic. Although in Ruby inheritance only supports single class inheritance, it does allow for mixins which allows for multiple inheritances of interface.

So in Ruby, we have a super class, or parent class, and a sub class, or child class that inherit characteristics from the parent class. And all classes on Ruby inherit from BasicObject class.

Let’s look at an example to better illustrate the uses of inheritance.

Dog class has access to all parent methods

If we run this file, we can expect the following output:

17:03 $ ruby inheritance.rb
Child class
Woof Woof
Im snoring

As you can see, the snore() method is available to the Dog class, even though it is defined in its parent class. In this sense we can imagine that all animals sleep, but only dogs bark. With inheritance, we don’t have to redefine the snore method, and we can add additional methods specific to dogs.

With inheritance you can also over ride parent methods by simply re-defining them. If we were to create a method snore() in the Dog class, whenever we call the snore method on a Dog object, it will refer to the method defined in the Dog class rather than the Animal class. This is a form of polymorphism.

Polymorphism

Polymorphism allows us to execute the same method but on different objects using either inheritance or duck-typing. We can use a class exaclty like its parent. Using almost the same code we used in our inheritance example, we can demonstrate one aspect of polymorphism:

Polymorphism using Inheritance

Running the above code, we will get the output:

17:37 $ ruby polymorphism.rb
Im snoring
Sleepy dog here

We have redefined the snore method to print “Sleepy dog here” when called on a Dog object, while it still prints “Im snoring” when called on an Animal object.

The Super Keyword

In addition to rewriting the method and changing its definition, we can also still use the original implementation of the method defined in the parent class. Ruby has a built in keyword super that allows us to access the parent definition of our method.

The super keyword refers to the parent class definition of snore()

Output:

18:15 $ ruby polymorphism2.rb
Im snoring
Sleepy dog here

Comprehension Is Key

I highly recommend not only reviewing these examples, but also trying to write out your own examples of the different methods in Object Oriented Programming. It is necessary to understand OPP if you want to pursue software engineering. Whether you use Ruby, Java, or C# or any other language, OOP is a key concept you need to understand.

GitHub:

References:

I ‘m a Web Developer and a Flatiron coding bootcamp alumni. I currently work in the financial tech industry as a Front End Engineer