0% found this document useful (0 votes)
10 views

Practical_OOP

This clear real world concept of Object Oriented Programming
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views

Practical_OOP

This clear real world concept of Object Oriented Programming
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 25

Object-Oriented Programming (OOP) is a programming paradigm centered

around objects rather than functions or procedures.

A Class is a blueprint or template for creating objects. It defines the properties


(attributes) and behaviors (methods) that objects created from the class will
have. Think of a class as a recipe: it contains the instructions and ingredients
needed to make a particular dish, but until you use the recipe, you don’t have the
actual dish.

Objects are instances of classes, which can represent real-world entities with
certain characteristics (attributes) and behaviors (methods).

OOP is popular because it allows for code that is modular, reusable, and easier
to understand and maintain.
It’s built on four main principles: Encapsulation, Abstraction, Inheritance, and
Polymorphism.

1. Encapsulation in Java

● Encapsulation means bundling data (variables) and methods (functions)


that operate on that data within a single class. It hides the internal state of
the object from outside interference and protects integrity of the data. The
idea is to control how the data is accessed and modified, ensuring that it
can only be changed in valid ways.
● In Java, we use private access modifiers for variables and provide public
getter and setter methods to control access.

Real-World Application: Bank Account Management

In a banking application, the details of a customer's bank account should be


protected from unauthorized access. For example, a customer's account balance
should not be directly accessible or modifiable; instead, customers should only
interact with the balance through specific methods like deposit and withdraw.

public class BankAccount {


// Private variables for encapsulation
private double balance; // Account balance
private String accountNumber; // Account number

// Constructor to initialize the account


public BankAccount(String accountNumber, double initialBalance) {
this.accountNumber = accountNumber;
this.balance = initialBalance;
}

// Getter method for balance


public double getBalance() {
return balance;
}

// Method to deposit money


public void deposit(double amount) {
if (amount > 0) {
balance += amount; // Update balance
System.out.println("Deposited: " + amount + ", New Balance: " +
balance);
} else {
System.out.println("Invalid deposit amount.");
}
}

// Method to withdraw money


public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount; // Update balance
System.out.println("Withdrawn: " + amount + ", New Balance: " +
balance);
} else {
System.out.println("Invalid withdrawal amount.");
}
}

// Display account details


public void displayAccountInfo() {
System.out.println("Account Number: " + accountNumber);
System.out.println("Current Balance: " + balance);
}
}

public class Main {


public static void main(String[] args) {
BankAccount account = new BankAccount("123456789", 1000.00);
account.displayAccountInfo();
account.deposit(500);
account.withdraw(200);
account.withdraw(1500); // Attempting to withdraw more than balance
account.displayAccountInfo();
}
}

Explanation:

● Private Variables: The balance and accountNumber fields are private,


meaning they cannot be accessed directly from outside the class.
● Public Methods: The deposit, withdraw, and getBalance methods provide
controlled access to the balance, ensuring that only valid operations can change
the balance.
● User Interaction: The user interacts with the account only through these public
methods, keeping the internal state secure.

2. Abstraction

Concept Explained:

Abstraction involves hiding the complex implementation details and showing only
the essential features of the object. It allows the user to interact with the object at
a high level without needing to understand the internal workings. This can be
achieved using abstract classes and interfaces in Java.

Real-World Application: Vehicle Management System

In a vehicle management system, different types of vehicles (cars, trucks,


motorcycles) may share some common features (like start, stop), but the
implementation of these features can vary significantly.
abstract class Vehicle {
abstract void start(); // Abstract method
abstract void stop(); // Abstract method

// Common method
public void displayType() {
System.out.println("This is a vehicle.");
}
}

class Car extends Vehicle {


@Override
void start() {
System.out.println("Car engine starting...");
}

@Override
void stop() {
System.out.println("Car engine stopping...");
}
}

class Truck extends Vehicle {


@Override
void start() {
System.out.println("Truck engine starting...");
}

@Override
void stop() {
System.out.println("Truck engine stopping...");
}
}

