Menu
Coddy logo textTech

Composição vs Herança

Parte da seção Programação Orientada a Objetos do Journey de PHP da Coddy — lição 56 de 91.

No capítulo anterior, você aprendeu que traits fornecem uma capacidade "tem-um" (has-a) enquanto a herança estabelece uma relação "é-um" (is-a). A Composição leva o conceito "tem-um" adiante ao construir objetos complexos a partir de objetos mais simples, armazenando-os como propriedades em vez de herdar deles.

Com herança, um Car pode estender Vehicle. Com composição, um Car contém um objeto Engine:

<?php
class Engine {
    public function start(): string {
        return "Engine started";
    }
}

class Car {
    private Engine $engine;
    
    public function __construct() {
        $this->engine = new Engine();
    }
    
    public function start(): string {
        return $this->engine->start();
    }
}

$car = new Car();
echo $car->start();

Saída:

Engine started

A classe Car não herda de Engine - ela possui um. Esta abordagem oferece vantagens significativas: você pode trocar o motor por uma implementação diferente, as classes permanecem fracamente acopladas e você evita as hierarquias rígidas que a herança profunda cria.

Uma diretriz comum em POO é "prefira a composição em vez da herança." A herança funciona bem para hierarquias de tipos genuínas (um Dog é verdadeiramente um Animal), mas a composição brilha quando você está montando funcionalidades a partir de partes independentes. Você pode combinar múltiplos objetos, substituí-los em tempo de execução e testar componentes isoladamente.

A próxima lição explora a injeção de dependência, que se baseia diretamente na composição ao controlar como os objetos recebem suas dependências.

challenge icon

Desafio

Fácil

Vamos construir um sistema de computador usando composição, onde um Computer é montado a partir de objetos componentes separados em vez de herdar deles. Isso demonstra como a composição permite construir objetos complexos a partir de partes simples e independentes.

Você organizará seu código em três arquivos:

  • Processor.php — Crie uma classe Processor que representa uma CPU. Use a promoção de construtor para definir um $model (string) privado e um $cores (inteiro) privado. Adicione um método getSpecs() que retorna "{$this->model} ({$this->cores} cores)".
  • Memory.php — Crie uma classe Memory que representa a RAM. Use a promoção de construtor para definir um $size (inteiro representando GB) privado. Adicione um método getCapacity() que retorna "{$this->size}GB RAM".
  • main.php — Inclua ambos os arquivos de componentes e crie uma classe Computer que utiliza composição. O Computer deve:
    • Armazenar um objeto Processor e um objeto Memory como propriedades privadas
    • Aceitar um modelo de processador, contagem de núcleos e tamanho de memória em seu construtor
    • Criar os objetos componentes internamente durante a construção
    • Ter um método describe() que retorna "Computer with " . $this->processor->getSpecs() . " and " . $this->memory->getCapacity()

    Você receberá três entradas: um modelo de processador, um número de núcleos e um tamanho de memória em GB. Crie um Computer com essas especificações e imprima o resultado da chamada de describe().

Observe como o Computer não estende Processor ou Memory — ele os contém. Esse relacionamento "tem-um" através da composição mantém cada componente independente e reutilizável, permitindo que o Computer delegue tarefas às suas partes quando necessário.

Folha de consulta

A composição constrói objetos complexos a partir de objetos mais simples, armazenando-os como propriedades em vez de herdar deles. Isso cria um relacionamento do tipo "tem um" (has-a), onde uma classe contém instâncias de outras classes.

Exemplo básico de composição:

<?php
class Engine {
    public function start(): string {
        return "Engine started";
    }
}

class Car {
    private Engine $engine;
    
    public function __construct() {
        $this->engine = new Engine();
    }
    
    public function start(): string {
        return $this->engine->start();
    }
}

A classe Car não herda de Engine - ela possui uma. Isso mantém as classes fracamente acopladas e evita hierarquias de herança rígidas.

Prefira a composição à herança: A herança funciona bem para hierarquias de tipos genuínas (um Dog é um Animal), mas a composição brilha ao montar funcionalidades a partir de partes independentes. Você pode combinar múltiplos objetos, substituí-los em tempo de execução e testar componentes isoladamente.

Experimente você mesmo

<?php
require_once 'Processor.php';
require_once 'Memory.php';

class Computer
{
    // TODO: Definir propriedades privadas para armazenar objetos Processor e Memory

    // TODO: O construtor deve aceitar o modelo do processador, contagem de núcleos e tamanho da memória
    // e criar os objetos dos componentes internamente
    public function __construct()
    {
        // TODO: Criar objetos Processor e Memory e armazená-los
    }

    // TODO: Implementar o método describe() que retorna
    // "Computer with [processor specs] and [memory capacity]"
    public function describe(): string
    {
        // TODO: Delegar para os objetos componentes e retornar a string formatada
    }
}

// Ler entrada
$processorModel = trim(fgets(STDIN));
$cores = intval(fgets(STDIN));
$memorySize = intval(fgets(STDIN));

// TODO: Criar um Computer com as especificações fornecidas e imprimir o resultado de describe()

?>
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos