Nesta lição, exploraremos o mundo dos Objetos em Programação Orientada a Objetos (OOP) e examinaremos mais de perto como eles formam a base da OOP.

Os objetos são as entidades tangíveis que englobam dados e comportamentos, permitindo-nos representar e interagir com conceitos do mundo real em nosso software. Entender o conceito de objetos é essencial para aproveitar o poder e a flexibilidade da OOP.

Ao longo desta lição, aprenderemos sobre os princípios fundamentais dos objetos, como criá-los e manipulá-los e como eles contribuem para a construção de sistemas de software modulares e escaláveis.

Instância em OOP

Na Programação Orientada a Objetos (OOP), uma instância é uma ocorrência individual de uma classe. Em outras palavras, quando você cria um objeto de uma classe, o objeto resultante é uma instância dessa classe.

Por exemplo, digamos que temos uma classe chamada Car que define os atributos e métodos para um carro. Quando criamos um novo carro objeto, estamos criando, instanciando uma da classe “Car”. Cada objeto de carro individual que criamos terá seu próprio conjunto exclusivo de valores de atributo, mas compartilhará o mesmo conjunto de métodos definidos na classe Car.

Instanciar um objeto significa criar uma ocorrência, única, de uma classe. Isso é feito usando a palavra-chave new na maioria das linguagens de programação. Quando criamos um novo objeto, estamos essencialmente criando uma cópia da classe com seu próprio conjunto exclusivo de valores de atributo. Isso nos permite criar vários objetos da mesma classe, cada um com seu próprio conjunto único de características.

Classe Chave
Classe Chave e os objetos criados a partir dela, objetos de chave

No exemplo acima, o molde de uma chave representa para nós uma Classe Key. E as chaves, nomeadas como k1 e k2, representam nossas instâncias do tipo de classe Key. Você pode ver nesta imagem que a classe (molde) não tem atributos, não tem uma cor ou um peso, nem mesmo qualquer comportamento, o molde não pode abrir uma porta. Mas os objetos-chave criados a partir dele possuem atributos, como cor, peso e podem realizar o comportamento de abrir uma porta.

De volta ao mundo do software, uma vez que tenhamos instanciado um objeto, podemos interagir com ele usando os métodos definidos na classe. Por exemplo, se tivermos instanciado um objeto de Car (Carro), podemos chamar métodos como start (ligar), speedUp (acelerar), slowDown (desacelerar) para fazer o carro executar essas ações. Isso nos permite criar código modular e reutilizável e modelar cenários complexos do mundo real com facilidade.

É importante entender que cada instância, ou cada objeto criado a partir de uma classe é único, mesmo que todos os valores de atributos para um conjunto de objetos sejam os mesmos. Pegue novamente o exemplo da classe Key, os objetos key (chaves criadas a partir do molde) podem ter a mesma cor e peso, mas não são o mesmo objeto. Assim, eles podem ter os mesmos valores de atributo, mas ainda assim, cada um tem sua própria identificação única.

Aqui está um exemplo que demonstra a instanciação de dois objetos criados a partir da classe Car, com os métodos start``, speedUp e slowDown. Cada objeto terá um atributo licensePlate (placa).

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();

A saída seria:

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();

A saída seria:

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

Diferenças entre classes e objetos na OOP

Para consolidar o que aprendemos em “Introdução às Classes em OOP” e nesta lição, em Programação Orientada a Objetos (OOP), classes e objetos são conceitos fundamentais, mas servem para diferentes propósitos.

Uma classe é um blueprint (projeto), um template ou um molde que define a estrutura e o comportamento dos objetos. Ela encapsula os atributos e métodos comuns que objetos do mesmo tipo terão. Em outras palavras, uma classe pode ser pensada como um modelo para a criação de objetos. Ela especifica quais dados os objetos armazenarão (atributos) e quais ações eles podem executar (métodos). As classes são reutilizáveis e fornecem uma maneira de criar várias “instâncias” de objetos com características semelhantes. Elas atuam como um projeto a partir do qual os objetos são instanciados.

É nas classes que todo o código é escrito

