Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
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.
O termo package ser utilizado como sinnimo de pacote com a inteno de se criar familiaridade com os
termos da linguagem Java.
30
31
uma dependncia de uma classe ou interface (podem ser vrias tambm) que pertence quele
package.
32
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.
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.
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.
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
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.
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.
41
}
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