Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
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 );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 NetoOlá 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.
/applications/core/interface/imageproxy/imageproxy.php?img=http://forum.imasters.com.br/public/style_emoticons/default/wink.gif&key=0566fd943552bcff9cb1b879403ca34b5ff8f67befaac7fe4648006e9f764689" alt="Imagem Postada" class="bbc_emoticon">
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.
;)
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
é 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
>
A menos que você tenha ido buscar o sapato dps =P
hehehe, boa !!!!
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 );
}
?
>
é 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();>
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(); ->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...
;)
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:
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
Muito bom a explicação.
além do conteúdo ser excelente e as discussões também eu dou muita risada nas brisada do Neto.
$maniacoAtiradorDeSapatos
auuahhuauhahuahuahuahuuhahuauahuauha
Tem mesmo que tirar onda senão fica tudo muito maçante e um assunto conceituadamente complexo para alguns não é bem assimilado.
Parabéns a você também Bruno que sempre onde vejo ta ajudando geral...
Imasters epic.
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 =|
valeu !
[]'s