public class Main {


public static void main(String[] args) {
Vehicle myCar = new Car();
Vehicle myTruck = new Truck();

myCar.displayType();
myCar.start();
myCar.stop();

myTruck.displayType();
myTruck.start();
myTruck.stop();
}
}

Explanation:

● Abstract Class: The Vehicle class is abstract, meaning it cannot be


instantiated. It defines the methods start and stop, which must be
implemented by any subclass.
● Subclass Implementation: The Car and Truck classes implement the start
and stop methods in their own way.
● High-Level Interaction: The user interacts with the Vehicle type without
needing to know how each specific vehicle starts or stops. This simplifies the
user experience and improves code maintainability.

3. Inheritance

Concept Explained:

Inheritance is a mechanism in OOP that allows a new class (subclass) to inherit


properties and methods from an existing class (superclass). This promotes code
reuse and establishes a hierarchical relationship between classes.

Real-World Application:
Application1: Employee Management System

In an employee management system, there might be different types of


employees (e.g., full-time, part-time, intern) that share common attributes and
behaviors but also have unique features.

class Employee {
protected String name; // Protected allows subclasses to access
protected int id;

public Employee(String name, int id) {


this.name = name;
this.id = id;
}

public void displayInfo() {


System.out.println("Name: " + name + ", ID: " + id);
}
}

class FullTimeEmployee extends Employee {


private double salary;

public FullTimeEmployee(String name, int id, double salary) {


super(name, id); // Call to the superclass constructor
this.salary = salary;
}

@Override
public void displayInfo() {
super.displayInfo(); // Call to the superclass method
System.out.println("Salary: " + salary);
}
}

class PartTimeEmployee extends Employee {


private double hourlyRate;

public PartTimeEmployee(String name, int id, double hourlyRate) {


super(name, id); // Call to the superclass constructor
this.hourlyRate = hourlyRate;
}

@Override
public void displayInfo() {
super.displayInfo(); // Call to the superclass method
System.out.println("Hourly Rate: " + hourlyRate);
}
}

public class Main {


public static void main(String[] args) {
FullTimeEmployee fullTimeEmp = new FullTimeEmployee("Alice", 1,
60000);
PartTimeEmployee partTimeEmp = new PartTimeEmployee("Bob", 2, 20);

fullTimeEmp.displayInfo();
partTimeEmp.displayInfo();
}
}

Explanation:

● Superclass: The Employee class contains common attributes like name and id,
and a method to display employee information.
● Subclasses: FullTimeEmployee and PartTimeEmployee inherit from
Employee, allowing them to use its properties and methods while adding their
specific attributes (salary and hourlyRate).
● Code Reusability: This structure allows for easy expansion of the employee
types without rewriting common functionalities, promoting efficient code reuse.

Application2:
class Product {
double price;
String description;

public Product(double price, String description) {


this.price = price;
this.description = description;
}

public void displayInfo() {


System.out.println("Price: $" + price + ", Description: " + description);
}
}

class Electronics extends Product {


String brand;
int warranty;

public Electronics(double price, String description, String brand, int warranty) {


super(price, description); // Call to parent class constructor
this.brand = brand;
this.warranty = warranty;
}

@Override
public void displayInfo() {
super.displayInfo();
System.out.println("Brand: " + brand + ", Warranty: " + warranty + " years");
}
}

class Clothing extends Product {


String size;
String material;

public Clothing(double price, String description, String size, String material) {


super(price, description);
this.size = size;
this.material = material;
}

@Override
public void displayInfo() {
super.displayInfo();
System.out.println("Size: " + size + ", Material: " + material);
}
}
4. Polymorphism

Concept Explained:

Polymorphism allows methods to do different things based on the object that it is


acting upon. It can be achieved through method overriding (where a subclass
provides a specific implementation of a method defined in its superclass) and
method overloading (where two methods have the same name but different
parameters).

Real-World Application:

Application1: Notification System

In a notification system, different types of notifications (like Email, SMS, and


Push notifications) can be sent using the same method name but will have
different implementations.

interface Notification {
void send(String message); // Method signature
}

class EmailNotification implements Notification {


@Override
public void send(String message) {
System.out.println("Sending Email: " + message);
}
}

