16 dezembro, 2010
Eddie Vedder- Better Days
22 novembro, 2010
Acoplamento fraco x Herança
Introdução
Acoplamento fraco é um dos principais requisitos para se construir software orientado a objetos (OO) de qualidade. O acoplamento fraco mede o quanto uma classe, depende de, ou está relacionada a, outra classe ou subsistema. A capacidade de uma classe em herdar o comportamento de outra(s) é uma das principais características do paradigma OO. A principal vantagem é poder criar novas classes quase de graça, aproveitando o código de outra. Esse artigo discute esses dois conceitos e mostra porque a herança, em geral, ajuda a comprometer o acoplamento fraco.
Acoplamento fraco
Uma classe com acoplamento forte depende muito (em geral sem necessidade) de outras. Isso pode conduzir aos seguintes problemas [Larman]:
classes difíceis de aproveitar tendo em vista que sempre que esta for utilizada todas as outras das quais ela depende devem estar presentes;
alterações nas classes relacionadas podem forçar mudanças locais e
são difíceis de compreender isoladamente.
Formas comuns de acoplamento ocorrem através de: variáveis de instância, variáveis locais a métodos ou de seus argumentos, chamada de serviços em outra classe, uma classe deriva direta ou indiretamente de outra ou uma classe implementa uma determinada interface. Resumindo, sempre que uma classe referencia um outro tipo em qualquer uma das circunstâncias acima está ocorrendo acoplamento. Considere o código:
public class X
{
private ClasseConcretaY var1;
void M1(ClasseConcretaW var2 ) { … }
}
Existem dois pontos principais de acoplamento, na variável de instância var1, que é do tipo ClasseConcretaY, e no argumento var2, que é do tipo ClasseConcretaW. Nestas duas partes do código a classe X referencia outras duas classes concretas. Isso significa que, sempre que esta classe for utilizada, as outras duas deverão estar disponíveis no espaço de nomes do programa. No caso de Java, o(s) pacote(s) onde estas se encontram deverá(ão) estar no classpath.
Mas, referenciar outras classes sempre causa problemas de acoplamento? A resposta é, depende! Referenciar classes estáveis e disseminadas raramente é um problema. Por exemplo, utilizar o pacote java.util num programa em Java dificilmente causará problemas futuros de acoplamento, uma vez que qualquer ambiente de execução Java contém essa biblioteca. O problema está em classes instáveis, pouco conhecidas, ou seja, nas classes que são criadas para atender os problemas específicos dos projetos.
Como diminuir o acoplamento?
Uma regra geral para diminuir o acoplamento é “programar para uma interface e não para uma implementação” [Gamma]. No exemplo acima isso significa substituir as declarações das classes concretas por declarações de interfaces. Fazendo isso desacopla-se o código de uma implementação específica, tornando-o dependente apenas de uma interface. Essa não é a solução definitiva, um bom projeto com boas atribuições de responsabilidades é crucial, porém ajuda muito. É mais fácil compreender isoladamente uma classe que referencia apenas interfaces e mais [Gamma]:
os clientes (usuários da classe) permanecem sem conhecimento dos tipos específicos dos objetos que eles usam, contanto que os objetos tenham aderência à interface que os clientes esperam,
os clientes permanecem sem conhecimento das classes que implementam estes objetos; eles somente têm conhecimento das classes abstratas que definem a interface.
Herança
A herança é a principal característica de distinção entre um sistema de programação orientado a objeto e outros sistemas de programação. As classes são inseridas em uma hierarquia de especializações de tal forma que uma classe mais especializada (subclasse) herda todas as propriedades da classe mais geral (superclasse) a qual é subordinada na hierarquia.
O principal benefício da herança é o reaproveitamento de código. A herança permite ao programador criar uma nova classe programando somente as diferenças existentes na subclasse em relação à superclasse. Isto se adeqüa bem a forma como compreendemos o mundo real, no qual conseguimos identificar naturalmente estas relações.
A reutilização por meio de subclasses é dito “reutilização de caixa branca”, pois usualmente expõe o interior das classes ancestrais para as subclasses. A herança é definida estaticamente em tempo de compilação e é simples de utilizar, uma vez que é suportada diretamente pela linguagem de programação.
Acoplamento fraco x Herança
A decisão de derivação a partir de uma superclasse precisa ser cuidadosamente considerada, uma vez que ela é uma forma muito forte de acoplamento [Larman]. As classes ancestrais freqüentemente definem pelo menos parte da representação física das suas subclasses. A implementação de uma subclasse, desta forma, torna-se tão amarrada à implementação da sua classe mãe que qualquer mudança na implementação desta forçará uma mudança naquela. Vejamos uma situação onde isso é verdadeiro. Considere o esquema de herança abaixo:
abstract public class X
{
private final int MAX = 100;
public int CalculaMaximo(int i)
{
return i * MAX;
}
public int UsaMaximo(int i)
{
int maximo = CalculaMaximo(i);
//faz alguma coisa de útil com maximo …
}
}
public class Y extends X
{
public void UsaMetodoDaClasseX()
{
….
int aux = UsaMaximo(10);
…
}
}
Até aqui tudo bem! Agora considere a seguinte modificação na classe X:
abstract public class X
{
private final int MAX = 100;
public int CalculaMaximo(int i)
{
return (int) i * (MAX /100); // Aproxima o resultado com cast
}
public int UsaMaximo(int i) { … }
}
Essa alteração na maneira como o máximo está sendo calculado pode gerar efeitos colaterais na classe Y. A aproximação para inteiro pode funcionar para alguns métodos que usam a CalculaMaximo() mas provocar resultados errôneos na UsaMetodoDaClasseX(). Assim, para que a classe Y continue funcionando, esta precisaria ser adaptada à nova realidade. Problemas podem ocorrer também quando estruturas de dados visíveis nas classes derivadas são alteradas. Um array bidimensional transformado para vetor ou mesmo um tipo int modificado para float certamente acarretará problemas.
Este exemplo simples ajuda a mostrar como uma alteração na implementação de um método numa classe base pode provocar anomalias nas suas classes derivadas. Observe que não ocorreu uma alteração de interface, o que necessariamente (e notoriamente) implica em alterações nas classes clientes. É por isso que a herança, em particular, revela um alto acoplamento. Além das hierarquias de classes criadas estarem suscetíveis às mudanças de interface, estão suscetíveis também às alterações nas implementações dos métodos.
Quando uma subclasse redefine algumas, mas não todas as operações, ela também pode afetar as operações que herda, assumindo-se que elas chamam as operações redefinidas [Gamma]. Isso gera um efeito semelhante ao apresentado acima, porém no sentido oposto, onde alterações nas classes mais especializadas podem gerar problemas nas classes base. Se a classe Y tivesse sobrescrito o método CalculaMaximo(), o problema com a aproximação poderia ocorrer no método UsaMaximo() da classe X.
Como evitar a herança?
Uma outra forma de reaproveitar funcionalidade é através da composição de objetos. Novas funcionalidades são obtidas compondo objetos para obter funcionalidades mais complexas. Uma das vantagens desta abordagem é a flexibilidade em poder selecionar em tempo de execução qual objeto será usado na composição (contanto que este respeite a interface definida). No exemplo anterior, se a classe Y tivesse uma referencia para um outro objeto com a funcionalidade definida em X, quando este fosse alterado restaria a ela ainda a possibilidade de utilizar uma versão antiga e seu funcionamento não estaria necessariamente comprometido.
Conclusão
Evitar herança e privilegiar a composição é em geral uma boa prática em projetos orientados a objetos. Favorecer a composição de objetos em relação à herança ajuda a manter cada classe encapsulada e focalizada em uma única tarefa. Suas classes e hierarquias de classes se manterão pequenas e mais tratáveis [Gamma]. Além disso, vimos como e porquê a utilização da herança resulta num alto acoplamento e os problemas que isso pode acarretar.
Bibliografia
[Gamma] Gamma, E; Helm, R; Johnson, R; Vlissides, J. Padrões de Projeto – Soluções Reutilizáveis de Software Orientado a Objetos, Bookman, 2000.
[Larman] Larman, C. Utilizando UML e Padrões, Bookman, 2004.
25 outubro, 2010
Para quem busca inspiração para escrever

18 outubro, 2010
SWU - 2010
15 outubro, 2010
23 agosto, 2010
O prazer da mudança

Acabei de assistir Hary e Sally pela 4 vez eu acho. O filme tem um lance legal onde de repente a sequência normal é interrompida e entra em cena casais já velhinhos contando orgulhosos como se conheceram há mil anos atrás e estão juntos até hoje. É engraçado como a sociedade (ou o ser humano, não sei) valoriza a constância, a estabilidade, a rotina. Qualquer mudança, em geral, é recebida com maus olhos. Mas, na minha opinião, a mudança é o que dá graça à vida, é o que nos faz crescer, sair do lugar, superar limites, conhecer coisas novas. Do que adianta viver até aos 80 anos fazendo sempre a mesma coisa. Que tédio! Um dos casais mais simpáticos é um tiozinho chinês que conta como conheceu a tiazinha chinesa. Foi assim: um homem de um vilarejo próximo disse a ele que havia uma moça muito boa e que estava pronta para casar. Ele não podia vê-la antes do casamento, pois assim rezava o costume, mas mesmo assim foi até o povoado próximo, ficou escondido e a espiou quando lavava roupas. Gostou dela e então disse ao homem que aceitava sim casar-se com a tal moça. Isso tinha sido há 52 anos e estavam juntos desde então. Isso é muito tempo.
Fazer a mesma coisa a vida toda é um pensamento que me apavora. As vezes brinco que queria mudar de profissão e virar soldador de alumínio por um tempo. Dou esse exemplo por causa da palestra do Almir Klink onde ele conta como eles tiveram que treinar pessoas para trabalhar como soldadores de alumínio no estaleiro dele. Como esse é um trabalho altamente especializado, quem aprende e fica bom logo é chamado para trabalhar em outros estaleiros ao redor do mundo. Quando o ouvi contando senti mesmo vontade de largar tudo e ir aprender a fazer navios. O quanto eu não aprenderia convivendo com aquelas pessoas que estariam ali. Aprenderia muitas outras histórias de vida diferentes das que eu vivi. Aprenderia um novo ofício diferente de tudo que eu já fiz. Sairia do escritório e iria trabalhar ao ar livre, perto do mar. E quando me cansasse daquilo começaria tudo de novo. Assim poderia/deveria ser a vida, poder vasculhar o mundo e tudo que ele tem a oferecer.
21 abril, 2010
Tarantino x Irmãos Coen
Filmes do Tarantino
1992 - Cães de aluguel
1994 - Pulp Fiction - Tempo de violência
1997 - Jackie Brown
2003 - Kill Bill: Volume 1
2004 - Kill Bill: Volume 2
2005 - Sin City - A cidade do pecado
2009 - Bastardos Inglórios
2014 - Kill Bill 3
Filmes dos irmãos Coen
2009 - A Serious Man (Um homem de família)
2008 - Queime Depois de Ler
2007 - Onde os Fracos Não Têm Vez
2006 - Paris, je t'aime
2004 - The Ladykillers
2003 - Intolerable Cruelty
2001 - The Man Who Wasn't There
2000 - O Brother, Where Art Thou? (E aí meu irmão, cadê você?)
1999 - The Big Lebowski (O grande Lebowski)
1996 - Fargo
1994 - The Hudsucker Proxy
1991 - Barton Fink
1990 - Miller's crossing
1987 - Raising Arizona (Arizona nunca mais)
1984 - Blood Simple (Gosto de sangue)
Divirta-se!!