2006-09-17 05:34:55
tags: 

O Zen e a arte cavalheiresca da programação orientada a objeto (Parte 6)

(Para ver todas as partes desta série clique aqui)

Olá, pessoal, já estamos aqui de volta para falar mais um pouquinho sobre OOP, PHP, e outras siglas igualmente ininteligíveis. Hoje quero falar sobre um tema que sempre gera muita confusão: interfaces. E, é claro, não podemos falar de interface sem olhar a etimologia dessa palavra.

O prefixo inter- vem da preposição latina inter, que significa "entre, no meio de". A palavra face, também de origem latina (fascia), significa "camada externa". Juntando as duas coisas, temos um termo genérico que significa praticamente qualquer coisa em tecnologia. Temos interfaces gráficas, interfaces com o usuário, interfaces RS232, interfaces usb, e por aí vai.

O conceito denominado de interface em OOP é bastante diferente disso tudo. No nosso mundo imaginário de carros, superpoderes, gnomos e outras criaturas fantásticas orientadas a objeto, interfaces são simplesmente definições padronizadas de acesso a funções que estão dentro das classes que as implementam. Falando assim parece bem complicado, mas não é não. Na verdade, na verdade, se a gente olhar com muito cuidado, nós de fato já usamos o conceito de interface aqui mesmo nos artigos anteriores.

Explico: quando nós criamos uma classe, estamos criando também uma interface. Lembra que nós construímos dois carros, um FiatUno e uma FerrariF1, e ambos podiam ->acelerar() ? Justamente! Ajoelhe-se diante do poder das interfaces!

Ao estender a classe Automovel para criar a classe FiatUno e a classe FerrariF1 nós estamos automaticamente implementando a interface usada na classe automóvel nas duas. Assim, temos absoluta certeza que todas as classes-filhas da classe Automovel vão poder ->acelerar(). Esse é exatamente o conceito de interface: a padronização do acesso aos dados e funções de uma classe ou objeto.

Mas o que é realmente interessante é que algum desses gênios malucos que inventaram os conceitos de OOP acordou um belo dia e teve uma idéia brilhante: "Perai, mas eu não preciso ter que criar classes-filhas toda hora pra usar uma interface!". Nasciam as palavras-chave interface e implements, que permitem a criação de interfaces que podem ser usadas entre classes que não tem nenhum parentesco entre si.

E eu estou aqui para provar tudo isso implementando Superpoderes em Automóveis! Você há de concordar que um Automovel não tem nada a ver com um SerHumano, já que eles não têm nenhum parentesco. Como ter certeza que essas classes e todos os seus filhos possam usar objetos da classe SuperPoder de forma padronizada? É fácil:

Primeiro, criamos a interface SuperHeroi:

 interface SuperHeroi {
    public function ativar(SuperPoder $superpoder);
} 

Bom, como você pode notar, a função ativar só vai funcionar se você mandar pra ela o SuperPoder desejado durante a chamada da função. Se mandar texto, número ou qualquer outra coisa vai ganhar um erro de presente.

Agora vamos alterar nossas classes Automovel e SerHumano para implementar a interface SuperHeroi:

Class SerHumano implements SuperHeroi { 	
    public $nome;
    public $vivo; 	
    public function __construct($nome) {
        $this->nome = $nome;
        $this->vivo = true;  	
    }
    public function taVivo() { 
        if($this->vivo == true) {             		
            print "Sim, eu estou vivo, e meu nome é $this->nome!"; 	
        } else {             	
            print "..."; 	
        }  	
    }
    public function ativar(SuperPoder $superpoder){
        $superpoder->ativar()
    }
} 

e agora a classe Automovel:

 abstract class Automovel implements SuperHeroi {
     public $aceleracao;
     public $velocidade_atual;
     public $cor;

     public function acelerar() {
        $this->velocidade_atual = $this->velocidade_atual + $this->aceleracao;
        print "Acelerando! Agora a velocidade é de " . $this->velocidade_atual . "Km/h!";
     }    
    public function ativar(SuperPoder $superpoder){
        $superpoder->ativar();
    }
 }

 

Agora, tanto os objetos SerHumano quanto objetos da classe Automovel (incluindo aqueles das classes FiatUno e FerrariF1, já que pela herança um FiatUno ou uma FerrariF1 sempre têm todas as propriedades e funções da classe Automovel) já podem ->ativar() um SuperPoder. Como a classe SuperPoder é abstrata e ninguém consegue ativar um SuperPoder abstrato, vou ativar a SuperForca:

$meucarro = new FerrariF1('vermelha'); 
$meucarro->ativar(new SuperForca);
// Meu deus, posso levantar um caminhão! 

E os gnomos, você deve estar se perguntando. Eles virão... Eles virão...