Sei sulla pagina 1di 14

Aula 3: Desacoplamento 2.

Parte
Na ltima aula, ns falamos a respeito da importncia das dependncias entre as partes do programa
em um projeto de software. Uma boa linguagem de programao permite a voc expressar as
dependncias entre as partes, alm de control-las prevenindo o surgimento de dependncias no
planejadas. Nesta aula, ns vamos demonstrar os aspectos do Java que podem ser utilizados para
expressar e controlar dependncias. Vamos estudar tambm uma variedade de solues para um
problema simples de programao, ilustrando com nfase o papel das interfaces.

3.1 Reviso: Diagrama de Dependncias Modular


Vamos comear com uma breve reviso do diagrama de dependncia modular (MDD) da ltima
aula. Um MDD mostra dois tipos de partes de programas: partes de implementao (classes em
Java) exibidas como retngulos com uma nica faixa no topo, e as partes de especificao exibidas
como retngulos com faixas tanto no topo quanto na parte de baixo. A organizao das partes em
agrupamentos (tal como packages1, ou pacotes, em Java) pode ser expressa no MDD atravs de
contornos englobando as partes do programa. Assim como definido pelo estilo de diagrama
denominado Venn-diagramstyle.
Uma flecha plana com a ponta aberta conecta uma parte de implementao A com uma parte de
especificao S, e expressa que o significado de A depende do significado de S. Isto, pois a
especificao S no pode, por si s, ter um significado dependente de outras partes, o que garante
que o significado de uma parte pode ser determinado a partir da prpria parte e da especificao da
qual ela depende, no sendo necessrio quaisquer outras informaes. Uma flecha pontilhada de A
para S significa uma dependncia fraca; ela expressa que A depende apenas da existncia de uma
parte que satisfaa especificao S, mas que, na verdade, no possui dependncia de nenhum
detalhe de S. Uma flecha com a ponta fechada de uma parte de implementao A para uma parte de
especificao S expressa que A satisfaz S; seu significado est em conformidade com o significado
de S.
Graas ao fato de que as especificaes so to essenciais, ns iremos sempre assumir que elas
esto presentes. Na maioria das vezes, ns no iremos desenhar partes de especificao
explicitamente, portanto, uma flecha de dependncia entre duas partes A e B deve ser interpretada
como uma dependncia de A para a especificao de B, e como uma flecha de conformidade de B
para sua especificao. Ns iremos demonstrar as interfaces do Java como partes de especificao
explicitamente.
1

O termo package ser utilizado como sinnimo de pacote com a inteno de se criar familiaridade com os
termos da linguagem Java.

30

3.2 Java Namespace


Como qualquer grande trabalho escrito, um programa se beneficia de uma organizao estrutural
hierrquica. Quando se tenta compreender uma grande estrutura, sempre til observ-la de baixo
para cima, iniciando-se com os nveis mais grosseiros da estrutura e procedendo-se para nveis mais
e mais detalhados. O sistema de nomes do Java suporta esta estrutura hierrquica. E promove
tambm um outro importante benefcio. Componentes diferentes podem usar os mesmos nomes
para seus subcomponentes, com distintos significados locais. No contexto do sistema como um
todo, os subcomponentes tero nomes que so determinados pelos componentes dos quais eles
pertencem, evitando confuses. Isto vital, pois permite aos desenvolvedores trabalharem
independentemente sem se preocupar com conflitos de nomes.
Agora apresentaremos como o sistema de nomes do Java funciona. Os componentes principais so
as classes e as interfaces, que possuem designaes de nomes de mtodos e de nomes de campos.
Variveis locais (dentro de mtodos) e argumentos de mtodos tambm so designados. Cada nome
em um programa Java possui um escopo, ou abrangncia: uma poro do texto do programa dentro
da qual aquele nome vlido e atado quele componente. Argumentos de mtodos, por exemplo,
tm o escopo do mtodo; campos tm o escopo da classe, e s vezes um escopo ainda maior. O
mesmo nome pode ser usado para referenciar coisas diferentes quando no h ambigidade. Por
exemplo, possvel utilizar-se o mesmo nome para um campo, um mtodo e uma classe; consulte a
especificao (spec) da linguagem Java para obter exemplos.
Um programa Java organizado em packages, ou pacotes. Cada classe ou interface possui seu
prprio arquivo (desconsiderando-se inner classes, ou classes internas, que no sero discutidas).
Os packages refletem a estrutura de diretrios. Da mesma forma que diretrios, packages podem ser
aninhados em estruturas de profundidades arbitrrias. Para organizar seu cdigo em packages, voc
deve fazer duas coisas: primeiro, voc indica no topo de cada arquivo a quais packages esta classe
ou interface pertence e, segundo, voc organiza os arquivos fisicamente em uma estrutura de
diretrios de forma que eles estejam de acordo com a estrutura dos packages. Por exemplo, a classe
dnj.browser.Protocol seria um arquivo chamado Protocol.java no diretrio dnj/browser.
Pode-se demonstrar esta estrutura no nosso diagrama de dependncias. As classes e interfaces
formam as partes entre as quais as dependncias so esquematizadas. Packages so mostrados como
contornos englobando estas classes e interfaces. s vezes conveniente esconder as dependncias
exatas entre as partes de diferentes packages e apenas mostrar um arco de dependncia no nvel dos
packages. Uma dependncia de um package significa que alguma classe ou interface (podem ser
vrias) daquele package possui uma dependncia; uma dependncia sobre um package significa

