Delegação - Programação Orientada a Objetos Pós-Moderna Parte3

    Uma das ideias da Programação Orientada a Objetos é diminuir a quantidade de código escrito, reutilizando o código de outras classes. Esta reutilização pode ocorrer por 2 tipos de relacionamentos: O relacionamento do tipo “É um” também conhecido como herança, onde um objeto é um tipo derivado de outro: Exemplo um tipo carro_conversível seria também um tipo carro. E o relacionamento do tipo “Tem Um”, onde um objeto contém em seus atributos outros objetos. Exemplo: um computador tem um teclado. Neste artigo vamos ilustrar o relacionamento “tem um” que pode ser facilitado no Moose pelo conceito de delegação.
    Vamos voltar ao primeiro artigo desta série: //www.devmedia.com.br/articles/viewcomp.asp?comp=21119


    Neste artigo criamos um objeto ponto, pegar a classe Ponto.pm e adicionar o código em negrito com os conceitos aprendidos no artigo 2, em //www.devmedia.com.br/articles/viewcomp.asp?comp=21143.

     1  package Ponto;
     2  use Moose;
     3
     4  #Declara os atributos x e y
     5  #como inteiros para leitura e escrita
     6  #ou seja, os valores podem ser modificados
     7  #durante a execução do programa.
     8
     9  has 'x' => (isa =>'Int',
    10                   is => 'rw',
    11           default => 0,
    12           required => 1);
    13
    14  has 'y' => (isa => 'Int',
    15                    is  => 'rw'
    16           default => 0,
    17           required => 1);
    18  1;

    E do objeto Linha, que estava sem código:

      1 package Linha;
      2 use Moose;
      3 1;

    Agora vamos reduzir o código da classe Ponto. Quando diversos atributos de uma classe tiverem as mesmas características eles podem ser declarados por meio de uma Role (regra) ou simplesmente por meio de um array anônimo. A vantagem de usar Roles é que as mesmas podem ser utilizadas por outras classes. Mas no caso um array será o bastante. Modifique o arquivo Ponto.pm:

      9 has ['x','y'] => (isa =>'Int',
     10         is => 'rw',
     11         default => 0,
     12         required => 1);
     13
     14 1;

    Assim os atributos x e y são criados de forma idêntica. Agora vamos cria a classe Linha, que terá 2 pontos:

      1 package Linha;
      2 use Moose;
      3 use lib (".");
      4 use Ponto;
      5
      6 has ['p1', 'p2'] => (isa => "Ponto",
      7         is => 'rw',
      8         default => sub { return Ponto->new( )},
      9         required => 1);
     10
     11 1;

    E um pequeno arquivo teste_linha.pl para testar nossos objetos:

      1 #!/usr/local/bin/perl -t
      2
      3 use 5.12.0;
      4 use lib (".");
      5 use Linha;
      6
      7 my $l = Linha->new(); #Cria objeto linha com valores Default
      8
      9 $l->p2->x(10);
     10 $l->p2->y(5);
     11
     12 printf "Linha 1, ponto1 x = %d, ponto y = %d\n",
     13         $l->p1->x, $l->p2->y;
     14         
     15 printf "linha 1, ponto2 x = %d, ponto y = %d\n",
     16         $l->p2->x, $l->p2->y;
     17
     18 my $l2 = Linha->new(p1 => Ponto->new(x => 3, y => 4),
     19                             p2 => Ponto->new( x => -1, y => -10) ); #Cria explicitamente os Pontos
     20
     21 printf "linha 2, ponto2 x = %d, ponto y = %d\n",
     22         $l2->p1->x, $l->p2->y;
     23         
     24 printf "linha 2, ponto2 x = %d, ponto y = %d\n",
     25         $l2->p2->x, $l2->p2->y;
    
    Configure testa_linha.pl como executável com o comando chmod +x testa_linha.pl. Esse programa gera a saída:

$ ./testa_linha.pl
Linha 1, ponto1 x = 0, ponto y = 5
linha 1, ponto2 x = 10, ponto y = 5
linha 2, ponto2 x = 3, ponto y = 5
linha 2, ponto2 x = -1, ponto y = -10
$

    Este é um exemplo simples do relacionamento “tem um”. Aqui uma classe possui em seus atributos outras classes. Explicitamente neste caso, uma linha tem 2 pontos. Ainda existe um atalho que  o Moose permite em relações “tem um”. A delegação. No nosso exemplo anterior, para acessar uma coordenada de um ponto da linha tínhamos que chamar o objeto ponto, como em $l->p1->x( ) ou
$l->p2->y( ). Mas seria mais interessante para o consumidor de nossa classe utilizar $l->x1( ), $l->x2, etc... Esta redução na interface do programa é chamada de Delegação no jargão do Perl. Vamos ver como isso funciona: Mapeamos com o Moose as interfaces delegadas com handles. Então vamos reeditar o arquivo Linha.pm:

      1 package Linha;
      2 use Moose;
      3 use lib (".");
      4 use Ponto;
      5
      6 for (1..2){
      7     has "p" . $_ => (isa => "Ponto",
      8         is => 'rw',
      9         default => sub { return Ponto->new()},
     10         required => 1,
     11         handles => { "x" . $_ => "x",
     12                      "y" . $_ => "y"}
     13         );}
     14
     15 1;

    Vamos entender esse código do módulo. O loop for cria 2 handles p1 e p2. O loop set a variável $_ para os valores definidos dentro do array (1..2) que é concatenada na string. Esta é mais uma foma de otimizar a criação de atributos repetitivos. Assim criamos os atributos p1 e p2 e as Delegations x1, x2, y1 e y2. Adicione o código abaixo ao arquivo testa_linha.pl:

     26
     27 my $l3 = Linha->new( );
     28 $l3->x1(2); $l3->y1(2); $l3->x2(8); $l3->y2(7);
     29
     30
     31 printf "linha 3, ponto1 x = %d, y = %d\n",
     32         $l3->x1, $l3->y1;
     33
     34 printf "linha 3, ponto2 x = %d, y = %d\n",
     35         $l3->x2, $l3->y2;
     36
     37 printf "linha 1, ponto1 x = %d, y = %d\n",
     38         $l->x1, $l->y1;
     39
     40 printf "linha 1, ponto2 x = %d, y = %d\n",
     41         $l->x2, $l->y2;

    E a saída sera:

$ ./testa_linha.pl
Linha 1, ponto1 x = 0, y = 5
linha 1, ponto2 x = 10, y = 5
linha 2, ponto2 x = 3, y = 4
linha 2, ponto2 x = -1, y = -10
linha 3, ponto1 x = 2, y = 2
linha 3, ponto2 x = 8, y = 7
linha 1, ponto1 x = 0, y = 0
linha 1, ponto2 x = 10, y = 5
$

    Veja que que você pode acessar as informações de coordenada do ponto tanto por $l->p1->x( ) quanto por $l->x1( ) quanto utiliza os handles. Neste artigo você aprendeu a: Reduzir o código para declaração de atributos repetitivos com arrays e loops; O relacionamento entre objetos do tipo “tem um”.