segunda-feira, 24 de março de 2008

Padrão Baixo Acoplamento

Aulas 12 e 13


Acoplamento de Controle

Anteriormente discutimos o acoplamento de dados, o menos pior dos acoplamentos, foi explicado que a melhor solução para diminuir este tipo de acoplamento é o uso de interface, aliás, para diminuição de todos os tipos de acoplamento o melhor caminho é o uso de interface. No acoplamento de dados, como o próprio nome já diz é aquele em que um objeto conhece muito os dados de outro, no próximo tipo que iremos discutir, chamado acoplamento de controle, não existe este conhecimento, mas sim, um certo controle de um certo objeto sobre o outro, explicando melhor:

Objeto A manda uma mensagem a objeto B;

Objeto B usa um parâmetro da mensagem para decidir o que fazer;


Exemplo:

Considere a classe Circuito como objeto A e classe Lâmpada como o objeto B:

O objeto circuito instancia a classe lâmpada, e passa os parâmetros desligada, ligada e piscando, a classe lâmpada então atribui um valor a cada parâmetro e executa a o procedimento para conhecer o estado da lâmpada.

Problema: em termos mais diretos, quem comanda o interruptor? Claro que a classe circuito, mas qual o problema nisso? Afinal, alguém tem que fazer isso. O problema não é alguém fazer, mas a forma como é feito, se ao invés da classe circuito mandar uma mensagem passando um parâmetro para desligar a lâmpada, somente passasse uma mensagem para desligá-la e a classe responsável executasse o procedimento, da maneira que lhe fosse convincente, seria muito mais prudente, afinal as duas não precisariam andar sempre de mãos dadas, característica do alto acoplamento.

Como no exemplo acima, a classe circuito cria um novo objeto de lâmpada e ao invés de passar parâmetros, cria métodos para passar mensagens.

A classe lâmpada, anteriormente não tinha métodos, apenas as comparações de if e else, mas utilizando um princípio para diminuir o acoplamento em casos de acoplamento de controle, decompomos a operação em múltiplas operações, ou seja, o método “public void setLampada(int valor)” do primeiro exemplo de lâmpada, em diversos métodos, como visto no segundo exemplo.


Acoplamento de Dados Globais

O terceiro tipo de acoplamento é o de dados globais, este tipo de acoplamento ocorre da seguinte maneira:

Dois ou mais objetos compartilham estruturas de dados globais, estes tipos de dados podem ser enxergados por todas as classes do sistema, pois como o próprio nome já diz é global.

Uma chamada de método pode mudar um valor global e o código não deixa isso aparente.


Acoplamento de Dados Internos

O quarto e último tipo de acoplamento, e o pior de todos é o acoplamento de dados internos, ocorre quando um objeto consegue alterar os dados locais de outro objeto, exemplo, uma variável de classe pública ou protected em java.

Solução: sempre utilizar encapsulamento, ou seja, variáveis private e métodos get e set.

sexta-feira, 21 de março de 2008

Padrão Baixo Acoplamento

Aula 11


Acoplamento de Dados

Acoplamento de dados, como já vimos, é o tipo de acoplamento onde uma classe conhece os dados da outra, fazendo com que se houver mudança em uma, automaticamente implicará mudança em outra.

Observe o exemplo a seguir, de uma classe aluno e uma classe lista ordenada, a finalidade delas é obter a matrícula de um aluno e coloca-las em uma lista ordenada.

A classe aluno obtêm a matrícula e o nome do aluno através do método get, bem como cria um novo objeto novoAluno e adiciona a lista de alunos, chamando assim a classe lista ordenada. Observe agora a classe lista ordenada:

A classe lista ordenada recebe um objeto do tipo aluno, e agora já observamos um problema de acoplamento, a classe lista ordenada nunca poderá receber um objeto de outro tipo para que seja comparado. Continuando, através do método add, a classe compara os objetos através da variável matrícula, que só existe na classe aluno, e aí observamos mais um acoplamento, e se a variável matrícula deixar de existir na classe aluno? E se for necessário comparar os alunos não por matrícula mas por ordem alfabética?.