class SMSNotification implements Notification {


@Override
public void send(String message) {
System.out.println("Sending SMS: " + message);
}
}

class PushNotification implements Notification {


@Override
public void send(String message) {
System.out.println("Sending Push Notification: " + message);
}
}

public class Main {


public static void main(String[] args) {
Notification email = new EmailNotification();
Notification sms = new SMSNotification();
Notification push = new PushNotification();

// Array of notifications
Notification[] notifications = {email, sms, push};

// Send messages using polymorphism


for (Notification notification : notifications) {
notification.send("Hello World!");
}
}
}

Explanation:

● Interface: The Notification interface defines a method send, which must be


implemented by all notification types.
● Different Implementations: EmailNotification, SMSNotification, and
PushNotification all implement the send method, providing their specific
ways to send notifications.
● Polymorphic Behavior: Notification types are used. Each type calls its own
send method implementation, allowing for dynamic behavior at runtime without
modifying the main code structure.

Application2: Payment Modes


Interface Payment {
void processPayment(double amount);
}
class CreditCardPayment implements Payment {
@Override
public void processPayment(double amount) {
System.out.println("Processing credit card payment of $" + amount);
}
}

class PayPalPayment implements Payment {


@Override
public void processPayment(double amount) {
System.out.println("Processing PayPal payment of $" + amount);
}
}

class BankTransferPayment implements Payment {


@Override
public void processPayment(double amount) {
System.out.println("Processing bank transfer payment of $" + amount);
}
}

public class PaymentProcessor {


public static void main(String[] args) {
Payment paymentMethod;

// Processing credit card payment


paymentMethod = new CreditCardPayment();
paymentMethod.processPayment(250.00);

// Processing PayPal payment


paymentMethod = new PayPalPayment();
paymentMethod.processPayment(150.00);

// Processing bank transfer payment


paymentMethod = new BankTransferPayment();
paymentMethod.processPayment(100.00);
}
}

5) Class And Object:

Real-Life Application Example: Library Management System

Let’s use a Library Management System to understand classes and objects. In


this system, we might have classes like Book, LibraryMember, and Library.
Each class represents a different concept in the library, and objects created from
these classes represent individual books, members, and libraries.

1. Book Class

● Attributes: title, author, ISBN, pages


● Behaviors: borrow, return, displayInfo

2. LibraryMember Class

● Attributes: name, memberID, borrowedBooks


● Behaviors: borrowBook, returnBook, viewBorrowedBooks

3. Library Class

● Attributes: name, address, books (a collection of Book objects), members


(a collection of LibraryMember objects)
● Behaviors: addBook, addMember, listBooks, listMembers

Using these classes, we can create multiple objects like individual books and
members with specific values. Below is a Java code example for the Book and
LibraryMember classes, showing how they work together.

Java Code Example

Step 1: Define the Book Class