31

uma dependncia de uma classe ou interface (podem ser vrias tambm) que pertence quele
package.

3.3 Controle de Acesso


Os controles de acesso do Java permitem que se controlem as dependncias. No texto de uma
classe, possvel indicar quais outras classes podem ter dependncias sobre ela, desta forma,
possvel, at certo grau, controlar a natureza das dependncias.
Uma classe declarada como public pode ser referenciada por quaisquer outras classes; do contrrio,
ela s pode ser referenciada por classes dentro do mesmo package. Portanto, atravs deste
modificador podemos evitar dependncias de qualquer outra classe que pertena a outro package.
Membros de uma classe isto , seus campos e mtodos podem ser marcados como public,
private ou protected. Um membro public pode ser acessado de qualquer lugar. Um membro private
s pode ser acessado de dentro da classe onde declarado. Um membro protected pode ser
acessado de dentro do package, ou de fora do package por uma subclasse2 da classe onde o membro
declarado criando, portanto, um efeito h muito conhecido de que um membro protected mais
acessvel, ao invs de menos acessvel, como a idia de proteo presume.
Recorde-se que uma dependncia de A sobre B significa uma dependncia de A sobre a
especificao de B. O uso de mtodos modificadores entre os membros de B nos permitem controlar
a natureza das dependncias ao alterar-se quais membros pertencem especificao de B. O
controle do acesso aos campos de B uma ajuda para se alcanar independncia de representao,
mas nem sempre uma garantia (como veremos adiante no curso).

O termo subclasse, utilizado no decorrer do texto, refere-se prtica de derivao de classes da


programao orientada a objetos.

32

3.4 Linguagens Seguras


