Practical 12: Object Oriented Programming Principles

Objective

In this lab, you will implement Basic Inheritance, Abstraction, Polymorphism and SOLID Principles in exercises. This exercise will help you understand the concepts.

Submission Date:

Prerequisites

  • Basic knowledge of Python syntax
  • Understanding of lists and functions in Python
  • Familiarity with time complexity concepts (optional, but helpful)

Lab Steps

Step 1: Basic Inheritance

Employee is subclass of Person. super() function is used to call the parent class’s methods, and leverage the functionality of the parent class.

# Parent Class: Person
class Person:
    def __init__(self, name, idnumber):
        self.name = name
        self.idnumber = idnumber

    def display(self):
        print(self.name)
        print(self.idnumber)

# Child Class: Employee
class Employee(Person):
    def __init__(self, name, idnumber, salary, post):
        super().__init__(name, idnumber)  
	# Using super() to call Person's __init__()
        self.salary = salary
        self.post = post

employee1 = Employee("Sonam", 22404, 60000, "student")
employee1.display()

Step 2: Data Abstraction

  • Create abstract base class Car
  • Import required modules
  • Create child class Hatchback
from abc import ABC, abstractmethod
class Car(ABC):
    def __init__(self, brand, model, year):
        self.brand = brand
        self.model = model
        self.year = year

    # Create abstract method      
    @abstractmethod
    def printDetails(self):
        pass
    # Create concrete method
    def accelerate(self):
        print("Speed up ...")  

class Hatchback(Car):
    def printDetails(self):
        print("Brand:", self.brand)
        print("Model:", self.model)
        print("Year:", self.year)
  
    def sunroof(self):
        print("Not having this feature")

# car1 = Car("Toyota", "Prius", "2004") # This does not work
hatch1 = Hatchback("Toyota", "Prius", "2004")
hatch1.sunroof()

Step 3: Class Polymorphism

Runtime polymorphism is achieved through method overriding. The study() method exhibits polymorphic behavior based on the object calling it.

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def study(self):
        print(self.name, " is studying Python.")

class HighSchoolStudent(Student):
    def __init__(self, name, age, grade):
        super().__init__(name, age)
        self.grade = grade
    
    def study(self):
        print(self.name, " is studying Mathematics.")

Karma = Student("Karma", 25)
Karma.study()

Sonam = HighSchoolStudent("Sonam Lhamo", 20, 12)
Sonam.study()

Step 4: Function Polymorphism

Methods can be written to have different behaviour depending of type of inputs received There are some functions in Python which are compatible to run with multiple data types. One such function is the len() function. It can run with many data types in Python. Let's look at some example use cases of the function

# Length of String
print(len("Programiz"))
# Length of List
print(len(["Python", "Java", "C"]))
# Length of Dictionary
print(len({"Name": "John", "Address": "Nepal"}))

Step 5: Operator Polymorphism

This is the ability to use common operations in different forms for different data inputs. Operator Overloading means giving extended meaning beyond their predefined operational meaning.

class complex:
    def __init__(self, a, b):
        self.a = a
        self.b = b
    
    # adding two objects
    def __add__(self, other):
        return self.a + other.a, self.b + other.b

Ob1 = complex(1, 2)
Ob2 = complex(2, 3)
Ob3 = Ob1 + Ob2
print(type(Ob3), Ob3)

Step 6: SOLID Principle 1: Single Responsibility Principle (SRP)

“A class should have one and only one reason to change.” – Robert C. Martin

class Person:
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return f'Person(name={self.name})'

class PersonDB:
    def save(self, person):
        print(f'Save the {person} to database')

Step 7: SOLID Principle 2: Open/Closed Principle (OCP)

“Software entities should be open for extension, but closed for modification.” – Bertrand Meyer

from abc import ABC, abstractmethod

class PersonStorage(ABC):
    @abstractmethod
    def save(self, person):
        pass

class PersonDB(PersonStorage):
    def save(self, person):
        print(f'Save the {person} to database')


class PersonJSON(PersonStorage):
    def save(self, person):
        print(f'Save the {person} to JSON file')

Step 8: SOLID Principle 3: Liskov Substitution Principle (LSP)

“Let q(x) be a property provable about objects of x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T.” – Barbara Liskov

from abc import ABC, abstractmethod

class Notification(ABC):
    @abstractmethod
    def notify(self, message):
        pass

class Email(Notification):
    def __init__(self, email):
        self.email = email
    def notify(self, message):
        print(f'Send "{message}" to {self.email}')

class SMS(Notification):
    def __init__(self, phone):
        self.phone = phone
    def notify(self, message):
        print(f'Send "{message}" to {self.phone}')

class Contact:
    def __init__(self, name, email, phone):
        self.name = name
        self.email = email
        self.phone = phone

class NotificationManager:
    def __init__(self, notification):
        self.notification = notification
    def send(self, message):
        self.notification.notify(message)

if __name__ == '__main__':
    contact = Contact('John Doe', 'john@test.com', '(408)-888-9999')
    sms_notification = SMS(contact.phone)
    email_notification = Email(contact.email)
    notification_manager = NotificationManager(sms_notification)
    notification_manager.send('Hello John')
    notification_manager.notification = email_notification
    notification_manager.send('Hi John')

Step 9: SOLID Principle 4: Interface Segregation Principle (ISP)

“Clients should not be forced to depend on methods they do not use.” – Robert C. Martin

First, split the Vehicle interface into two smaller interfaces: Movable and Flyable, and inherits the Movable class from the Flyable class. Second, inherits from the Flyable class from the Aircraft class. Third, inherit the Movable class from the Car class.

class Movable(ABC):
    @abstractmethod
    def go(self):
        pass

class Flyable(Movable):
    @abstractmethod
    def fly(self):
        pass

class Aircraft(Flyable):
    def go(self):
        print("Taxiing")

    def fly(self):
        print("Flying")

class Car(Movable):
    def go(self):
        print("Going")

Step 10: SOLID Principle 5: Dependency Inversion Principle (DIP)

“High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions.” – Robert C. Martin

CurrencyConverter is the abstraction layer

from abc import ABC

class CurrencyConverter(ABC):
    def convert(self, from_currency, to_currency, amount) -> float:
        pass

class FXConverter(CurrencyConverter):
    def convert(self, from_currency, to_currency, amount) -> float:
        print('Converting currency using FX API')
        print(f'{amount} {from_currency} = {amount * 1.15} {to_currency}')
        return amount * 1.15

class AlphaConverter(CurrencyConverter):
    def convert(self, from_currency, to_currency, amount) -> float:
        print('Converting currency using Alpha API')
        print(f'{amount} {from_currency} = {amount * 1.2} {to_currency}')
        return amount * 1.2

class App:
    def __init__(self, converter: CurrencyConverter):
        self.converter = converter

    def start(self):
        self.converter.convert('EUR', 'USD', 100)

if __name__ == '__main__':
    converter = AlphaConverter() # Select converter here
    app = App(converter)
    app.start()

Step 11: Run through OOP unit Worksheet 2

Run through OOP unit Worksheet 2 on Online Banking Application

Worksheet2

Exercises for Students

  1. Implement various different variables, methods and classes based on principles of Basic Inheritance, Abstraction, Polymorphism. and Solid Principles.

Conclusion

In this lab, you've implemented and tested further concepts on OOP.

Key takeaways: