Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

João Batista Neto

1.4.2 Métodos de Interface e Polimorfismo

Recommended Posts

Continuando sobre métodos de interface e polimorfismo, vimos até agora que nossos objetos só conseguem trabalhar uns com os outros através de sua interface, que são os métodos que podem ser vistos, ou seja, só podemos pedir para que um objeto efetue uma operação ou nos forneça alguma informação utilizando-se sua interface

Vimos também que uma interface não serve para "amarrar" nosso código, pelo contrário, serve para remover as dependências de uma implementação.

Mas, o que é remover as dependências de uma implementação ?

Vimos que herança de classes permite compartilhar código, mas imaginem que tenhamos um Pau, um Gato e Eu.

Eu, como uma instância de Pessoa posso jogar alguma coisa em alguma outra coisa, mas vejam, eu como programador, posso assumir o cargo como engenheiro em uma empresa de desenvolvimento de software.

Não existiria qualquer sentido se eu tivesse duas implementações distintas de Eu já que Eu que joga o pau no gato é o mesmo Eu que pode desenvolver uma aplicação.

Polimorfismo é a capacidade de um mesmo objeto de se comportar de diversas formas diferentes ou de objetos totalmente diferentes se comportarem de forma igual.

Vejamos:

interface Projetil {
}

interface Alvo {
public function acerta( Projetil $projetil );
}



Anteriormente, a necessidade de se atirar alguma qualquer coisa em qualquer outra coisa fez com que criássemos as interfaces Projetil e Alvo, com isso passamos a poder jogar, além de pedras em gatos, sapatos em cachorros, mas:

interface Calcavel {
public function mostraNumero();
}



Além de poder jogar um sapato no cachorro, podemos também calçá-lo e, como disse, Eu sou uma Pessoa que posso jogar coisas em outras coisas e ser programador ao mesmo tempo:

interface Pessoa {
public function mostraNome();
public function calca( Calcavel $calcavel );
}

interface Programador {
public function escreveCodigo();
}

interface Atirador {
public function atira( Alvo $alvo );
}



Dessa forma:

class Eu implements Pessoa, Programador, Atirador {
private $calcado;

public function mostraNome(){
echo 'Sou o Neto' , PHP_EOL;

return 'Neto';
}

public function escreveCodigo(){
echo '<?php' , PHP_EOL , 'echo "Polimorfismo é legal.";' , PHP_EOL;
}

public function atira( Alvo $alvo ){
if ( $this->calcado ){
$alvo->acerta( $this->calcado );
} else {
echo 'Estou descalço.' , PHP_EOL;
}
}

public function calca( Calcavel $calcavel ){
$this->calcado = $calcavel;
}
}

class Sapato implements Projetil, Calcavel {
private $numero;

public function __construct( $numero ){
$this->numero = $numero;
}

public function mostraNumero(){
echo 'Sapato número ' , $this->numero , PHP_EOL;
}
}

class Cachorro implements Alvo {
public function acerta( Projetil $projetil ){
echo 'Cain, cain, cain, cain...' , PHP_EOL;
}
}



Vejam que Eu é uma Pessoa mas também um Atirador e um Programador, se eu estiver indo ao trabalho e no caminho encontrar um cachorro:

$eu = new Eu();
$eu->calca( new Sapato( 42 ) );
$eu->atira( new Cachorro() );



Saída:

Cain, cain, cain, cain...


Mas, se eu for até uma empresa:

class Empresa {
public function conversa( Pessoa $pessoa ){
$nome = $pessoa->mostraNome();

echo 'Olá ' , $nome , ', seja bem vindo...' , PHP_EOL;
}

public function contrata( Programador $programador ){
$programador->escreveCodigo();
}
}



O mesmo Eu que anteriormente jogou o próprio sapato no cachorro, pode conversar na Empresa já que além de Atirador, sou também uma Pessoa:

$eu = new Eu();
$empresa = new Empresa();
$empresa->conversa( $eu );



Saída:

 

Sou o Neto
Olá Neto, seja bem vindo...


