Beginner’s Guide to the Basics of Object-Oriented Programming

A beginner’s guide to learning OOP with explanation of it’s principles

Omar Emad
CodeX
12 min readApr 26, 2023

--

When writing a program it is very common for it to get more complicated as you add more features, It is also common to find it a nightmare to reuse code from one part of your program in another. A simple solution that helps mitigating these issues is using object-oriented programming (OOP). In this article I will be using Java to explain object oriented programming and its fundamentals

What’s Object-Oriented Programming ?

OOP is a way of organizing your code into “objects” that contain both data and functions. This allows you to bundle related pieces of code together and easily reuse them in different parts of your program. OOP also allows you to hide the implementation details of your code, making it easier to maintain and modify without affecting other parts of your program.

Why should you use Object-Oriented Programming ?

Overall, learning OOP principles can help you write cleaner, more organized, more efficient, and more maintainable code, which will save you time and effort in the long run by :

  1. Improved code organization
    By grouping related data and functions into objects, your code will be more organized and easier to understand. This makes it easier for you and others to read and understand your code.
  2. Increased code reusability
    By creating reusable classes, you can easily integrate them into other parts of your program without having to write separate code for each instance.
  3. Better code maintainability
    By hiding the implementation details of your code, you can easily modify and update your code without affecting other parts of your program. This makes it easier to fix bugs and add new features, without worrying about breaking your code.
  4. Better code scalability
    When you create hierarchical relationships between classes, it becomes easier to add new features and functionality to your program without affecting existing code. For example, if you have a class that represents a duck, you can create subclasses for specific types of ducks, such as wild ducks, rubber ducks, and any kind of duck!

Before you continue

If you know any object oriented programming language basics you have all the prerequisites to understand this article, I will be using java to make all the examples, if you think an example is unclear or needs further explanation give me a comment and I will do my best to ensure this article is clear.
If you want a place to learn the basics of java I think the course made by Tech with Tim with collaboration with freeCodeCamp is amazing here is a link to the course.

What’s a “Class” ?

A class is like a blueprint for creating things. It tells you what the thing should look like and what it should be able to do. For example, let’s say you want to make a toy robot. A toy robot class would tell you what parts the robot needs, like wheels and a motor, robot properties like color and height, and what the robot should be able to do, like move and make noises. Once you have the blueprint, you can use it to make as many robots as you want. Each robot you make using the blueprint is called an object.

Creating a robot class

a red robot with height of 170 cm

The main elements of a class are:

1.Class name
The class name is the identifier used to refer to the class in the code. It is the name that is given to the class when it is defined. it basically like a custom variable or like a struct if you know C.

public class Robot {
}

Here we defined a class called Robot, public here means any part of our code can interact with the Robot. We will see they keyword private later which means only code inside the class an access it.

2.Class attributes
Class attributes are normal variables that change based on the properties of the class

public class Robot {
// Properties of the robot
private String color;
private double height;

// Parts of the robot
private String[] parts = {"wheels", "motor", "arms"};
}

This robot class has properties for the robot’s color and height, as well as an array of strings to represent the parts that the robot needs.

3.Class constructor
A class constructor is the function that runs when you create a new instance of the class (object). It usually is used to set the attributes (properties) of the class.

public class Robot {
// Properties of the robot
private String color;
private double height;

// Parts of the robot
private String[] parts = {"wheels", "motor", "arms"};

// Constructor to initialize the robot's properties
public Robot(String color, double h) {
this.color = color;
height = h;
}
}

Here we used the constructor to set the color and height of the robot. The this keyword refers to the class itself, we use it so the compiler doesn’t confuse the color in the parameter with the color in the attribute. We didn’t do the same for height since the parameter name is different from the attribute name.

4.Class methods
These define class functionality, also it’s pretty common to write setter and getter functions for private attributes to be able to access them from anywhere in the code. here is an example of the robot class with methods:

public class Robot {
// Properties of the robot
private String color;
private double height;

// Parts of the robot
private String[] parts = {"wheels", "motor", "arms"};

// Constructor to initialize the robot's properties
public Robot(String color, double h) {
this.color = color;
height = h;
}

// Function to move the robot
public void move() {
System.out.println("The robot is moving");
}

// Function to start the robot
public void start() {
System.out.println("The robot is starting");
}

// Setter for color property
public void setColor(String color) {
this.color = color;
}

// Getter for color property
public String getColor() {
return this.color;
}

// Setter for height property
public void setHeight(double height) {
this.height = height;
}

// Getter for height property
public double getHeight() {
return this.height;
}
}

The Robot class also has two functions: move and start. The move function simply prints a message to the console indicating that the robot is moving. The start function similarly prints a message to the console indicating that the robot is starting.

What’s an “Object” ?

A blue print of a cube named class and an instances of cube named objects

An object is an instance of a class, While the class is the blueprint an object is what we build using the blueprint, It’s where we set the attributes and use the functionality of the class.

Initializing an object

An object is an instance of a class, While the class is the blueprint an object is what we build using the blueprint, It’s where we set the attributes and use the functionality of the class.

// Instance of a red robot with height of 1.5
Robot robot1 = new Robot("Red", 1.5);

// Create of a blue robot with height of 1.0
Robot robot2 = new Robot("Blue", 1.0);
a red tall robot and a short blue robot

In this example, we create two instances of the Robot class, robot1 and robot2. The robot1 object is initialized with a color of "Red" and a height of 1.5, while the robot2 object is initialized with a color of "Blue" and a height of 1.0.

Once you have created an instance of the Robot class, you can call its methods and access its properties to manipulate and use the object. For example, you could call the setColor method to change the color property of the robot1 object:

robot1.setColor("Green");

Or you could call the getColor method to get the current color property of the robot2 object:

String robot2Color = robot2.getColor();

You can also call methods like move and start

// Call the move and start functions on the robot1 object
robot1.move();
robot1.start();

In this example, we create an instance of the Robot class called robot1. We then call the move and start functions on the robot1 object, which will cause the robot to move and start performing a task.

The move and start functions are defined in the Robot class and can be called on any object created from that class. This allows you to easily control the behavior of the robot by calling these functions on the object.

OOP principles

Some of the main principles of OOP include encapsulation, abstraction, inheritance, and polymorphism. These principles help to organize code into logical units, reduce duplication, and make it easier to reuse and modify. OOP is widely used in many different programming languages, like (python, java, C++,Dart , C# and many more)

Encapsulation

One of the key principles of OOP is encapsulation. This means grouping together related data and functions into a single object. For example, if you were creating a program to manage a library, you might have an “Book” object that contains data about a book, such as its title, author, and number of pages. The Book object could also have functions that allow you to check out a book, renew a book, or return a book. By encapsulating the data and functions into a single object, you can easily reuse the Book object in other parts of your program without having to write separate code for each book in the library.

Here is an example of the book class

public class Book {
private String title;
private String author;
private int pages;
private boolean checkedOut;

public Book(String title, String author, int pages) {
this.title = title;
this.author = author;
this.pages = pages;
this.checkedOut = false;
}

public void checkOut() {
if (!checkedOut) {
checkedOut = true;
System.out.println(title + " has been checked out.");
} else {
System.out.println(title + " is already checked out.");
}
}

public void renew() {
if (checkedOut) {
System.out.println(title + " has been renewed.");
} else {
System.out.println(title + " cannot be renewed because it is not checked out.");
}
}

public void returnBook() {
if (checkedOut) {
checkedOut = false;
System.out.println(title + " has been returned.");
} else {
System.out.println(title + " is already returned.");
}
}
}

Let’s say we have a program that manages a library of books, a good example of reusability that comes from encapsulation would be if we create a list of books called library like this

ArrayList<Book> library = new ArrayList<Book>();

library.add(new Book("To Kill a Mockingbird", "Harper Lee", 281));
library.add(new Book("1984", "George Orwell", 328));
library.add(new Book("The Catcher in the Rye", "J.D. Salinger", 277));

If we want to create a function that checks out books for example, we could first start by writing a function that finds book by it’s title:

public static Book findBookByTitle(ArrayList<Book> library, String title) {
for (Book book : library) {
if (book.getTitle().equals(title)) {
return book;
}
}
return null;
}

We can then use this function in a checkout book function like this:

public static void checkOutBook(ArrayList<Book> library, String title) {
Book book = findBookByTitle(library, title);
if (book != null) {
book.checkOut();
} else {
System.out.println("Book not found in library.");
}
}

By encapsulating the data and functions related to a book into a single Book object, you can easily reuse the Book object in other parts of your program. In this example, the findBookByTitle() and checkOutBook() methods both use the Book object's getTitle() and checkOut() methods, respectively, to search for and check out a book. This makes the code easier to read, write, and maintain, since you don't have to duplicate code for each book in the library.

NOTE THAT : Many people confuse encapsulation for data hiding, Encapsulation is the grouping of related fields and methods, which can be used to implement data hiding. However, encapsulation itself is not the same as data hiding.

Inheritance

Another important principle of OOP is inheritance. This allows you to create new classes that are based on existing classes. This allows for code reusability and allows you to create hierarchical relationships between classes. For example, you could have a “Vehicle” class that contains data and functions common to all vehicles, such as the number of wheels and the ability to accelerate. You could then create subclasses for specific types of vehicles, such as “Car” and “Truck”, that inherit the attributes and functions of the “Vehicle” class. The “Car” and “Truck” classes could have their own unique attributes and functions, such as the number of doors or the ability to tow, but they would also have the attributes and functions of the “Vehicle” class.

Here is an example of a “Vehicle” class in Java:

public class Vehicle {
// The number of wheels on the vehicle
private int numWheels;

// The current speed of the vehicle
private int speed;

// The maximum speed the vehicle can reach
private int maxSpeed;

// A constructor for the Vehicle class
public Vehicle(int numWheels, int maxSpeed) {
this.numWheels = numWheels;
this.maxSpeed = maxSpeed;
this.speed = 0;
}

// A method to accelerate the vehicle
public void accelerate(int amount) {
if (speed + amount <= maxSpeed) {
speed += amount;
} else {
speed = maxSpeed;
}
}

// Getters and setters for the class attributes
public int getNumWheels() {
return numWheels;
}

public void setNumWheels(int numWheels) {
this.numWheels = numWheels;
}

public int getSpeed() {
return speed;
}

public void setSpeed(int speed) {
this.speed = speed;
}

public int getMaxSpeed() {
return maxSpeed;
}

public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
}

We can make Car class that inherits from Vehicle

public class Car extends Vehicle {
// The number of doors on the car
private int numDoors;

// A constructor for the Car class
public Car(int numWheels, int maxSpeed, int numDoors) {
super(numWheels, maxSpeed);
this.numDoors = numDoors;
}

// Getter and setter for the numDoors attribute
public int getNumDoors() {
return numDoors;
}

public void setNumDoors(int numDoors) {
this.numDoors = numDoors;
}
}

This Car class extends the Vehicle class and adds a new attribute: numDoors. The Car class has a constructor that takes three arguments: numWheels, maxSpeed, and numDoors. The Car constructor calls the super constructor to initialize the numWheels and maxSpeed attributes, and then sets the value of the numDoors attribute.

public class Truck extends Vehicle {
// The maximum weight the truck can carry
private int maxWeight;

// A constructor for the Truck class
public Truck(int numWheels, int maxSpeed, int maxWeight) {
// Call the superclass (Vehicle) constructor
super(numWheels, maxSpeed);

// Set the maxWeight attribute
this.maxWeight = maxWeight;
}

// Getters and setters for the maxWeight attribute
public int getMaxWeight() {
return maxWeight;
}

public void setMaxWeight(int maxWeight) {
this.maxWeight = maxWeight;
}
}

In object-oriented programming, the super keyword refers to the parent class. It is used to access methods in the parent class that have been overridden in a child class. Using the super keyword is a convenient way to call the parent class's version of a method without having to explicitly refer to the parent class.

The Car class also has a getter and setter for the numDoors attribute. These methods allow the user to access and modify the value of the numDoors attribute.

Polymorphism

Another principle of OOP is polymorphism. It allows objects of different classes to be treated the same way. This allows you to write more flexible and scalable code, as you don’t have to write separate code for each class of object. For example let’s say we want to make a function that draws a shape, this shape could be either a rectangle, square or a circle.
We could write it in this basic way :

public class DrawingShapes {
public static void main(String[] args) {
drawRectangle();
drawSquare();
drawCircle();
}

public static void drawRectangle() {
System.out.println("Drawing a rectangle...");
// Code to draw a rectangle
}

public static void drawSquare() {
System.out.println("Drawing a square...");
// Code to draw a square
}

public static void drawCircle() {
System.out.println("Drawing a circle...");
// Code to draw a circle
}
}

This code is used to draw different shapes such as rectangles, squares, and circles. It does this by defining three methods, drawRectangle(), drawSquare(), and drawCircle(), which print a message indicating which shape is being drawn and then execute the code to draw that shape.

However, this code has a limitation, If we want to add a new shape to our program, we would have to modify the code to include a new method for drawing that shape. This could be problematic if we have a lot of shapes to add.

To solve this problem, We can create a Shape class that serves as a blueprint for all shapes and then create a class for each specific shape that inherits from the Shape class. Each shape class can then override a draw() method that is defined in the Shape class, allowing us to add new shapes to our program without having to modify the existing code. This approach applies polymorphism and makes our code more flexible and extensible as the number of shapes increases. Here is a code example on how to implement this.

public abstract class Shape {
public abstract void draw();
}

public class Rectangle extends Shape {
public void draw() {
System.out.println("Drawing a rectangle...");
// Code to draw a rectangle
}
}

public class Square extends Shape {
public void draw() {
System.out.println("Drawing a square...");
// Code to draw a square
}
}

public class Circle extends Shape {
public void draw() {
System.out.println("Drawing a circle...");
// Code to draw a circle
}
}

public class DrawingShapes {
public static void main(String[] args) {
Shape[] shapes = {new Rectangle(), new Square(), new Circle()};

for (Shape shape : shapes) {
shape.draw();
}
}
}

The DrawingShapes class is used to illustrate a program that draws a lot of different shapes using only one function which is shape.draw().

Special credits

I would like to give special credits to chatGPT for helping me generate a lot of the code examples it really made writing this article a whole lot easier :)

--

--

Omar Emad
CodeX

Hey, I am a technical project manager for a react native project, also I work as a flutter developer. Hope you find my articles insightful !