Uma propriedade chave de um programa a de que uma parte s deveria depender de outra se o
fizermos explicitamente referenciando a outra parte atravs de seu nome. Isto parece bvio, mas, de
fato, esta uma caracterstica vlida apenas para as chamadas linguagens de programao
seguras. Em linguagens no seguras, o texto em uma parte pode afetar o comportamento de outra
sem que nomes sejam compartilhados. Isto nos leva aos chamados bugs traioeiros que so
dificlimos de se detectar, e que podem ocasionar efeitos desastrosos e imprevisveis.
Veja como eles surgem. Considere um programa escrito em C no qual um mdulo (em C apenas
um arquivo) faz a atualizao de um array. Uma tentativa de se definir o valor de um elemento de
um array alm de seus limites s vezes ir falhar, pois causa uma violao de memria, atingindo
uma rea de memria alm daquela definido para o processo. Mas, infelizmente, na maioria das
vezes isso ir funcionar, e o resultado ser a escrita de um pedao arbitrrio de memria
arbitrrio, pois o programador no sabe como o compilador alocou a memria do programa, e no
pode predizer quais outras estruturas de dados foram afetadas. Como resultado, uma atualizao do
array a pode afetar o valor de uma estrutura de dados com o nome d, por exemplo, que declarada
em um mdulo diferente e que nem mesmo possui um tipo em comum com a.
Linguagens seguras controlam estes efeitos atravs de diversas tcnicas combinadas. Checagem
dinmica de limites de arrays previnem o tipo de atualizao que acabamos de mencionar; em Java
uma exceo seria lanada. O gerenciamento automtico de memria garante que a memria no
seja liberada e em seguida, erroneamente, utilizada. Ambas as tcnicas baseiam-se na idia
fundamental de tipagem forte, que garante que um acesso declarado como sendo um valor de um
tipo t no programa texto ser sempre um acesso a uma valor do tipo t em tempo de execuo. No
h risco de que cdigo projetado para ser utilizado sobre arrays seja aplicado a uma string ou a um
inteiro.
Linguagens seguras surgiram em 1960. Algumas famosas linguagens seguras incluem Algol-60,
Pascal, Modula, LISP, CLU, Ada, ML, e agora Java. interessante notar que por muitos anos a
indstria reclamou que os custos da segurana destas linguagens eram muito altos, e que era
invivel migrar de linguagens no seguras (como C++) para linguagens seguras (como Java). Java
se beneficiou de muita publicidade a respeito de applets, e agora que a linguagem largamente
utilizada, muitas bibliotecas esto disponveis e existem muitos programadores que conhecem Java,
muitas companhias deram o brao a torcer e esto reconhecendo os benefcios de uma linguagem
segura. Algumas linguagens seguras garantem a correo de tipagem em tempo de compilao
atravs de tipagem esttica. Outras, como Scheme e LISP, realizam sua checagem de tipo em
tempo de execuo, sendo que seus sistemas de tipagem apenas distinguem os tipos primitivos.
Veremos rapidamente como um sistema de tipagem mais expressivo tambm pode ajudar no

33

controle das dependncias. Se a confiabilidade importante, sbio utilizar uma linguagem segura.
Na aula 1 eu contei uma estria sobre o uso de linguagens no seguras em um sistema de raios-x.

3.5 Interfaces
Em linguagens com tipagem esttica, podem-se controlar dependncias atravs da escolha de tipos.
Pode-se dizer que uma classe que menciona apenas objetos do tipo T no pode ter uma dependncia
de uma classe que possui objetos de um tipo T diferente. Em outras palavras, pode-se deduzir, a
partir dos tipos de uma classe, de quais outras classes esta classe depende.
No entanto, em linguagens com subtipos (tipos derivados), uma coisa interessante possvel.
Suponha que a classe A mencione apenas a classe B. Isto no significa que apenas mtodos criados
a partir da classe B possam ser chamados. Em Java, os objetos instanciados a partir de uma
subclasse C de B so tidos como tendo tambm o tipo B, assim, mesmo que A no possa criar
objetos da classe C diretamente, ela pode acess-los por intermdio de outra classe. O tipo C dito
ser um subtipo do tipo B, pois um objeto C pode ser utilizado quando um objeto B aguardado. Isto
chamado substituibilidade, ou seja, a possibilidade de substituir.
Na verdade, a prtica de se criar subclasses funde dois princpios distintos. Um a subtipagem: que
define que objetos de uma classe C so tidos como tendo tipo compatvel com B, por exemplo. O
outro a herana: que define que o cdigo da classe C pode reutilizar o cdigo de B. Mais adiante
neste curso iremos discutir algumas das conseqncias infortnias de se fundir estes dois princpios,
e veremos como a substituibilidade nem sempre funciona, como de se esperar. Por enquanto,
iremos focar no mecanismo de subtipagem apenas, pois o que importa na nossa discusso. O Java
prov uma noo de interfaces que proporciona mais flexibilidade na prtica da subtipagem do que
o uso de subclasses. Uma interface Java , na nossa terminologia, uma parte de especificao pura.
Ela no contm cdigo executvel, utilizada apenas para se alcanar desacoplamento.
Veja como funciona. Ao invs de se ter uma classe A dependente de uma classe B, introduz-se uma
classe I. Agora, A menciona I ao invs de B, e B deve satisfazer a especificao de I. claro que o
compilador Java no trabalha com especificaes comportamentais: ele apenas checa se os tipos dos
mtodos de B so compatveis com os tipos declarados em I. Em tempo de execuo, toda vez que
A estiver aguardando um objeto do tipo I, um objeto do tipo B tambm aceito. Por exemplo, na
biblioteca Java, h uma classe chamada java.util.LinkedList que implementa listas encadeadas. Se
voc estiver escrevendo cdigo que exige apenas que um objeto seja uma lista, e no
necessariamente que seja uma lista encadeada, deve-se utilizar o tipo java.util.List no seu cdigo, o
que uma interface implementada por java.util.LinkedList. Existem outras classes como ArrayList e
Vector que implementam esta interface. Desde que seu cdigo refira-se apenas interface, ele ir
funcionar com qualquer uma destas classes de implementao.