Para isso, vamos refatorá-las para que as duas não mais dependam uma da outra.

Uma das melhores soluções para reduzir o acoplamento é a utilização de interface, vamos relembrar o que vem a ser uma interface. Uma interface nada mais é que uma superclasse que adiciona funcionalidades à classe que a implementa, ou seja, se uma determinada classe implementa uma interface, é como se ela assinasse um contrato e em troca receberia a garantia de que iria implementar as funcionalidades que existem na interface.

Observe como ficou a classe aluno:

Qual a primeira mudança que notamos? Isso mesmo, a classe Aluno agora está implementando uma interface chamada “comparable”, que é a interface que permite fazer comparação de objetos. Em seguida encapsula as variáveis com os métodos get e set, o que também não acontecia no exemplo anterior, em seguida há o método compareTo, um método da interface comparable, esse método transforma aluno em uma variável do tipo comparable (Aluno aluno = (Aluno)o), e em seguida faz a comparação para retornar um inteiro à classe que irá fazer a ordenação, nesse caso a classe ListaOrdenada.

A classe ListaOrdenada instancia a lista, recebe o novo elemento, põe na ordem correta e o insere na lista.

Agora qual a diferença principal que notamos nessas duas classes? A classe listaordenada é capaz de ordenar qualquer tipo de objeto, e não somente a matrícula, como era no exemplo anterior, se houver uma mudança na classe aluno, a classe listaordenada continuará ordenando pois o objeto que é passado a ela não é um objeto do tipo aluno e sim do tipo comparable.

quinta-feira, 20 de março de 2008

Padrão Baixo Acoplamento

Aula 10


Em um sistema orientado a objetos, os objetos são todos interligados, uns mandando mensagens a outros, como já vimos até agora, existem aqueles que têm a responsabilidade de conhecer qual o responsável por determinada ação, ou quem possui determinada informação para executar tal ação, e existem aqueles com a responsabilidade de fazer as ações, de executa-las.

O padrão que vamos conhecer hoje é responsável por medir o quanto uma classe está ligada a outra, isso é possível através do diagrama de classe, quando se observa a ligação fisicamente, ou quando avaliamos uma classe e constatamos que ela tem muito conhecimento de outra, ou quando uma classe depende de muitos elementos de outra classe, isso se chama alto acoplamento.

O alto acoplamento traz diversos problemas para um sistema, entre eles:

1. Difícil entendimento: vamos imaginar uma situação em que você precisa fazer uma reengenharia de um sistema que já está pronto, ou que necessita encontrar um erro que está lhe dando dor de cabeça no seu sistema, ao começar analisar as classes descobre que para entender essa classe, precisa estudar a próxima que está ligada a ela, para também entender esta, precisa estudar a próxima, e assim por diante, imagine o tempo que irá desperdiçar nisso.

2. Difícil reutilização: vamos imaginar outra situação, digamos que seja necessário retirar uma determinada parte do sistema, algo como um módulo de calcular folha de pagamento de um sistema financeiro, para ser levada e adequada a outro sistema financeiro, imagine que as classes responsáveis por isso, estejam ligadas ao módulo de RH, você vai levar o módulo de RH junto?

3. Propagação de mudanças: continuando do item anterior, imagine que seja necessário mudar uma classe do módulo de folha de pagamento, para isso, teria que mudar a classe que está no módulo de RH, e se você não for o responsável pelo módulo de RH? E se além de ter que mudar esta classe, também mudar várias outras que estão ligadas à primeira.

A solução para isso seria minimizar o acoplamento entre as classes, ou seja, deixa-las com baixo acoplamento.

Existem quatro tipos de acoplamento:

  • Acoplamento de dados: quando uma classe conhece os dados da outra;
  • Acoplamento de controle: quando uma classe exerce controle sobre o comportamento de outra.
  • Acoplamento de dados globais: quando dois ou mais objetos compartilham os mesmos dados.
  • Acoplamento de dados Internos: quando um objeto altera os dados locais de outro objeto, isso em java não é difícil de evitar, é só utilizar variáveis private, ao invés de públicas.

