Objota O mundo orientado a objetos

Simulando herança em JavaScript

Posted on fevereiro 14, 2011

Posted by Rodrigo Ireno

Já faz algum tempo que escrevi um artigo de como fazer classes em javascript, porém foi somente uma introdução. Na verdade javascript não é uma linguagem orientada a objetos, ela somente possui alguns recursos que possibilitam simular este conceito de programação.

Se fossemos comparar com todos os recursos que Java (por exemplo) disponibiliza, seria uma completa injustiça, pois atende em peso este conceito. Enquanto javascript sustenta-se apenas com functions, prototipagem e alguns métodos especiais.

Mesmo assim consegue simular uma série de conceitos da orientação a objetos, como:

  • Estruturas de objeto
  • Herança de atributos e métodos – (entre functions)

E pode acreditar, com isso já dá pra fazer muita coisa. Então mão na massa.

Existem várias formas de se fazer esta simulação, mas vou mostrar os métodos que prefiro usar, pois demonstra ter mais organização.

Herança via métodos call e apply

Call:

call( objeto, argumento1, argumento2, argumento3)

Apply:

apply( objeto, ArrayDeArgumentos )

Ambos os métodos trabalham de forma igual, o que eles fazem é trazer o contexto do objeto chamado para dentro do seu objeto atual, não entendeu?.  Vendo é mais fácil!

function Pai( nome, sobreNome){
 this.nome = nome;
 this.sobreNome = sobreNome;
}

function Filho(nome, sobrenome, idade){

 //call chama construtor do objeto Pai
 Pai.call(this, nome, sobrenome);

 this.idade = idade;

 this.mostra = function(){
 alert("Nome completo: "+this.nome+" "+this.sobreNome+"\nIdade: "+this.idade);
 };
}

var objota = new Filho("Maria", "Bonita", 35);

objota.mostra();

Veja que neste exemplo o que fiz foi chamar o construtor do objeto Pai, utilizando a função call. E veja que passei os parâmetros nome e sobrenome.

Agora vejamos este outro exemplo utilizando o método apply. Prefiro esse pois você escreve menos! Hehehe.


function Pai( nome, sobrenome){
 this.nome = nome;
 this.sobreNome = sobrenome;
}

function Filho(nome, sobrenome, idade){

 //apply chama construtor do objeto Pai
 Pai.apply(this, arguments);

 //também pode ser:
 //Pai.apply(this, new Array(nome, sobrenome));

 this.idade = idade;

 this.mostra = function(){
 alert("Nome completo: "+this.nome+" "+this.sobreNome+"\nIdade: "+this.idade);
 };
}

var objota = new Filho("Maria", "Bonita", 35);

objota.mostra();

Como vimos anteriormente o método apply recebe um array com os argumentos, certo. Então. A grande vantagem dele é que podemos utilizar a propriedade arguments herdada do objeto global (que todo objeto em javascript possui). Ele é um array justamente com todos os argumentos necessários para a construção do objeto pai. A única vantagem é a facilidade de implementação caso o objeto em questão tenha muitos argumentos. Você escreve bem menos.

Estes métodos pra mim já dão conta do recado, se você quiser se aprofundar um pouco mais aqui vai pelo menos os nomes dos outros métodos utilizados.

Herança via Object masquerading

Herança via Prototype

Multipla herança

É isso galera, até a próxima. E qualquer coisa comente aí.

Herança e Polimorfismo

Posted on julho 30, 2010

Posted by Rodrigo Ireno

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. 🙂