E ainda, posso trabalhar como programador:

$eu = new Eu();
$empresa = new Empresa();
$empresa->contrata( $eu );



A saída:

 

 

<?phpecho "Polimorfismo é legal.";


Percebam que o objeto Empresa apenas conversa com Pessoa e apenas contrata Programador, como Eu além de Atirador é também uma Pessoa e um Programador, ele pode comportar-se de acordo com a situação, ou seja, o mesmo objeto Eu comporta-se de várias formas diferentes.

Bom, por hoje é só, no próximo artigo da série PHP Orientado a Objetos vamos continuar falando sobre polimorfismo e introduziremos as classes abstratas.

Imagem Postada

 

 

 

Índice Imagem Postada

 

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bom dia João..

 

Primeiramente Parabens pelos posts http://forum.imasters.com.br/public/style_emoticons/default/joia.gif

 

eu to com uma duvida meio noob.. como eu acesso a funçao mostraNumero da class sapato?

você fez:

	$eu->calca( new Sapato( 42 ) );

entao presumi que:

$eu->calca->mostraNumero();

achei q assim funcionaria, mas engano meu =|

 

Notice: Undefined property: Eu::$calca

valeu !

 

[]'s

Compartilhar este post


Link para o post
Compartilhar em outros sites

lmao,

 

A operação mostraNumero() é do sapato e não de Eu, para acessar esse método você precisa referenciar o objeto sapato, por exemplo:

 

$sapato = new Sapato( 42 );
$sapato->mostraNumero();

$eu = new Eu();
$eu->calca( $sapato );
$eu->atira( new Cachorro() );

 

Percebe a diferença ?

 

calca() é um método de Eu, para chamá-lo você deve utilizar como uma função, passando os parâmetros que ela pede e recuperando os valores que ela possivelmente retorna, da mesma forma, mostraNumero() é um método do Sapato e deve ser chamado no objeto $sapato.

 

;)

Compartilhar este post


Link para o post
Compartilhar em outros sites

Hmm

 

entendi..

 

é q achei pelo fato de você colocar um new Sapato no objeto Eu ai poderia acessar os metodos de sapato <_<

 

$eu->calca( new Sapato( 42 ) );)

Hahah

 

valeu ae http://forum.imasters.com.br/public/style_emoticons/default/clap.gif

Compartilhar este post


Link para o post
Compartilhar em outros sites

é q achei pelo fato de você colocar um new Sapato no objeto Eu ai poderia acessar os metodos de sapato

A menos que deixássemos Pessoa->$calcado como public (afinal, qualquer pessoa pode ver o seu calçado).

 

$eu->calcado->mostraNumero()

 

João, esqueceu de definir Pessoa->$calcado como null, depois da função atira(). A menos que você tenha ido buscar o sapato dps =P

Compartilhar este post


Link para o post
Compartilhar em outros sites

João, esqueceu de definir Pessoa->$calcado como null, depois da função atira().

Na verdade, eu acredito que $calcado devesse ser um array de dois índices, um para cada pé do sapato e, cada vez que atirasse, removesse um índice (um pé do calçado).

 

Mas a pergunta seria: Não é errado calca() ser:

 

public function calca( Calcavel $calcavel ) {
   $this -> calcado = array( $calcavel, $calcavel );
}

 

?

Compartilhar este post


Link para o post
Compartilhar em outros sites

é q achei pelo fato de você colocar um new Sapato no objeto Eu ai poderia acessar os metodos de sapato

A menos que deixássemos Pessoa->$calcado como public (afinal, qualquer pessoa pode ver o seu calçado).

 

$eu->calcado->mostraNumero()

 

João, esqueceu de definir Pessoa->$calcado como null, depois da função atira(). A menos que você tenha ido buscar o sapato dps =P

 

 

Lembrei de uma adição aqui:

 

Se o método calca(cacado $calcado) retornasse o objeto que foi calçado, a implementação sugerida pelo daria certo:

 