34

Vrias classes podem implementar a mesma interface, e uma classe pode implementar vrias
interfaces. Pelo contrrio, uma classe pode herdar no mximo uma classe. Por causa disso, algumas
pessoas utilizam o termo herana de mltipla especificao para descrever a funcionalidade das
interfaces do Java, ao contrrio da verdadeira herana mltipla na qual pode-se reutilizar cdigo de
mltiplas superclasses.
Inicialmente, as interfaces trazem dois benefcios. Primeiro, elas permitem que se expressem partes
de pura especificao no cdigo, de forma que seja possvel garantir que o uso da classe B por uma
classe A envolve apenas uma dependncia de A para a especificao S, e no em outros detalhes de
B. Segundo, as interfaces permitem criar vrias partes de implementao que estejam em
conformidade com uma nica especificao, sendo que a seleo de qual parte de implementao
ser usada ocorrer em tempo de execuo.

3.6 Exemplo: Instrumentao de um Programa


No restante da aula, iremos estudar alguns mecanismos de desacoplamento no contexto de um
exemplo que pequeno, mas que representativo de uma importante classe de problemas.
Suponha que se queiram reportar os passos incrementais de um programa no decorrer de sua
execuo, exibindo seu progresso linha por linha. Por exemplo, em um compilador com suas
diversas etapas, pode-se desejar exibir uma mensagem quando cada etapa comea e termina. Em um
cliente de e-mail, podemos exibir cada um dos passos envolvidos na tarefa de se fazer o download
dos e-mails a partir de um servidor. Este tipo de mecanismo de acompanhamento da execuo til
quando os passos individuais podem levar um longo tempo de execuo ou quando so propensos
falha (de forma que o usurio possa cancelar o comando que originou a execuo). Barras de
progresso so muitas vezes utilizadas neste contexto, mas elas introduzem complicaes adicionais
com as quais no iremos nos preocupar.
Como um exemplo concreto, considere um cliente de e-mail que possua um package principal
(core) contendo uma classe Session com cdigo projetado para estabelecer uma sesso de
comunicao com um servidor e para fazer o download de mensagens, uma classe Folder para os
objetos que modelam pastas e seu contedo, e uma classe Compactor que contm o cdigo para
compactar a representao das pastas no disco. Assuma que h chamadas de Session para Folder e
de Folder para Compactor, assuma ainda que as intensas atividades de recursos computacionais que
queremos instrumentar ocorrem apenas em Session e Compactor, e no em Folder.
O mdulo diagrama de dependncia mostra que Session depende de Folder, que possui uma
dependncia mtua de Compactor.

35

Iremos analisar uma variedade de meios para implementar nosso mecanismo de instrumentao, e
iremos estudar as vantagens e desvantagens de cada. Comeando pelo mais simples, mais ingnuo
projeto possvel, podemos distribuir sentenas como
System.out.println (Iniciando download);
ao longo do programa.

3.6.1 Abstrao por parametrizao