O acoplamento fraco é um princípio a ser levado em conta em todas as decisões de projeto, pois é um princípio de avaliação que o projetista aplica enquanto avalia as decisões do projeto.

quinta-feira, 13 de março de 2008

Padrão Criador ( na prática )

Aula 9 (Laboratório)


Sabemos que a criação de objetos é uma das atividades mais comuns em um sistema orientado a objeto, e é útil ter um princípio para atribuição geral de responsabilidades de criação. Seguindo estes princípios o sistema apresentará maior clareza, acoplamento fraco, encapsulamento e reutilização, nos artigos anteriores discutimos todas essas qualidades, e portanto não há necessidade de defini-las novamente.

Veremos agora uma aplicação prática do padrão criador, utilizando os mesmos diagramas e praticamente o mesmo código da AULA 8, mas um pouco mais completo.

Pelo texto da postagem anterior, sabemos que a classe “Venda” é responsável por calcular o total de uma venda, a classe “ItemVenda” por calcular o subtotal e a classe “Produto” por saber o preço unitário de cada produto, agora a questão é: quem é responsável por criar quem? Qual dessas classes cria a instância de outra? Pelo primeiro diagrama, percebe-se que a classe “produto” não cria ninguém, ela é apenas criada, então vamos começar por ela.

Uma vez que a classe produto só possui métodos acessores e mutatórios, ela não precisa ser instanciada mas apenas que as outras classes invoquem, ou seja, chamem esses métodos contendo as variáveis da classe produto.


public class Produto {

private Integer idProduto;
private String descricaoProduto;
private Double valorUnitario;
public Produto() {
}
public Integer getIdProduto() {
return idProduto;
}
public void setIdProduto(Integer idProduto) {
this.idProduto = idProduto;
}
public String getDescricaoProduto() {
return descricaoProduto;
}
public void setDescricaoProduto(String descricaoProduto) {
this.descricaoProduto = descricaoProduto;
}
public Double getValorUnitario() {
return valorUnitario;
}
public void setValorUnitario(Double valorUnitario) {
this.valorUnitario = valorUnitario;
}
}

Já a classe “ItemVenda” além de possuir métodos acessores e mutatórios possui um método que obtêm a quantidade de cada produto, através da variável “qtde” e multiplica pela valor unitário de cada produto, informações estas pertencentes à classe produto, veja bem, a classe “ItemVenda” não está instanciando a classe “Produto”, apenas utilizando o método get que obtêm o valor unitário de cada produto.


public class ItemVenda {

private Double qtde;
private Produto produto ;
public ItemVenda() {
}
public Double getValorItemVenda(){
return getQtde()*getProduto().getValorUnitario();
}
public Double getQtde() {
return qtde;
}
public void setQtde(Double qtde) {
this.qtde = qtde;
}
public Produto getProduto() {
return produto;
}
public void setProduto(Produto produto) {
this.produto = produto;
}
}

E como a classe “ItemVenda” possui o método que calcula o valor individual de cada produto, ninguém mais interessada em utilizá-la do que a classe que calcula o total de uma venda, ou seja, a classe “Venda” e agora sim, estamos aplicando o padrão criador, pois a classe “Venda” instancia a classe “ItemVenda” para que esta realize o cálculo.


public class Venda {

private Integer idVenda;
private Date dataVenda;
private Set itemVendaList= new HashSet();

public Venda() {
}
public Integer getIdVenda() {
return idVenda;
}
public void setIdVenda(Integer idVenda) {
this.idVenda = idVenda;
}
public Date getDataVenda() {
return dataVenda;
}
public void setDataVenda(Date dataVenda) {
this.dataVenda = dataVenda;
}
public Double getValorTotal(){
Double valorTotal=0.0;
for(ItemVenda currentItem : itemVendaList){
valorTotal+=currentItem.getValorItemVenda();
}
return valorTotal;
}
public void addItem(ItemVenda i){
itemVendaList.add(i);
}
public void removeItem(ItemVenda i){
itemVendaList.remove(i);
}
public ItemVenda criarItemVenda(Double qtde, Produto produto){
ItemVenda itemVenda = new ItemVenda();
itemVenda.setProduto(produto);
itemVenda.setQtde(qtde);
addItem(itemVenda);
return itemVenda;
}
}