The Book class will represent a single book in the library. It has attributes like
title, author, and ISBN, and behaviors like borrowing and returning the book.
class Book {

// Attributes

private String title;

private String author;

private String ISBN;

private boolean isAvailable;

// Constructor

public Book(String title, String author, String ISBN) {

this.title = title;

this.author = author;

this.ISBN = ISBN;

this.isAvailable = true; // Book is available by default

// Behavior to borrow the book

public boolean borrow() {

if (isAvailable) {

isAvailable = false;

System.out.println("Book borrowed: " + title);

return true;

} else {

System.out.println("Book not available: " + title);

return false;
}

// Behavior to return the book

public void returnBook() {

isAvailable = true;

System.out.println("Book returned: " + title);

// Method to display book information

public void displayInfo() {

System.out.println("Title: " + title + ", Author: " + author + ", ISBN: " + ISBN +
", Available: " + isAvailable);

Step 2: Define the LibraryMember Class

The LibraryMember class represents a library member who can borrow books.
Each member has a name, memberID, and a list of borrowed books.

import java.util.ArrayList;

import java.util.List;

class LibraryMember {

// Attributes

private String name;

private String memberID;


private List<Book> borrowedBooks;

// Constructor

public LibraryMember(String name, String memberID) {

this.name = name;

this.memberID = memberID;

this.borrowedBooks = new ArrayList<>();

// Method to borrow a book

public void borrowBook(Book book) {

if (book.borrow()) {

borrowedBooks.add(book);

System.out.println(name + " borrowed: " + book);

// Method to return a book

public void returnBook(Book book) {

if (borrowedBooks.contains(book)) {

book.returnBook();

borrowedBooks.remove(book);

System.out.println(name + " returned: " + book);

}
}

// Method to view all borrowed books

public void viewBorrowedBooks() {

System.out.println("Borrowed Books by " + name + ":");

for (Book book : borrowedBooks) {

book.displayInfo();

Step 3: Create Objects in the Main Program

Now, let’s create some objects for Book and LibraryMember and interact with
them to see how classes and objects work together.

public class Main {

public static void main(String[] args) {

// Create Book objects

Book book1 = new Book("The Great Gatsby", "F. Scott Fitzgerald",


"9780743273565");

Book book2 = new Book("To Kill a Mockingbird", "Harper Lee",


"9780061120084");

// Display book information

book1.displayInfo();

book2.displayInfo();
// Create a LibraryMember object

LibraryMember member = new LibraryMember("Alice", "M001");

// Member borrows books

member.borrowBook(book1); // Alice borrows "The Great Gatsby"

member.borrowBook(book2); // Alice borrows "To Kill a Mockingbird"

// Display borrowed books

member.viewBorrowedBooks();

// Member returns a book

member.returnBook(book1); // Alice returns "The Great Gatsby"

// Display borrowed books after returning one

member.viewBorrowedBooks();

Explanation of How Classes and Objects Work Here

1. Class Definitions:
○ We defined two classes: Book and LibraryMember.
○ Each class has specific attributes and methods related to the type of
entity it represents. Book manages book information and availability,
while LibraryMember manages borrowed books for each member.
2. Creating Objects:
○ In Main, we created specific book objects (book1 and book2) and a
library member object (member).
○ Each Book object represents a unique book with specific details like
title, author, and ISBN.
○ The LibraryMember object (member) represents a library member
named "Alice" with a unique ID "M001".
3. Using Objects:
○ Alice (the LibraryMember object) borrows book1 and book2.
The borrowBook method checks if the book is available and, if so,
marks it as borrowed.
○ We display the list of books Alice has borrowed.
○ When Alice returns book1, the returnBook method updates the
book’s availability and removes it from her borrowed list.
4. Encapsulation in Action:
○ The Book class’s borrow and returnBook methods control how
each book's availability is updated, ensuring consistency and
avoiding direct manipulation of the isAvailable attribute.
○ Similarly, LibraryMember manages the list of borrowed books,
encapsulating the borrowing and returning behavior.

Real-Life Context

In a real library system, each Book object would represent a physical or digital
book available to members. Each LibraryMember object would represent a
registered library member. Together, classes and objects help simulate and
manage real-world interactions, such as borrowing and returning books, by
organizing data and functions logically and efficiently.
Real-Life Application of OOP: Library Management System in Java

Let’s create a simplified Library Management System in Java using the OOP
principles.

1) Encapsulation: Each Book has private attributes like title, author,


and status, with methods to check out and return the book.

public class Book {

private String title;

private String author;

private boolean isAvailable;

public Book(String title, String author) {

this.title = title;

this.author = author;

this.isAvailable = true;

public void checkout() {

if (isAvailable) {

isAvailable = false;

System.out.println(title + " has been checked


out.");

} else {
System.out.println(title + " is not
available.");

public void returnBook() {

isAvailable = true;

System.out.println(title + " has been returned.");

public boolean isAvailable() {

return isAvailable;

public String getTitle() {

return title;

2) Abstraction: A Library class with methods for adding and finding books
hides the internal storage of the book list.

import java.util.ArrayList;
public class Library {

private ArrayList<Book> books = new ArrayList<>();

public void addBook(Book book) {

books.add(book);

System.out.println(book.getTitle() + " has been


added to the library.");

public Book findBookByTitle(String title) {

for (Book book : books) {

if (book.getTitle().equalsIgnoreCase(title)) {

return book;

System.out.println("Book not found.");

return null;

3) Inheritance: Different user types (Student and Teacher) inherit from a


base User class with a borrowing limit.

public class User {

protected String name;


protected int borrowLimit;

public User(String name, int borrowLimit) {

this.name = name;

this.borrowLimit = borrowLimit;

public class Student extends User {

public Student(String name) {

super(name, 3);

public class Teacher extends User {

public Teacher(String name) {

super(name, 5);

4) Polymorphism: The User can be either a Student or Teacher, and we


can handle both types using polymorphism.

public class LibraryManagement {

public static void main(String[] args) {


Library library = new Library();

Book book1 = new Book("Java Programming", "Author


A");

Book book2 = new Book("Data Structures", "Author


B");

library.addBook(book1);

library.addBook(book2);

User student = new Student("Alice");

User teacher = new Teacher("Bob");

Book foundBook = library.findBookByTitle("Java


Programming");

if (foundBook != null && foundBook.isAvailable()) {

foundBook.checkout();

This structure provides a modular and maintainable way to build a Library


Management System in Java using the core OOP principles.
Abstraction is basically the ability to use some code or behavior without having to know how it
works. You just have to know what interface it exposes and it will do what you expect.

Here's a simple example: In any reasonable language, you can write something equivalent to
print("Hello world") and it will print "Hello world" to your terminal -- but do you know how print
(or its equivalent) actually works? I would bet that the overwhelming majority of people who've ever
written code probably don't.

That's because print is an abstraction. The actual steps between invoking a hello world program
and seeing "hello world" pop up on your screen go deep into the internals of the operating system
and CPU, but you don't have to know that -- you just have to know that you can invoke print and it'll
work. (And, in fact, print is an abstraction on top of abstractions. The programming language
maintainers who implemented print don't have to know all the OS internals, they just have to know
what interfaces the OS exposes. And the OS maintainers don't have to know the details of the CPU's
inner circuitry, they just have to know what instruction set the CPU exposes.)

Where abstraction and OOP come together is in the form of interfaces and composition. In OOP, you
can have multiple different classes implement the same interface but work in different ways. For
example, say you needed to write a program that sends messages to people in a variety of ways
(e.g. Discord, Slack, email, and SMS). With OOP, you could define a MessagingClient interface with
a sendMessage method and have classes that implement that interface and method. Each class's
implementation of sendMessage would be different, but code that uses it wouldn't have to worry
about which implementation it's using. You could write some code like this and just rely on each
individual client object's class to handle the specifics:
for (MessagingClient client : messagingClients) {

client.sendMessage(message);

The key here is that each client in messagingClients is pre-populated with all the information it
needs to send a message. It might have credentials for Discord and information about which server
and channel to post a message in. It might have an email address and information about an SMTP
server to use. It might have something completely different. Whatever it has, it doesn't matter to this
code that's trying to send the message. You don't have to alter that loop to support a new
MessagingClient implementation. Likewise, you can use MessagingClient anywhere and those
places don't have to know what implementation they're using or where it comes from. If you wanted
to support sending messages via Reddit DM or fax or something, you'd just have to implement a new
MessagingClient and then wire it up so it gets passed in the right places in your code. (Okay, "just"
is doing a lot of work there. I think actually learning how to do this is one of the harder parts of
figuring out OOP.)

For example, you could have messagingClients be pulled from a config file that can be updated to
include arbitrary messaging destinations. You could write code that has a registry of all your
MessagingClient implementations and then use that registry to read entries from the config file
and instantiate instances of each appropriate implementation. Then you can just pass that array of
MessagingClient instances to the function with that for loop. The loop and its containing function
don't care where those messagingClients came from -- it just cares that they implemented
sendMessage. Likewise, whoever updates the config file doesn't have to worry about how the
messages get sent, they just have to worry about providing the right details to configure each service
properly. If you do it right, this enables you to completely decouple the code that's responsible for
building the messagingClients collection and the code that actually invoke each client to send each
message.

You might also like