O problema com este esquema bvio. Quando rodamos o programa em modo batch, podemos
redirecionar a sada de dados padro do programa para um arquivo. Percebemos, ento, que isto
seria til para gerar mensagens acrescidas da informao do momento quando elas ocorreram, de
maneira que poderamos mais tarde, quando lermos o arquivo de mensagens, saber quanto tempo
durou cada um dos vrios passos executados. Desejamos que nossas sentenas sejam da forma
System.out.println (Iniciando download em: + new Date ());
O que deveria ser fcil, mas no . Temos que procurar todas as sentenas presentes em nosso
cdigo (e distingu-las de outras chamadas a System.out.println destinadas a outros propsitos), e
alterar cada uma delas separadamente.
claro, o que deveramos ter feito definir um procedimento para encapsular esta funcionalidade.
Em Java, seria feito atravs de um mtodo esttico:
public class StandardOutReporter {
public static void report (String msg) {
System.out.println (msg);
}
}
Agora, a alterao pode ser realizada em um nico local no cdigo. Apenas modificamos o

36

procedimento para
public class StandardOutReporter {
public static void report (String msg) {
System.out.println (msg + at: + new Date ());
}
}
Matthias Felleisen chama isso de princpio do ponto de controle individual. O mecanismo neste
caso um com o qual voc deve estar familiar: o curso 6001 o chama de abstrao por
parametrizao, pois cada chamada ao procedimento, tal como
StandardOutReporter.report (Iniciando download);
uma instncia da descrio genrica, com o parametrizador msg atado a um valor particular.
Podemos ilustrar o ponto de controle individual em um diagrama de dependncia modular.

Introduzimos uma nica classe da qual as classes que utilizam o mecanismo de instrumentao
dependem: StandardOutReporter. Perceba que no h dependncia de Folder para
StandardOutReporter, pois o cdigo de Folder no faz chamadas para esta outra classe.

3.6.2 Desacoplamento com Interfaces


No entanto, este esquema est bem longe da perfeio. Automatizar a funcionalidade em uma nica
classe foi uma boa idia, mas o cdigo ainda possui uma dependncia na noo de escrita para a
sada de dados padro. Se quisssemos criar uma nova verso do nosso sistema com uma interface
grfica de usurio (GUI), precisaramos substituir esta classe com uma outra contendo o cdigo
apropriado para a GUI. Isto significaria alterar todas as referncias no package core para uma classe
diferente, ou alterar o cdigo da prpria classe, e ter que manipular duas verses incompatveis da

37

classe com o mesmo nome. Nenhuma das duas uma boa opo.
De fato, o problema pior do que isso. Em um programa que utiliza GUI, escreve-se para a GUI
atravs de uma chamada a um mtodo de um objeto que representa parte da interface grfica: um
painel de texto, ou um campo de mensagem. Em Swing, o toolkit de interfaces de usurio do Java,
as subclasses de JTextComponent possuem um mtodo setText. Dado um componente
JTextComponent representado pela varivel outputArea, por exemplo, a sentena de exibio
poderia ser:
outputArea.setText (msg)
Como vamos passar a referncia para o componente na posio de chamada (na nova classe
StandardOutReporter)? E como vamos faz-lo sem introduzir cdigo especfico do Swing na classe
responsvel por reportar os progressos da execuo do programa?
As interfaces Java provm a soluo. Criamos uma interface com um nico mtodo para reportar os
progressos de execuo que ser chamado para exibio dos resultados.
public interface Reporter {
void report (String msg);
}
Agora, acrescentamos a cada mtodo do nosso sistema um argumento deste tipo. A classe Session,
por exemplo, pode ter um mtodo download:
void download (Reporter r, ) {
r.report (Iniciando download );

}
Agora definimos uma classe que ir implementar o comportamento do mtodo report. Iremos
utilizar a sada de dados padro como nosso exemplo, por razes de simplicidade:
public class StandardOutReporter implements Reporter {
public void report (String msg) {
System.out.println (msg + at: + new Date ());
}
}

38