Finalizando, teremos um método main que instancia a classe "Venda" e cada um dos produtos.

domingo, 9 de março de 2008

Padrão Especialista ( na prática )

Aula 8 (em Laboratório)


Nesta aula vimos a aplicação prática do padrão especialista, a implementação em código. Vamos pegar como exemplo uma parte de um modelo que tem como objetivo calcular o total de uma venda, especificando cada produto, a quantidade de cada produto, e o sub-total de cada item de venda, este diagrama contêm 3 classes somente, são essas classes:

Partiremos do princípio de todo esquema para uma venda, saber o total dela, portanto, qual a classe responsável por conhecer o total de uma venda? A classe responsável terá que conhecer todas as instâncias ItemVenda da Venda e o subtotal de cada uma delas, portanto a classe Venda é uma forte candidata pois uma Venda contém ItemVenda. Definida a classe que calcula o total de uma venda, vamos definir a classe responsável por conhecer o subtotal de uma venda, para isso é necessário saber a quantidade de cada produto, quem detém estas informações é a classe ItemVenda, portanto esta é a classe responsável por implementar o método de calcular subtotal. Mas para implementar este método a classe ItemVenda precisa conhecer o preço unitário de cada produto, e é aí que entra a responsabilidade da classe produto, que é obter especificação do produto para mandar como resposta para a classe ItemVenda quando esta enviar uma mensagem para obter o preço de cada produto.

No final, com todos os métodos em suas respectivas classes, o diagrama ficou assim:

Implementando em código:

public class Produto
{
private integer idProduto;
private string descricao;
private double valorUnitário;

public string getdescricao(){
return descricao;
}

public void setDescricao(string valor){
valor=descricao;
}
}


public class ItemVenda{
private double qtde;
private Produto p;

public void setP (Produto p) {
this.p = p;
}


public class Venda {
private Set itemVendaList=new HashSet();
private Date dataVenda;
private integer idvenda;


public criarItemvenda (Produto P, double qtde)
{
Itemvenda i =new ItemVenda();
i .setP(p);
i.setQtde(qtde);
itemVendaList.add(i);

}
}


observação: nos diagramas as classes "LinhaDeVenda" e "EspecificaçãoProduto" são as mesmas classes "ItemVenda" e "Produto" do trecho de código

domingo, 2 de março de 2008

Padrões GRASP (Padrão Criador)

Aulas 6 e 7


Nos artigos anteriores vimos que um programa construído no paradigma de orientação a objetos é nada mais que uma coleção de objetos interagindo entre si, mas o que vem a ser um objeto? Na linguagem técnica, um objeto é uma instância de uma classe, e o que é uma instância? O ato de criar objetos a partir de uma ou várias classes se chama instanciação. Mas como é feito esse trabalho de criar objetos? Objetos são criados a partir de chamadas de procedimento, ou seja, de mensagens(métodos) enviadas por classes para que sejam criados novos objetos, mas agora, vem o ponto crucial deste assunto que estamos estudando, qual a classe correta, ou seja, qual a mais indicada para criar novas instâncias de outra classe(objetos)? Afinal, existem muitos deles dentro de um programa, e não é qualquer classe que pode sair criando objetos à vontade, portanto vamos à explicação:

Segundo o Padrão Criador (Creator), para que uma classe tenha a responsabilidade de criar instâncias de outra classe é necessário que se aplique o procedimento a seguir: Vamos supor que existam duas classes A e B, a classe responsável por criar instância da outra será aquela em que mais de uma das seguintes condições se aplicar:

a. B agrega objetos da classe A.

b. B contém objetos da classe A.

c. B registra instâncias da classe A.

d. B usa muitos objetos da classe A.

e. B possui os dados usados para inicializar A.