Por outro lado, um objeto é uma instância de uma classe. É uma representação concreta da classe, criada usando o modelo fornecido pela classe. Um objeto representa uma entidade ou instância específica no sistema e tem seu único conjunto de valores de atributo. Ele pode interagir com outros objetos e executar ações definidas pelos métodos de classe. Os objetos têm seus próprios estado, comportamento, e identidade. Eles podem armazenar dados em seus atributos e invocar métodos para executar ações nesses dados.

Objetos são instâncias concretas de classes que mantêm valores em suas variáveis (atributos) e executam o código criado em classes.

Em resumo, uma classe define a estrutura geral e o comportamento de objetos, enquanto um objeto é uma instância específica criada a partir de uma classe, com seu próprio conjunto de valores de atributo e a capacidade de executar ações definidas pela classe. As classes servem como blueprints, enquanto os objetos são as entidades concretas que são criadas com base nesses blueprints.

Olhe para esta representação gráfica de um possível projeto de carro (semelhante à nossa classe de Car), e todos os objetos de carro criados a partir desse projeto. Todas as especificações estão no projeto, mas os objetos são as manifestações concretas dele. Preste atenção, mais uma vez, que mesmo que todos os carros sejam parecidos, alguns deles até idênticos em termos de seus atributos e comportamento (ações que podem executar), ainda assim cada um é único.

Projeto do carro e seus objetos
Projeto do carro e seus objetos (carros criados a partir do projeto)

Identificando classes e instanciando objetos em domínios reais

Em domínios reais (regras de negócios), você precisará abstrair as estruturas de classes de descrições de usuário, amostras de planilhas e relatórios, documentos e outras fontes de informação do negócio.

Vamos ver um exemplo simples sobre uma abstração orientada a objeto de um documento de fatura (invoice).

Considere a seguinte fatura:

Exemplo de fatura

A partir da imagem é possível identificar essas informações:

  • Número da fatura: INV-00001
  • Nome do cliente: John Doe
  • Endereço do cliente: 123 Main Street, Anytown, CA 12345
  • Data da fatura: 2023-08-02
  • Itens da fatura:
    • Item 1: PHP Advanced Course, quantidade 1, preço $100
    • Item 2: OOP Theory eBook, quantidade 1, preço $75
    • Item 3: Engenharia de Software Mentoring, quantidade 5, preço $45
  • Valor total da fatura: $400

Modelando isso para OOP podemos extrair as seguintes classes e seus atributos:

  • Classe Invoice: Esta classe representa a própria fatura. Ele tem atributos para o número da fatura, nome do cliente, endereço do cliente, data da fatura e itens da fatura. Ele também tem métodos para calcular o valor total da fatura e imprimir a fatura.
  • Classe Item: Esta classe representa um item na fatura. Ele tem atributos para o nome do item, quantidade e preço.

Representando as classes em código de software

Aqui estão alguns exemplos simples de como implementar as classes no código de software.

A classe Invoice tem métodos para calcular o valor total da fatura e imprimir a fatura. A classe Item tem atributos para o nome do item, quantidade e preço.

Observe que qualquer valor pode ser usado para as propriedades, pois as informações de domínio são usadas apenas para fins de modelagem. Ao criar objetos a partir desses modelos (classes), você é livre para definir qualquer valor necessário no contexto do software resultante.

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

Criando objetos e interagindo com:

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();
    }
}

Os exemplos mostrados neste post são apenas algumas das muitas maneiras pelas quais classes e objetos podem ser usados em software. À medida que você continuar a aprender sobre OOP, você descobrirá muitas outras maneiras de usar esses conceitos para criar software poderoso e reutilizável.

Aqui estão algumas considerações adicionais sobre classes e objetos:

  • Classes e objetos são uma poderosa abstração que pode ser usada para representar e interagir com objetos do mundo real.
  • Classes e objetos podem ser usados para criar software reutilizável que é fácil de manter e estender.
  • Existem muitas maneiras diferentes de implementar classes e objetos no código de software.
  • A melhor maneira de aprender sobre classes e objetos é praticar o uso deles.