Leon Chaewon Kong's dev blog

Object Oriented Programming 1 - Basic Concepts


Table Of Contents

  1. Procedural Programming
  2. Object-oriented Programming
    2.1 Modeling Objects
    2.2 Inheritance


OOP is like a huge flame that striked programmer society. Nowadays computer engineer that couldn’t show the concepts and benefits of OOP is considered as disqualified. Then, what OOP exactly means and what benefits OOP offer? This basics of OOP is the main topic of today.

1. Procedural Programming

A long time ago in a galaxy far, far away, there was the computer. Since computer has been invented, making softwares to run the huge, ugly thing was our matter - software engineers’ matter.

Before Procedural Programming concept, codes were written line by line, conducted line by line. As simple as that. Yet, the softwares getting complicated as well as logics and codes beneath it. On certain point, people realized that this won’t work. So, they devise new paradigm in order to inhance efficiency and readability of codes. The Birth of procedures.

Procedures, a.k.a sub-routines, methods, or functions, are the key element of procedural programming. Unlike codes line by line, functions are used in procedural programming in order to improve modularity and maintenance.

Functions are effective. One same function can be executed as many times as needed, without writing whole function again.

Just look:

# get sum of given array without function/method
a = [1, 2, 3, 4]
result = 0

for el in a:
  result += el


# Another sum of array
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = 0

for el in b:
  result += el

Calculating sum of whole array is quite common process dealing with data. Without using function(or PROCEDURE), developers would have to repeat the whole code again and again whit tiny little modification.

In procedural programming, however, developers could just improvise a function and use it instead of repeating the whole codes again and again.

def sum_arr(array):
  result = 0

  for el in range(array):
    result += el

  return result


a = [1, 2, 3, 4, 5]
b = [1, 6, 2, 4]

sum_arr(a) # 15
sum_arr(b) # 13

This is how procedural programming works. Making functions, making modules. You can make specific functions and modules and call them as many times you want. Even you can make it independent file and import it.

# Import module outside of the file
import random

# generates random float number between 0 and 1
random.random()

One Last Thing: Procedural programming paradigm separates implementation from interface. One who need to use the sumArr() function doesn’t have to know about codes inside the function. One only need to know the interface: sumArr() function gets array as a parameter and returns sum results of the array. Only input and output matters. One doesn’t have to know details or how the function works internally.

This makes much easier when doing co-ops with other programmers. Sometimes reading codes that generated by other programmer line by line could be pain in the ass. In procedural programming, you don’t have to, only if you understand the interface.

2. Object-oriented Programming

2.1 Modeling Objects

Object-oriented paradigm starts from the question ‘how objects in real worlds could be modeled?’ whereas procedural paradigm has been spawned from ‘what does this program do exactly?’.

Think about you have to describe a car. You can ride it, you can drive it, you can fuel it, it moves, it has many wheels. If you have to store data and methods related to cars, you might want to gather them and make them as a group, because group of things are much easier to manipulate and manage.

Then, what’s for? Do we really have to make a group of data and methods for cars in practical programming world? Maybe not. But, consider this: membership in a website, like Facebook. Members in Facebook can write and read articles. They have related informations email, age, college, friends and so on. Facebook also need to remember what posts you liked and what posts your friends liked.

Too much informations and too much functions. In modern computer science, data is all that matters. Usually data is the culprit that makes modern application complicated. Procedural programming is not enough. That does not enhance data flow or managing data.

Thus, let there be light, or, let there be OOP. With OOP, you can make groups with functions and data that are related. If you are a member of Facebook, you have name, age and school you graduate from. You have a huge list of friends. You can follow or unfollow person. Now you can make these functions and data into class and instance. (Let’s not think about what class and instance means; just look into it. Feel it.)

class Member:
  
  # Constructor: initializes instance properties.
  def __init__(self, name, age, school, friends):
    self.name = name
    self.age = age
    self.school = school
    self.friends = friends
  
  # Method that makes friend
  def friend(self, member):
    self.friends.append(member)
  
  # Method that deletes friend
  def unfriend(self, friend):
    self.friends.remove(friend)
  
  # Method that shows friends
  def show_friends(self):
    print("Friends of {}: {}".format(self.name, ", ".join(self.friends)))


if __name__ == "__main__": # Execution block.

  # Create instance called harry with Member class
  harry = Member("Harry", 28, "Hogwart", ["Hermione", "Ron", "Jinny"])

  # Let's see who are the friends of harry's
  harry.show_friends() # Friends of Harry: Hermione, Ron, Jinny

  # Add Hagrid as a friends (Follow Hagrid)
  harry.follow("Hagrid")
  harry.show_friends() # Friends of Harry: Hermione, Ron, Jinny, Hagrid

Like functions can be repeatedly used, class can. Class is a movable-type printing press and instance is the Bible printed from it. With printing press, you can print as many Bibles you want. You can print with green color, blue color, red color and any other colors that you want.

In the previous example, you can also make draco or albus or voldemort as an instance. With the printing press called ‘Member’, you can create as many instances or books as you want.

The important thing is: each instance may have slightly different data. Draco may have different friends than Harry. Voldemort may be older than Harry. Some members are not graduated from Hogwart. Yet, they share the same structure of data and functions. They have their own name, age, school, and friends. They have methods(functions inside class) like follow(), unfollow(), show_friends().

2.2 Inheritance

If class B inherits class A, B is a sub-kind of A. Consider Vehicle class and Car class. Car is a kind of vehicles. If there should be other classes like Train and Ship, maybe it would be better to define super class (or parent class) that shares common properties (i.e. max_passenger, max_speed) and methods (i.e. give_ride, drive).

class Vehicle:
    def __init__(self, passingers=[]):
        self.passingers = passingers
    
    def give_ride(self, list):
        self.passingers.extend(list)


class Car(Vehicle):
    def __init__(self, passingers, driver, gear):
        super().__init__(passingers)
        self.driver = driver
        self.gear = gear

    def change_gear(self, newGear):
        self.gear = newGear
        print("Gear Changed: {}".format(self.gear))

    def __str__(self):
         return "driver: {} passingers: {} gear: {}"\
             .format(self.driver, self.passingers, self.gear)
    

class Airplane(Vehicle):
    def __init__(self, passingers, pilots, crews):
        self.passingers = passingers
        self.pilots = pilots
        self.crews = crews
    
    def take_off(self):
        message = ("Ladies and Gentlemen, " + 
                    "our plane is about to take off. " + 
                    "Please fasten your seat belt.")
        print(message)

    def __str__(self):
        return "pilots: {}, passengers: {}, crews: {}"\
            .format(self.pilots, self.passingers, self.crews)


if __name__ == "__main__":
    car = Car(["Steve"], "Leon", "P")
    print(car)
    car.give_ride(["Kay"])
    print(car)
    car.change_gear("D")

    airplane = Airplane(\
    ["Homer", "Marge", "Bart", "Lisa", "Maggie"],\
     ["Luke", "Han"], ["Anakin", "Yoda"])
    print(airplane)
    airplane.take_off()

This example shows some basic concepts of inheritance. Both Car and Airplane class inherited Vehicle class. They both have ‘passengers’ prop and they both can give ride by ‘give_ride()’ method.

However those Car class and Airplane class are slightly different. The ‘car’ instance from Car class has props like ‘driver’ and ‘gear’, wheareas the ‘airplane’ instance from Airplane class has ‘pilots’ and ‘crews’. ‘car’ has method ‘change_gear()’ whereas ‘airplane’ has method ‘take_off()’.