Object-Oriented Programming(OOP)

#EN

Introduction

Most Engineers must hear the word, Object-Oriented Programming(OOP).
However, there are few engineers who can explain it.
In this article, I'll try to dig deeper into this topic.

1. The Forgotten History of OOP

1-1. Low level languages to High level languages

Low level languages like machine code and assembly appeared in the 1940s.
By the end of the 1950s, the first popular high-level languages appeared.
After that, C-family languages have replaced both COBOL and FORTRAN for most applications.
In the course of its programing languages development, they've established how easy it is for people to express the work they want the PC to do.

1-2. Structured languages

Structured languages were proposed to further improve productivity and quality of programming.
They increased independence of subroutines to make them more maintainable.
They also need to reduce the number of global variables shared by multiple subroutines.
However, they have to use global valuable when they need to retain information beyond the execution time of a subroutine.
In this case, it's difficult to know which subroutine is modifying a global variable.

1-3. OOP

To solve the above problems, Object-oriented programming (OOP) was coined by Alan Kay.
OOP is a style of programming that focuses on using objects to design and build applications. OOP organizes the program to combine data and functionality and wrap it inside something called an Object.

  • Objects

Objects represent a real-world entity and the basic building block of OOP.
ex) an Online Shopping System will have objects such as shopping cart, customer,product item, etc.

  • Class

Class is the prototype or blueprint of an object. It is a template definition of the attributes and methods of an object.
ex) in the Online Shopping System, the Customer object will have attributes like shipping address, credit card, etc., and methods for placing an order, canceling an order, etc.

2. The four principles of OOP

2-1: Encapsulation

Encapsulation is the mechanism of binding the data together and hiding it from the outside world.
It is achieved when each object keeps its state private so that other objects don’t have direct access to its state.
Instead, they can access this state only through a set of public functions.

class Product:

    def __init__(self):
        self.__maxprice = 900

    def sell(self):
        print("Selling Price: {}".format(self.__maxprice))

    def set_max_price(self, price):
        self.__maxprice = price

product = Product()
product.sell() # Selling Price: 900

# change the price
product.__maxprice = 1000
product.sell() # Selling Price: 900

# using setter function
product.set_max_price(1000)
product.sell() # Selling Price: 1000

2-2. Abstraction

Abstraction can be thought of as the natural extension of encapsulation.
It means hiding all but the relevant data about an object in order to reduce the complexity of the system.
In a large system, objects talk to each other, which makes it difficult to maintain a large code base;
Abstraction helps by hiding internal implementation details of objects and only revealing operations that are relevant to other objects.

from abc import ABC, abstractmethod

class Parent(ABC):
  def common(self):
    print('In common method of Parent')

  @abstractmethod
  def vary(self):
    pass

class Child1(Parent):
  def vary(self):
    print('In vary method of Child1')

class Child2(Parent):
  def vary(self):
    print('In vary method of Child2')

# object of Child1 class
child1 = Child1()
child1.common() # In common method of Parent
child1.vary() # In vary method of Child1

# object of Child2 class
child2 = Child2()
child2.common() # In common method of Parent
child2.vary() # In vary method of Child2

2-3: Inheritance

Inheritance is a mechanism to eliminate code duplication by grouping common parts of class definitions

2-4: Polymorphism

Polymorphism is the ability of an object to take different forms and thus, depending upon the context, to respond to the same message in different ways.
ex) a chess game; a chess piece can take many forms, like bishop, castle, or knight and all these pieces will respond differently to the ‘move’ message.

class Bishops:

    def move(self):
        print("Bishops can move diagonally")

class Knights:

    def move(self):
        print("Knights can move two squares vertically and one square horizontally, or two squares horizontally and one square vertically")

# common interface
def move_test(chess_piece):
    chess_piece.move()

#instantiate objects
bishop = Bishops()
knight = Knights()

# passing the object
move_test(bishop) # Bishops can move diagonally
move_test(knight) # Knights can move two squares vertically and one square horizontally, or two squares horizontally and one square vertically

3. Example

CreditCard Class

  • Actually, we need to consider type check error if arg is invalid value
class CreditCard
  def __init__(self, customer, bank, acnt, limit):
    # encapsulation nonpublic
    self._customer = customer
    self._bank = bank
    self._account = acnt
    self._limit = limit
    self._balance = 0

  # accessor
  def get_customer(self):
    return self._customer

  def get_bank(self):
    return self._bank

  def charge(self, price):
    if price + self._balance > self._limit: # if charge would exceed limit
      return False                          # cannot accept charge
    else:
      self._balance += price
      return True

class PredatoryCreditCard(CreditCard):
  def __init__(self, customer, bank, acnt, limit, apr):
    super().__init__(customer, bank, acnt, limit)
    self._apr = apr

  def change(self, price):
    success = super().charge(price)
    if not success:
      self._balance += 5
    return success

  def process_month(self):
    if self._balance > 0:
      monthly_factor = pow(1 + self._apr, 1/12)
      self._balance *= monthly_factor

Related Posts