Salve, salve leitores do iMasters.
Depois de algum tempo afastado devido a alguns projetos, finalmente retorno para compartilhar um pouco mais de minha experiência com PHP. Vamos continuar na linha em que paramos.
Padrões de Projetos (Design Patterns);
Essa semana veremos os padrão Value Object ou, simplesmente, o padrão VO.
Em diversas aplicações orientadas a objetos, muitos objetos possuem uma Identidade. Uma importante classe de domínio como a classe Cliente ou a classe Fornecedor terá vários atributos um ID, um nome, um e-mail O valor desse atributos é que diferenciam diferentes objetos de sua classe. Portanto, um objeto com uma Identidade, PERSISTE, ou seja, ele existe durante toda aplicação.
Para nós programadores, um Cliente A é apenas um Cliente A e as mudanças nesse objeto durará durante toda execução da aplicação;
Mas existe situações em que alguns objetos NÃO precisam ter uma Identidade, pois esses objetos representam apenas características singulares de outros objetos;
Você pergunta: Não entendi!;
Vamos lá…Por exemplo, é comum usarmos objetos para representar Datas, Números, Dinheiro, etc.
Esses objetos não precisam de uma identidade, pois representam somente valores, ou seja, eles não precisam persistir durante toda a aplicação.
Eles não pertencem ao grupo de classes de Domínio e dificilmente aparecem em um Diagrama de Classes;
Digamos que são classes auxiliares…
Certo, e daí? Não basta eu criar uma classe Data ou uma classe Dinheiro?;
Sim, basta fazer isso, mas com alguns cuidados.
Veja o código abaixo e DESCUBRA o problema em se fazer SOMENTE isso.
Digamos que implementamos uma classe DinheiroRuim (Coloquei esse nome não porque dinheiro seja ruim :), mas porque está com uma implementação errada para o padrão VO ).
class DinheiroRuim{
protected quantidade;
public function __construct(quant=0){
this->quantidade = quant;
}
public function getQuantidade(){
return this->quantidade;
}
public function soma(valor){
this->quantidade = valor->getQuantidade();
}
}
Agora implementamos a classe Trabalho que possui uma referência à classe DinheiroRuim (atributo salario);
class Trabalho{
protected salario;
public function __construct(){
this->salario = new DinheiroRuim(200);
}
public function getSalario(){
return this->salario;
}
}
Criamos a classe Trabalhador que possui uma instância à classe Trabalho
class Trabalhador{
public trabalho;
}
E Finalizamos com a classe de teste TesteDinheiroRuim;
class TesteDinheiroRuim{
trabalho = new Trabalho();
trabalhador1 = new Trabalhador();
trabalhador2 = new Trabalhador();
trabalhador1->trabalho = trabalho->getSalario();
echo trabalhador1->trabalho->getQuantidade(); //IMPRIME 200
trabalhador2->trabalho = trabalho->getSalario();
echo trabalhador2->trabalho->getQuantidade(); //IMPRIME 200
trabalhador1->trabalho->soma(trabalho->getSalario());
echo trabalhador1->trabalho->getQuantidade(); //IMPRIME 400
//ERRO TRABALHADOR 2 TAMBÉM AUMENTOU O SALARIO
echo trabalhador2->trabalho->getQuantidade(); //IMPRIME 400
}
Ao rodarmos a aplicação acima, detectamos um erro!!!
Perceba que utilizamos um mesmo objeto Trabalho para os objetos Trabalhador1 e Trabalhador2;
No PHP 5, todos os objetos são passados por REFERÊNCIA, isso quer dizer que para OBJETOS, é passado o local de memória do objeto e NÃO uma CÓPIA;
Dessa forma, toda alteração que o objeto Dinheiro sofrer, PERSISTIRÁ por TODA a aplicação, ou seja, o objeto POSSUI uma IDENTIDADE;
Não preciso dizer que isso não é o desejado, já que queremos a classe Dinheiro somente armazenando valores para UM Trabalhador;
O PADRÃO VALUE OBJECT RESOLVE ESSE PROBLEMA!!
Nome do Padrão: VALUE OBJECT
Problema: Como construir uma classe leve e fácil de construir e descritiva, como Data ou Dinheiro ?
Solução: Objetos Leves devem possuir um comportamento semelhante ao tipos de dados primitivos do PHP (inteiro, float, string, etc): Se você atribui o mesmo objeto a duas diferentes variáveis e muda uma das variáveis, a outra variável deve permanecer imutável. Isso é o VO (Value Object).
Veja qual o comportamento que procuramos…
<?php
valor1 = 10;
valor2 = valor1;
echo valor1; // IMPRIME 10
echo valor2; //IMPRIME 10
valor2 = 25;
echo valor1; // IMPRIME 10
echo valor2; //IMPRIME 25
?>
Perceba que ao atribuímos a variável valor1 a valor2, ambos terão o mesmo valor (10);
Mas ao alterarmos qualquer das variáveis, a mudança não reflete em ambas as variáveis, ou seja, a variável NÃO POSSUI IDENTIDADE;
É esse o comportamento que esperamos obter com o Padrão VO;
E como faremos isso??
Vamos lá…
O Padrão VO possui 3 principios:
Seu valor é IMUTÁVEL, você não pode mudar o valor original;
É passado por cópia (não por referência), isto é, quando passado como parâmetro em um método, deve-se criar uma nova cópia do objeto;
Geralmente possui métodos de operação (Adição, Subtração, etc);
Para implementar o primeiro principio, basta retirarmos os métodos setters e adicionar os métodos de acessibilidade do atributo para bloqueio (private ou protected);
Alterando nossa classe DinheiroRuim, criamos a nova classe Dinheiro;
class Dinheiro{
private quantidade;
public function __construct(quant=0){
this->quantidade = (float)quant;
}
public function getQuantidade(){
return this->quantidade;
}
public function soma(valor){
return new Dinheiro(this->quantidade valor->getQuantidade());
}
}
Veja que alteramos o nível de acessibilidade do atributo quantidade para private. Dessa forma, restringimos o acesso direto à variável;
Também alteramos o método soma(); Note que em momento algum alteramos o valor original do atributo quantidade, estando de acordo com o primeiro principio do VO. Note também que, diferente da classe DinheiroRuim, o método retorno um NOVO objeto Dinheiro, simulamos assim uma passagem por valor e nunca teremos a mesma cópia do objeto distribuído em várias instâncias;
O Padrão VO é de fácil implementação, torna seu código elegante, de fácil manuntenção, evita aqueles erros inexplicáveis e pode ser utilizado em conjunto com outros padrões de projetos;
Bem pessoal, o VOé isso!
Próxima semana trago a vocês o famoso Padrão de Projeto Data Access Object (DAO)
Abraços e Sucesso!