public function calca(calcavel $calcado){
   $this->calcado = $calcavel;
   return $this->calcado;
}

 

$eu->calca(new Sapato('42'))->mostraNumero();

Compartilhar este post


Link para o post
Compartilhar em outros sites

Na verdade, eu acredito que $calcado devesse ser um array de dois índices, um para cada pé do sapato e, cada vez que atirasse, removesse um índice (um pé do calçado).

 

Mas a pergunta seria: Não é errado calca() ser:

 

public function calca( Calcavel $calcavel ) {
	$this -> calcado = array( $calcavel, $calcavel ); 
}

 

Se o método calca(cacado $calcado) retornasse o objeto que foi calçado, a implementação sugerida pelo daria certo:

 

Ok, respondendo as duas situações em uma única tacada:

 

Martin Fowler descreveu uma vez, uma situação bastante interessante, chamada Fluent Interface.

 

Fluent Interfaces descrevem um encadeamento, onde um método de interface retorna uma referência ao próprio objeto que possui o método chamado, por exemplo:

 

class FluentInterfaceTest {
	public function test() {
		echo 'Testing...' , PHP_EOL;

		return $this; //retornamos uma referência ao próprio objeto
	}
}

$fluentInterfaceTest = new FluentInterfaceTest();
$fluentInterfaceTest->test()->test()->test()->test()->test()->test()->test()->test()->test()->test();

 

A saída será:

Testing...

Testing...

Testing...

Testing...

Testing...

Testing...

Testing...

Testing...

Testing...

Testing...

 

Com isso, em vez de violar nosso encapsulamento, deixando nosso calçado público e, consequentemente, passivo de ser modificado de fora (alguém pode colocar uma pedra onde deveria ter um calçado), fazemos com que nosso método calca() retorne a instância do objeto que que calçou.

 

Se fizermos uma modificação à nossa interface Pessoa, adicionando um método pegaCalcado() e fazendo com que nosso método calca() retorne uma instância de Pessoa, conseguimos fazer as coisas utilizando esse encadeamento, por exemplo:

 

interface Pessoa {
	public function mostraNome();
	public function calca( Calcavel $calcavel );
	public function pegaCalcado();
	public function tiraCalcado();
}

 

Dessa forma, a implementação ficaria:

 

class Eu implements Pessoa, Programador, Atirador {
	private $calcado = array();

	public function mostraNome() {
		echo 'Sou o Neto' , PHP_EOL;

		return 'Neto';
	}

	public function escreveCodigo() {
		echo '<?php' , PHP_EOL , 'echo "Polimorfismo é legal.";' , PHP_EOL;
	}

	public function atira( Alvo $alvo ) {
		$alvo->acerta( $this->tiraCalcado() );

		return $this; //retornamos o próprio objeto
	}

	public function calca( Calcavel $calcavel ) {
		if ( count( $this->calcado ) < 2 ) {
			foreach ( $this->calcado as $calcado ) {
				if ( $calcado === $calcavel ) {
					throw new LogicException( 'Já estou usando esse calcado em um dos pés.' );
				}
			}

			$this->calcado[] = $calcavel;
		} else {
			throw new LogicException( 'Opz, tenho apenas dois pés' );
		}

		return $this; //retornamos o próprio objeto
	}

	public function tiraCalcado(){
		if ( count( $this->calcado ) ){
			return array_shift( $this->calcado );
		} else {
			throw new RuntimeException( 'Estou descalço.' );
		}
	}

	public function pegaCalcado(){
		if ( count( $this->calcado ) ){
			return end( $this->calcado );
		} else {
			throw new RuntimeException( 'Estou descalço.' );
		}
	}
}

 

Vamos ver como ficou:

 

$eu = new Eu();
$eu->calca( new Sapato( 42 ) )->pegaCalcado()->mostraNumero();

 

Veja que, como o método calca() retorna a instância de Pessoa (no caso, uma instância de Eu), podemos utilizar na sequencia o método pegaCalcado() que retorna uma instância de Calcavel (no caso Sapato) e, assim, podemos utilizar o método mostraNumero();

 