Esta classe no a mesma classe que a anterior, e que possua o mesmo nome. O mtodo no mais
esttico, de maneira que podemos instanciar um objeto da classe e chamar o mtodo a partir dele.
Alm do mais, indicamos que esta classe uma implementao da interface Reporter. claro, para
a sada de dados padro esta soluo no parece ser muito boa, e a criao do objeto implica em um
custo computacional. Mas, para o caso da GUI, iremos fazer algo mais elaborado e criar um objeto
que esteja atado ao mecanismo JTextComponent em particular.
public class JTextComponentReporter implements Reporter {
JTextComponent comp;
public JTextComponentReporter (JTextComponent c) {comp = c;}
public void report (String msg) {
comp.setText (msg + at: + new Date ());
}
}
No topo do programa, iremos criar um objeto e pass-lo:
s.download (new StandardOutReporter (), );
Onde s representa uma instncia da parte (ou classe) Session.
Agora, alcanamos algo interessante. A chamada ao mtodo report executa, em tempo de execuo,
cdigo que invoca System.out. Mas mtodos como o download da classe Session dependem apenas
da interface Reporter, que no faz referncia a nenhum mecanismo de sada de dados especfico.
Conseguimos, com sucesso, desacoplar o mecanismo de sada de dados e o programa, quebrando a
dependncia do ncleo do programa de seus dispositivos de sada de dados (seu I/O).
Observe o diagrama de dependncia modular. Recorde-se que uma flecha com a cabea fechada de
A para B lida como A satisfaz B. B pode ser uma classe ou uma interface; o relacionamento em
Java pode ser de implementao ou de extenso. Aqui, a classe StandardOutReporter satisfaz a
interface Reporter.
A propriedade chave do esquema que no h mais uma dependncia de nenhuma classe do
package ncleo (core) sobre uma classe do package gui. Todas as dependncias apontam (pelo
menos logicamente!) de gui para core. Para alterar a sada de dados do programa para um
mecanismo GUI, ao invs da sada de dados padro, teramos apenas que substituir a classe
StandardOutReporter pela classe JTextComponentReporter, e modificar o cdigo da classe
principal do package GUI para chamar seu construtor nas classes que contm cdigo de I/O
concreto. Este idioma, esta maneira de se fazer as coisas, talvez seja o uso mais popular das

39

interfaces, sendo muito valioso seu aprendizado e domnio.

Lembre-se que as flechas pontilhadas so dependncias fracas. Uma dependncia fraca de A para B
significa que A referencia os nomes de B, mas no referencia o nome de nenhum de seus membros.
Em outras palavras, A sabe que a classe ou interface B existe, e refere-se a variveis daquele tipo,
mas no faz chamadas a nenhum mtodo de B, e nem acessa qualquer campo de B.
A dependncia fraca de Main sobre Reporter simplesmente indica que a classe Main pode incluir
cdigo que manipula um objeto do tipo Reporter genrico; no se trata de um problema. A
dependncia fraca de Folder sobre Reporter, no entanto, um problema: o objeto do tipo Reporter
deve ser passado atravs de mtodos de Folder para mtodos de Compactor. Todo mtodo da
cadeia de chamadas que alcana um mtodo instrumentado deve receber um Reporter como
argumento. O que um incomodo, e que pode tornar doloroso um processo posterior de
aperfeioamento deste esquema.

3.6.3 Interfaces vs. Classes Abstratas


Voc deve estar se perguntando se poderamos ter utilizado uma classe abstrata ao invs de uma
interface. Uma classe abstrata uma classe que no est completamente implementada; ela no
pode ser instanciada, ela deve ser estendida atravs de uma subclasse que a completa. Classes
abstratas so teis quando se deseja produzir cdigo comum a vrias classes. Suponha que
quisssemos exibir uma mensagem dizendo quanto tempo cada passo da execuo levou. Ns

40

podemos implementar uma classe Reporter cujos objetos mantm o estado no qual estavam quando
da ltima chamada ao mtodo report, calculando, ento, a diferena de tempo entre a chamada
corrente e a ltima chamada. Ao tornar esta classe abstrata, poderamos reutilizar o cdigo em cada
uma das subclasses concretas StandardOutReporter, JTextComponentReporter, etc.
Por que no fazer com que o argumento do mtodo download da classe Session tenha esta classe
abstrata como seu tipo, ao invs de uma interface? H duas razes. A primeira que desejamos que
a dependncia sobre o cdigo de Reporter seja a mais fraca possvel. A interface no possui cdigo
nenhum; ela expressa a especificao mnima do que necessrio. A segunda razo que no h
herana mltipla em Java: uma classe pode estender no mximo uma nica outra classe. Portanto,
quando voc estiver projetando o ncleo do programa, voc no quer utilizar sua nica
oportunidade de utilizar o recurso de subclasses prematuramente. Uma classe pode implementar
qualquer nmero de interfaces, ou seja, ao escolher uma interface, voc deixa por conta do
projetista das classes Reporter a questo de como elas sero implementadas.

