In this lesson, we will explore the world of Objects in Object-Oriented Programming (OOP), and take a closer look at how they form the foundation of OOP.

Objects are the tangible entities that encompass both data and behaviors, allowing us to represent and interact with real-world concepts in our software. Understanding the concept of objects is essential for harnessing the power and flexibility of OOP.

Throughout this lesson, we will learn about the fundamental principles of objects, how to create and manipulate them, and how they contribute to building modular and scalable software systems.

Instance in OOP

In Object-Oriented Programming (OOP), an instance is an individual occurrence of a class. In other words, when you create an object from a class, the resulting object is an instance of that class.

For example, let’s say we have a class called Car that defines the attributes and methods for a car. When we create a new car object, we are instantiating an instance of the “Car” class. Each individual car object that we create will have its own unique set of attribute values, but will share the same set of methods defined in the Car class.

To instantiate an object means to create a new instance of a class. This is done by using the new keyword in most programming languages. When we create a new object, we are essentially creating a copy of the class with its own unique set of attribute values. This allows us to create multiple objects from the same class, each with its own unique set of characteristics.

Key Class
Key Class

In the above example, the mold of a key represents for us a Key Class. And the keys, named as k1 and k2, represents our instances the type of Key class. You can see in this image that the class (mold) doesn’t have atributes, it don’t have a color or a weight, not even any behavior, the mold can’t open a door. But the key objects created from it do have attributes, as color, weight and can perform the behavior of open a door.

Back to software world, once we have instantiated an object, we can interact with it using the methods defined in the class. For example, if we have instantiated a car object, we can call methods like start, speedUp, slowDown to make the car perform those actions. This allows us to create modular and reusable code, and to model complex real-world scenarios with ease.

It’s important to understand that each instance, or each object created from a class is unique, even if all attributes values for a set of objects are the same. Take again the Key class example, the key objects could have the same color and weight but they are not the same object. So, they can have the same attribute values but still, each one has it’s own unique identification.

Here’s an example in that demonstrates the instantiation of two objects created from Car class, with the methods start, speedUp, and slowDown. Each object will have an attribute licensePlate.

class Car {
  public $licensePlate;

  public function start() {
    echo "Starting the car with license plate: " . $this->licensePlate . "\n";
  }

  public function speedUp() {
    echo "Speeding up the car with license plate: " . $this->licensePlate . "\n";
  }

  public function slowDown() {
    echo "Slowing down the car with license plate: " . $this->licensePlate . "\n";
  }
}

// Create two car objects
$car1 = new Car();
$car1->licensePlate = 'ABC123';
$car2 = new Car();
$car2->licensePlate = 'XYZ789';

$car1->start();
$car2->start();
$car2->speedUp();
$car1->speedUp();
$car1->slowDown();
$car1->speedUp();
$car2->slowDown();

The output would be:

Starting the car with license plate: ABC123
Starting the car with license plate: XYZ789
Speeding up the car with license plate: XYZ789
Speeding up the car with license plate: ABC123
Slowing down the car with license plate: ABC123
Speeding up the car with license plate: ABC123
Slowing down the car with license plate: XYZ789
class Car {
    constructor() {
        this.licensePlate = '';
    }

    start() {
        console.log(`Starting the car with license plate: ${this.licensePlate}`);
    }

    speedUp() {
        console.log(`Speeding up the car with license plate: ${this.licensePlate}`);
    }

    slowDown() {
        console.log(`Slowing down the car with license plate: ${this.licensePlate}`);
    }
}

// Create two car objects
const car1 = new Car();
car1.licensePlate = 'ABC123';
const car2 = new Car();
car2.licensePlate = 'XYZ789';

car1.start();
car2.start();
car2.speedUp();
car1.speedUp();
car1.slowDown();
car1.speedUp();
car2.slowDown();

The output would be:

Starting the car with license plate: ABC123
Starting the car with license plate: XYZ789
Speeding up the car with license plate: XYZ789
Speeding up the car with license plate: ABC123
Slowing down the car with license plate: ABC123
Speeding up the car with license plate: ABC123
Slowing down the car with license plate: XYZ789

Differences between Classes and Objects on OOP

To consolidate what we have learned on “Introduction to Classes on OOP” and this lesson, in Object-Oriented Programming (OOP), classes and objects are fundamental concepts, but
they serve different purposes.

A class is a blueprint, a template or a mold that defines the structure and behavior of objects. It encapsulates the common attributes and methods that objects of the same type will have. In other words, a class can be thought of as a blueprint for creating objects. It specifies what data the objects will hold (attributes) and what actions they can perform (methods). Classes are reusable and provide a way to create multiple “instances” of objects with similar characteristics. They act as a project from which objects are instantiated.

It is in the classes that all code is writen

On the other hand, an object is an instance of a class. It is a concrete representation of the class, created using the blueprint provided by the class. An object represents a specific entity or instance in the system and has its own unique set of attribute values. It can interact with other objects and perform actions defined by the class methods. Objects have their own state, behavior, and identity. They can hold data in their attributes and invoke methods to perform actions on that data.

Objects are concrete instances of classes that hold values in their variables (attributes) and execute the code created in classes.

In summary, a class defines the general structure and behavior of objects, whereas an object is a specific instance created from a class, with its own set of attribute values and the ability to perform actions defined by the class. Classes serve as blueprints, while objects are the concrete entities that are created based on those blueprints.

Look at this graphical representation of a possible car blueprint (similar to our Car class), and all the car objects created from that blueprint. All specifications are in the blueprint, but the objects are the concrete manifestations of it. Pay attention, once again, that even though all the cars look similar, some of them are identical in terms of their attributes and behavior (actions that they can perform), while each one is unique.

Car blueprint and its objects
Car blueprint and its objects

Identifying Classes and Instantiating Objects on real domains

On real domains (business rules), you gonna need to abstratct the classes structures from user descriptions, sheet and report samples, documents and other sources.

Let’s see a simple example on an object oriented abstraction from an invoice document.

Consider the following invoice:

Invoice Sample

From the image er can identify this pieces of information:

  • Invoice number: INV-00001
  • Customer name: John Doe
  • Customer address: 123 Main Street, Anytown, CA 12345
  • Invoice date: 2023-08-02
  • Invoice items:
    • Item 1: PHP Advanced Course, quantity 1, price $100
    • Item 2: OOP Theory eBook, quantity 1, price $75
    • Item 3: Software Engineering Mentoring, quantity 5, price $45
  • Total invoice amount: $400

Modeling this to OOP we canextract the following classes and they attributes:

  • Invoice class: This class represents the invoice itself. It has attributes for the invoice number, customer name, customer address, invoice date, and invoice items. It also has methods for calculating the total invoice amount and printing the invoice.
  • Item class: This class represents an item on the invoice. It has attributes for the item name, quantity, and price.

Representing the classes in software code

Here are some simple examples of how to implement the classes in software code.

The Invoice class has methods for calculating the total invoice amount and printing the invoice. The Item class has attributes for the item name, quantity, and price.

Note that any value can be used for the properties, as the domain information is only used for modeling purposes. When creating objects from these models (classes), you are free to set any value needed in the context of the resultant software.

class Invoice {
    private $invoice_number;
    private $customer_name;
    private $customer_address;
    private $invoice_date;
    private $invoice_items = [];

    public function __construct($invoice_number, $customer_name, $customer_address, $invoice_date, $invoice_items) {
        $this->invoice_number = $invoice_number;
        $this->customer_name = $customer_name;
        $this->customer_address = $customer_address;
        $this->invoice_date = $invoice_date;
        $this->invoice_items = $invoice_items;
    }

    public function calculate_total_amount() {
        $total_amount = 0;
        foreach ($this->invoice_items as $item) {
            $total_amount += $item->quantity * $item->price;
        }
        return $total_amount;
    }

    public function print_invoice() {
        echo "Invoice number: " . $this->invoice_number . "\n";
        echo "Customer name: " . $this->customer_name . "\n";
        echo "Customer address: " . $this->customer_address . "\n";
        echo "Invoice date: " . $this->invoice_date . "\n";
        echo "Invoice items:\n";
        foreach ($this->invoice_items as $item) {
            echo $item->item_name . ", " . $item->quantity . ", " . $item->price . "\n";
        }
        echo "Total invoice amount: " . $this->calculate_total_amount() . "\n";
    }
}

class Item {
    private $item_name;
    private $quantity;
    private $price;

    public function __construct($item_name, $quantity, $price) {
        $this->item_name = $item_name;
        $this->quantity = $quantity;
        $this->price = $price;
    }
}

$invoice = new Invoice(123456, "John Doe", "123 Main Street, Anytown, CA 12345", "2023-03-08", [
    new Item("Product A", 1, 100),
    new Item("Product B", 2, 50),
    new Item("Product C", 3, 25),
]);

$invoice->print_invoice();
class Invoice {
    constructor(invoiceNumber, customerName, customerAddress, invoiceDate, invoiceItems) {
        this.invoiceNumber = invoiceNumber;
        this.customerName = customerName;
        this.customerAddress = customerAddress;
        this.invoiceDate = invoiceDate;
        this.invoiceItems = invoiceItems;
    }

    calculateTotalAmount() {
        let totalAmount = 0;
        for (const item of this.invoiceItems) {
            totalAmount += item.quantity * item.price;
        }
        return totalAmount;
    }

    printInvoice() {
        console.log("Invoice number:", this.invoiceNumber);
        console.log("Customer name:", this.customerName);
        console.log("Customer address:", this.customerAddress);
        console.log("Invoice date:", this.invoiceDate);
        console.log("Invoice items:");
        for (const item of this.invoiceItems) {
            console.log(item.itemName, item.quantity, item.price);
        }
        console.log("Total invoice amount:", this.calculateTotalAmount());
    }
}

class Item {
    constructor(itemName, quantity, price) {
        this.itemName = itemName;
        this.quantity = quantity;
        this.price = price;
    }
}

const invoice = new Invoice(123456, "John Doe", "123 Main Street, Anytown, CA 12345", "2023-03-08", [
    new Item("Product A", 1, 100),
    new Item("Product B", 2, 50),
    new Item("Product C", 3, 25),
]);

invoice.printInvoice();
class Invoice:
    def __init__(self, invoice_number, customer_name, customer_address, invoice_date, invoice_items):
        self.invoice_number = invoice_number
        self.customer_name = customer_name
        self.customer_address = customer_address
        self.invoice_date = invoice_date
        self.invoice_items = invoice_items

    def calculate_total_amount(self):
        total_amount = 0
        for item in self.invoice_items:
            total_amount += item.quantity * item.price
        return total_amount

    def print_invoice(self):
        print("Invoice number:", self.invoice_number)
        print("Customer name:", self.customer_name)
        print("Customer address:", self.customer_address)
        print("Invoice date:", self.invoice_date)
        print("Invoice items:")
        for item in self.invoice_items:
            print(item.item_name, item.quantity, item.price)
        print("Total invoice amount:", self.calculate_total_amount())


class Item:
    def __init__(self, item_name, quantity, price):
        self.item_name = item_name
        self.quantity = quantity
        self.price = price

Creating objects and interacting with then:

invoice = Invoice(123456, "John Doe", "123 Main Street, Anytown, CA 12345", "2023-03-08", [
    Item("Product A", 1, 100),
    Item("Product B", 2, 50),
    Item("Product C", 3, 25),
])

invoice.print_invoice()
class Invoice {
    private int invoiceNumber;
    private String customerName;
    private String customerAddress;
    private String invoiceDate;
    private List<Item> invoiceItems;

    public Invoice(int invoiceNumber, String customerName, String customerAddress, String invoiceDate, List<Item> invoiceItems) {
        this.invoiceNumber = invoiceNumber;
        this.customerName = customerName;
        this.customerAddress = customerAddress;
        this.invoiceDate = invoiceDate;
        this.invoiceItems = invoiceItems;
    }

    public int getInvoiceNumber() {
        return invoiceNumber;
    }

    public String getCustomerName() {
        return customerName;
    }

    public String getCustomerAddress() {
        return customerAddress;
    }

    public String getInvoiceDate() {
        return invoiceDate;
    }

    public List<Item> getInvoiceItems() {
        return invoiceItems;
    }

    public int calculateTotalAmount() {
        int totalAmount = 0;
        for (Item item : invoiceItems) {
            totalAmount += item.getQuantity() * item.getPrice();
        }
        return totalAmount;
    }

    public void printInvoice() {
        System.out.println("Invoice number: " + invoiceNumber);
        System.out.println("Customer name: " + customerName);
        System.out.println("Customer address: " + customerAddress);
        System.out.println("Invoice date: " + invoiceDate);
        System.out.println("Invoice items:");
        for (Item item : invoiceItems) {
            System.out.println(item.getItemName() + ", " + item.getQuantity() + ", " + item.getPrice());
        }
        System.out.println("Total invoice amount: " + calculateTotalAmount());
    }
}

class Item {
    private String itemName;
    private int quantity;
    private int price;

    public Item(String itemName, int quantity, int price) {
        this.itemName = itemName;
        this.quantity = quantity;
        this.price = price;
    }

    public String getItemName() {
        return itemName;
    }

    public int getQuantity() {
        return quantity;
    }

    public int getPrice() {
        return price;
    }
}

public class Main {
    public static void main(String[] args) {
        Invoice invoice = new Invoice(123456, "John Doe", "123 Main Street, Anytown, CA 12345", "2023-03-08",
                Arrays.asList(new Item("Product A", 1, 100), new Item("Product B", 2, 50), new Item("Product C", 3, 25)));

        invoice.printInvoice();
    }
}

The examples shown in this post are just a few of the many ways that classes and objects can be used in software. As you continue to learn about OOP, you will discover many other ways to use these concepts to create powerful and reusable software.

Here are some additional thoughts on classes and objects:

  • Classes and objects are a powerful abstraction that can be used to represent and interact with real-world objects.
  • Classes and objects can be used to create reusable software that is easy to maintain and extend.
  • There are many different ways to implement classes and objects in software code.
  • The best way to learn about classes and objects is to practice using them.