Ainda, adicionando algumas verificações ao código:

 

$sapato = new Sapato( 42 );
$eu = new Eu();
$eu->calca( $sapato );
$eu->calca( $sapato );

 

Não é possível usar o mesmo sapato nos dois pés, então, nesse caso, teremos o disparo de uma exceção.

 

Ou ainda:

$eu = new Eu();
$eu->calca( new Sapato( 42 ) );
$eu->calca( new Sapato( 42 ) );

$eu->atira( new Cachorro() );
$eu->atira( new Cachorro() );
$eu->atira( new Cachorro() );

 

Novamente, teremos o disparo de uma exceção, já que atirei meus dois pés de sapato, fiquei descalço, consequentemente, não posso acertar um terceiro cachorro.

 

Agora, se eu estiver em uma loja de sapatos, posso me "munir" de vários sapatos e, assim, "recarregar" constantemente:

 

$maniacoAtiradorDeSapatos = new Eu();
$maniacoAtiradorDeSapatos
	->calca( new Sapato( 42 ) )->atira( new Cachorro() )
	->calca( new Sapato( 42 ) )->atira( new Cachorro() )
	->calca( new Sapato( 42 ) )->atira( new Cachorro() )
	->calca( new Sapato( 42 ) )->atira( new Cachorro() )
	->calca( new Sapato( 42 ) )->atira( new Cachorro() )
	->calca( new Sapato( 42 ) )->atira( new Cachorro() )
	->calca( new Sapato( 42 ) )->atira( new Cachorro() )
	->calca( new Sapato( 42 ) )->atira( new Cachorro() )
	->calca( new Sapato( 42 ) )->atira( new Cachorro() )
	->calca( new Sapato( 42 ) )->atira( new Cachorro() )
	->calca( new Sapato( 42 ) )->atira( new Cachorro() )
	->calca( new Sapato( 42 ) )->atira( new Cachorro() )
	->calca( new Sapato( 42 ) )->atira( new Cachorro() )
	->calca( new Sapato( 42 ) )->atira( new Cachorro() )
	->calca( new Sapato( 42 ) )->atira( new Cachorro() )
	->calca( new Sapato( 42 ) )->atira( new Cachorro() )
	->calca( new Sapato( 42 ) )->atira( new Cachorro() )
	->calca( new Sapato( 42 ) )->atira( new Cachorro() )
	->calca( new Sapato( 42 ) )->atira( new Cachorro() );

 

A saída:

Cain, cain, cain, cain...

Cain, cain, cain, cain...

Cain, cain, cain, cain...

Cain, cain, cain, cain...

Cain, cain, cain, cain...

Cain, cain, cain, cain...

Cain, cain, cain, cain...

Cain, cain, cain, cain...

Cain, cain, cain, cain...

Cain, cain, cain, cain...

Cain, cain, cain, cain...

Cain, cain, cain, cain...

Cain, cain, cain, cain...

Cain, cain, cain, cain...

Cain, cain, cain, cain...

Cain, cain, cain, cain...

Cain, cain, cain, cain...

Cain, cain, cain, cain...

Cain, cain, cain, cain...

 

;)

Compartilhar este post


Link para o post
Compartilhar em outros sites

Excelente, agora temo uma separação mais concreta do conceito de de dois pés de calçado.

 

Mas esse último camarada vai ser processado pelo IBAMA :lol:

Compartilhar este post


Link para o post
Compartilhar em outros sites

Show http://forum.imasters.com.br/public/style_emoticons/default/joia.gif

 

Parabéns João, perfeita sua explicação :lol:

 

Mas esse último camarada vai ser processado pelo IBAMA :lol:

Coitados dos cachorros, se fossem gatos eu nem ligaria hahah ;)

 

 

[]'s

Compartilhar este post


Link para o post
Compartilhar em outros sites

Tem mesmo que tirar onda senão fica tudo muito maçante e um assunto conceituadamente complexo para alguns não é bem assimilado.

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.