Objota O mundo orientado a objetos

Herança e Polimorfismo

Posted on julho 30, 2010

Herança

Herança em orientação a objetos é algo simples de se entender, pois assim como um filho herda características do pai uma classe também herda características de uma superclasse. A superclasse pode ser uma classe pai, avô ou bisavô.

Enfim a superclasse vem antes da classe atual. E assim como em uma arvore genealógica uma superclasse pode ser uma subclasse de alguém, e assim sucessivamente.

Então, assim como um filho que herda os olhos do pai, uma classe herda atributos de sua super classe. E assim como (desconsidero as especulações científicas) um filho herda o temperamento e algumas atitudes do pai, uma classe herda métodos de sua super classe.

Mais que herdar atributos e métodos de uma classe para outra, existe uma real vantagem nisso tudo. Reaproveitamento de código! Afinal se já programei um método que faz exatamente isso na superclasse, pra que fazer isso outra vez? Minha classe irá herdar estes métodos e atributos! Entenderam? É simples o entendimento deste conceito, porém muito mais difícil é aplicá-lo. Mas isso fica por conta das camadas mais altas. Analistas, Engenheiros e Arquitetos de software.

Para programar em php uma classe que herda atributos e métodos de uma superclasse é muito simples. Basta usar a palavra chave "extends"

Ex: classeFilho extends classePai. Isso fica lá em cima na assinatura da classe. Veja um exemplo abaixo:


<?php
class Automovel{
	private $numeroPlaca;
	private $numeroDeRodas;

	public function Automovel($Placa, $nRodas){
		$this->setNumeroPlaca($Placa);
		$this->setNumeroDeRodas($nRodas);
	}

	public function setNumeroPlaca($novaPlaca){
		if($novaPlaca > 999 && $novaPlaca <= 9999)
		$this->numeroPlaca = $novaPlaca;
	}
	public function setNumeroDeRodas($novoNumeroRodas){
		if($novoNumeroRodas > 0)
		$this->numeroDeRodas = $novoNumeroRodas;
	}

	public function getNumeroPlaca(){
		return $this->numeroPlaca;
	}
	public function getNumeroDeRodas(){
		return $this->numeroDeRodas;
	}

}

class Carro extends Automovel{

	private $modelo;

	public function Carro($Placa, $nRodas, $modelo){
		parent::Automovel($Placa, $nRodas);
		$this->setModelo($modelo);
	}

	public function setModelo($nomeModelo){
		$this->modelo = $nomeModelo;
	}
	public function getModelo(){
		return $this->modelo;
	}

}

$obj = new Carro(8945,4,"Phusca");

echo "Modelo : {$obj->getModelo()}<br/>
	  Placa : {$obj->getNumeroPlaca()}<br/>
	  Rodas : {$obj->getNumeroDeRodas()}<br/>";

?>

Como visto no exemplo acima, a classe Carro "extend", ou seja, ela se estende a classe Automovel. Herdando atributos comuns a qualquer automóvel, veja que para elaborar uma estrutura de classes desta forma é preciso analisar bem o problema.

Repare que instanciei no final um objeto do tipo Carro e ele chama pelo método getNumeroPlaca() e getNumeroDeRodas(), sendo que ambos foram implementados na superclasse Automovel.

Nas duas classes ao declarar os atributos, utilizei private, pois isso deixa com um baixo grau de acoplamento. Porém em algumas circunstancias é necessário que uma subclasse “veja” atributos da superclasse, como se fosse public. Para isso declare como protected então esses atributos serão visíveis somente para a classe herdeira. Vide exemplo, com as mesmas classes:


<?php
class Automovel{
	protected $numeroPlaca;
	protected $numeroDeRodas;

	public function Automovel($Placa, $nRodas){
		$this->setNumeroPlaca($Placa);
		$this->setNumeroDeRodas($nRodas);
	}

	public function setNumeroPlaca($novaPlaca){
		if($novaPlaca > 999 && $novaPlaca <= 9999)
		$this->numeroPlaca = $novaPlaca;
	}
	public function setNumeroDeRodas($novoNumeroRodas){
		if($novoNumeroRodas > 0)
		$this->numeroDeRodas = $novoNumeroRodas;
	}

	public function getNumeroPlaca(){
		return $this->numeroPlaca;
	}
	public function getNumeroDeRodas(){
		return $this->numeroDeRodas;
	}

}

class Carro extends Automovel{

	private $modelo;

	public function Carro($Placa, $nRodas, $modelo){
		//parent::Automovel($Placa, $nRodas);

		//Atributos da superclasse visíveis somente dentro da classe Carro
		$this->numeroPlaca = $Placa;
		$this->numeroDeRodas = $nRodas;

		//Isto é da clase Carro
		$this->setModelo($modelo);
	}

	public function setModelo($nomeModelo){
		$this->modelo = $nomeModelo;
	}
	public function getModelo(){
		return $this->modelo;
	}

}

$obj = new Carro(8945,4,"Phusca");

echo "Modelo : {$obj->getModelo()}<br/>
	  Placa : {$obj->getNumeroPlaca()}<br/>
	  Rodas : {$obj->getNumeroDeRodas()}<br/>";

?>

Polimorfismo

Junto com esse conceito de herança está vinculado algo muito útil. O polimorfismo. A própria palavra já explica um pouco: polimorfismo (muitas formas) aqui está uma idéia bacana, um objeto genérico que pode em qualquer momento assumir uma forma específica. Muito útil quando você não sabe que objeto vem por aí.

Por exemplo, um método que recebe um objeto por parâmetro que pode variar entre alguns tipos. Se você não tem certeza do que vem aí, por que colocar algo específico. Coloque algo genérico!

Como? Veja, agora teremos um terceiro objeto Moto e um objeto de exemplo por nome de Exemplo, que irá executar toda a história:


<?php
class Automovel{
	private $numeroPlaca;
	private $numeroDeRodas;

	public function Automovel($Placa, $nRodas){
		$this->setNumeroPlaca($Placa);
		$this->setNumeroDeRodas($nRodas);
	}

	public function setNumeroPlaca($novaPlaca){
		if($novaPlaca > 999 && $novaPlaca <= 9999)
		$this->numeroPlaca = $novaPlaca;
	}
	public function setNumeroDeRodas($novoNumeroRodas){
		if($novoNumeroRodas > 0)
		$this->numeroDeRodas = $novoNumeroRodas;
	}

	public function getNumeroPlaca(){
		return $this->numeroPlaca;
	}
	public function getNumeroDeRodas(){
		return $this->numeroDeRodas;
	}

}

class Carro extends Automovel{

	private $modelo;

	public function Carro($Placa, $nRodas, $modelo){
		parent::Automovel($Placa, $nRodas);
		$this->setModelo($modelo);
	}

	public function setModelo($nomeModelo){
		$this->modelo = $nomeModelo;
	}
	public function getModelo(){
		return $this->modelo;
	}

}

class Moto extends Automovel{

	private $modelo;

	public function Moto($Placa, $nRodas, $modelo){
		parent::Automovel($Placa, $nRodas);
		$this->setModelo($modelo);
	}

	public function setModelo($nomeModelo){
		$this->modelo = $nomeModelo;
	}
	public function getModelo(){
		return $this->modelo;
	}

}

class Exemplo{
	private $objetoGenerico;

	/*
		Veja! Declaro no parâmentro que aceito
		um objeto do tipo Automovel, assim posso
		receber tanto um objeto Carro como um Moto
	 */
	public function Exemplo( Automovel $obj){
		$this->setObjetoGenerico($obj);
	}

	public function setObjetoGenerico(Automovel $novoObj){
		$this->objetoGenerico = $novoObj;
	}

	public function Mostra(){
		if($this->objetoGenerico !== NULL){
			echo "Modelo : {$this->objetoGenerico->getModelo()}<br/>
				  Placa : {$this->objetoGenerico->getNumeroPlaca()}<br/>
			  	  Rodas : {$this->objetoGenerico->getNumeroDeRodas()}<br/><br/>";
		}
	}
}

//objeto do tipo carro
$carro = new Carro(9999,4,"Phusca");

//objeto do tipo moto
$moto = new Moto(4444,2,"Ronda");

$exemplo = new Exemplo($carro);

//mostra dados do carro
$exemplo->Mostra();

//muda de objeto
$exemplo->setObjetoGenerico($moto);

//mostra dados da Moto
$exemplo->Mostra();

?>

Veja que fantástica é essa organização! Como eu disse mais difícil do que compreender herança e polimorfismo é aplicá-lo. Mas isso já é outra história, este artigo fica por aqui e até a próxima meus caros. Dúvidas? Postem a vontade.

próximo artigo: Vamos voltar a falar de conexão com banco de dados, desta vez usando um objeto. 🙂

Posted by Rodrigo Ireno

Comentários (2) Trackbacks (1)
  1. Compreendi direitinho com suas analogias, parabéns.

  2. Rodrigo Iremo, seu conceito de polimorfismo é errôneo. Deves ter te confundido com os conceitos. Em seu exemplo você descreveu uma agregação e não polimorfismo. Por favor, corrijam-me se estiver errado.


Leave a comment