3.6.4 Campos Estticos


A desvantagem clara do esquema discutido na seo 3.6.3 que o objeto Reporter deve ser inserido
por todo o ncleo do programa. Se toda a sada de dados for exibida em um nico componente de
texto, parece ser no muito bom ter que passar uma referncia a este objeto pra l e pra c dentro do
cdigo. Em termos de dependncia, todo mtodo possui, no mnimo, uma dependncia fraca sobre a
interface Reporter
Variveis globais, ou campos estticos em Java, provm uma soluo para este problema. Para
eliminar muitas destas dependncias, ns podemos manter o objeto do tipo Reporter como um
campo esttico de uma classe:
public class StaticReporter {
static Reporter r;
static void setReporter (Reporter r) {
this.r = r;
}
static void report (String msg) {
r.report (msg);
}
}
Agora, tudo que precisamos fazer definir o objeto Reporter esttico no incio:

41

StaticReporter.setReporter (new StandardOutReporter ());


E podemos fazer chamadas para ele sem a necessidade de uma referncia para um objeto:
void download () {
StaticReporter.report (Iniciando download );

}
No diagrama de dependncia modular, o efeito desta alterao que agora apenas as classes que
realmente utilizam o objeto do tipo Reporter so dependentes dela:
Perceba agora que a dependncia fraca de Folder no existe mais. Ns j vimos este conceito antes,
claro, no nosso segundo esquema no qual a classe StandardOutReporter possua um mtodo
esttico. Este esquema combina o aspecto esttico com o desacoplamento que as interfaces
providenciam.
As referncias globais so cmodas, pois lhe permitem alterar o comportamento de mtodos em
nveis bem baixos da hierarquia de chamadas sem a necessidade de alterao do cdigo que os
envoca. Mas as variveis globais so perigosas. Elas podem tornar o cdigo extremamente difcil de
ser compreendido. Para se determinar o efeito de uma chamada a StaticReporter.report, por
exemplo, necessrio saber como o campo esttico r est definido. Pode haver uma chamada ao
mtodo setReporter em qualquer lugar no cdigo, e para se definir qual efeito ela tem, necessrio
traar o fluxo da execuo para se determinar quando o mtodo executado em relao ao cdigo
de interesse.

42

Outro problema com relao s variveis globais que elas apenas funcionam bem quando
realmente h um objeto que possui significado persistente. A sada padro de dados um destes
casos. Mas componentes de texto em uma GUI no so. Ns podemos, muito bem, desejar que
diferentes partes de nosso programa reportem seu progresso a diferentes painis da nossa GUI. No
esquema em que os objetos do tipo Reporter so passados de uma parte para outra do cdigo, ns
podemos criar diferentes objetos e pass-los a diferentes partes do cdigo. Na verso esttica,
teremos que criar mtodos diferentes, o que comea a degenerar a elegncia do cdigo.
Concorrncias tambm ocasionam dvidas na idia de se usar um nico objeto. Suponha que
faamos o upgrade de nosso cliente de e-mail para que seja capaz de fazer o download das
mensagens a partir de diversos servidores de forma concorrente, isto , ao mesmo tempo. Ns no
gostaramos que as mensagens de progresso de todas as sesses de download fossem intercaladas
em uma nica sada de dados.
Uma boa prtica ser cuidadoso com variveis globais. Pergunte a voc mesmo se possvel
utilizar um mesmo objeto. Normalmente, voc ir encontrar amplas razes para ter mais do que um
objeto no decorrer de seu programa. Este esquema denominado Singleton na literatura, pois a
classe possui um nico objeto.

43

Potrebbero piacerti anche