Sunteți pe pagina 1din 241

Arquitetura, Projeto e

Desenvolvimento de Sistemas
Uma abordagem ao projeto orientado a objetos,
arquitetura em camadas, persistncia e testes
verso 2014-02-02 20:34:22

Licena

Licena
O trabalho Arquitetura e Projeto de Sistemas de Mrcio Torres foi licenciado com uma Licena
Creative Commons - Atribuio - NoComercial - CompartilhaIgual 3.0 No Adaptada.
Podem estar disponveis autorizaes adicionais ao mbito desta licena em:
http://academico.riogrande.ifrs.edu.br/~marcio.torres/livros/aps

Atribuio-Uso no-comercial-Compartilhamento
pela mesma licena 3.0 Unported
(CC BY-NC-SA 3.0)
Voc tem a liberdade de:
COMPARTILHAR: copiar, distribuir e transmitir a obra.
REMIXAR: criar obras derivadas.
Sob as seguintes condies:
ATRIBUIO: Voc deve creditar a obra da forma especificada pelo autor ou licenciante (mas
no de maneira que sugira que estes concedem qualquer aval a voc ou ao seu uso da obra).
USO NO-COMERCIAL: Voc no pode usar esta obra para ns comerciais.
COMPARTILHAMENTO PELA MESMA LICENA: Se voc alterar, transformar ou criar em
cima desta obra, voc poder distribuir a obra resultante apenas sob a mesma licena, ou sob
uma licena similar presente.
Ficando claro que:
RENNCIA: Qualquer das condies acima pode ser renunciada se voc obtiver permisso do
titular dos direitos autorais.
DOMNIO PBLICO: Onde a obra ou qualquer de seus elementos estiver em domnio pblico
sob o direito aplicvel, esta condio no , de maneira alguma, afetada pela licena

Licena

Sumrio
Licena........................................................................................................................................ 2
Prlogo........................................................................................................................................ 8
Prefcio....................................................................................................................................... 9
Sobre este Livro......................................................................................................................... 10
Convenes usadas.............................................................................................................. 10
Organizao dos captulos....................................................................................................11
Para quem (e no ) este livro...........................................................................................13
Como usar este livro............................................................................................................. 13
Reconhecimentos...................................................................................................................... 15
Sobre o Autor............................................................................................................................. 16
Captulo 0 Conceitos e Contextos...........................................................................................17
Programador: o amador e o profissional...........................................................................17
Pedaos de mau cdigo...................................................................................................17
Qual a diferena entre programador e desenvolvedor?....................................................17
Projetista: o preo do amanh..........................................................................................17
Software Design == Projeto de Software..........................................................................18
Pedaos de mau design...................................................................................................18
O bom, o mau e o impacto na Qualidade de Software.....................................................18
Princpios, Padres, Tcnicas, Prticas e Bruxarias.........................................................18
Teste [[dar melhor nome]].................................................................................................18
Trilhando o caminho......................................................................................................... 18
Bibliografia........................................................................................................................ 18
Parte 1: Codificao de Funcionalidades e Tcnicas.................................................................19
Captulo 1: Prticas e Tcnicas de Codificao....................................................................20
Qualidade do Cdigo........................................................................................................20
Programando.................................................................................................................... 22
Programando por intuio............................................................................................22
Programando por coincidncia.....................................................................................25
Programando deliberadamente....................................................................................26
Cdigos fceis de entender..............................................................................................27
Estilos e convenes de codificao................................................................................27
Boas prticas para escrever cdigo..................................................................................29
Use nomes que deixem o propsito bem claro............................................................29
Deixe as diferenas bem visveis e agrupe as semelhanas criteriosamente..............30
Use nomes pronunciveis............................................................................................32
Substantivos como nomes de classes Verbos como nomes de mtodos....................32
Ingls, Portugus ou em ........................................................................34
Escreva mtodos pequenos.........................................................................................36
Resolva um problema por vez......................................................................................39
Use poucos parmetros nos mtodos, quanto menos melhor.....................................39
Evite argumentos que servem de flag (flag arguments)...............................................43
Escreva comentrios teis...........................................................................................43
Torne os comentrios desnecessrios.........................................................................43
Exclua os comentrios irrelevantes que servem de rudo............................................44
No comente, documente!...........................................................................................45
3

Licena

Tcnicas avanadas de codificao.................................................................................47


Constructor Chaining (encadeamento de construtores)...............................................47
Fluent Interface............................................................................................................ 50
Funes Varidicas (VARARGS).................................................................................50
foreach (para cada) e iterabilidade...............................................................................52
Iterators (iteradores) e Iterabilidade.............................................................................56
Generators (Geradores)...............................................................................................59
EAFP vs LBYL............................................................................................................. 60
Static Factory Methods (mtodos estticos de fabricao)..........................................60
Exception Rethrow (relanamento de excees).........................................................62
StringBuilder Concatenation (concatenao de strings)...............................................62
Property Map (mapa de propriedades).........................................................................62
Left Hand Comparison (comparao na mo esquerda)..............................................62
Short-Circuit Evaluation (avaliao de curto-circuito)...................................................62
Array as List (array como lista).....................................................................................62
Only One Return (s um retorno).................................................................................62
Return Early (retorne cedo).......................................................................................62
Guard Clause (clusula salvaguarda)..........................................................................65
Boolean Return (retorno boleano)................................................................................65
Boolean Success/Fail Return (retorno de sucesso/falha com boleano).......................65
Default Value With Ternary Expression (valor padro com expresso ternria)..........65
Regex Validation (validao com expresses regulares).............................................65
Kluge: uma Histria POG.............................................................................................66
Kluge: Constant Interface.............................................................................................66
Kluge: Number to String...............................................................................................66
Code Golf..................................................................................................................... 66
Palavras finais sobre prticas e tcnicas..........................................................................66
Bibliografia........................................................................................................................ 66
Captulo 2: Refatoraes e Melhoria do Cdigo Existente....................................................67
Definindo Refatorao......................................................................................................67
Por que refatorar?............................................................................................................. 69
Maus cheiros no cdigo (a.k.a. Code Smell)....................................................................69
Cdigo duplicado......................................................................................................... 70
Classes e mtodo muito longos...................................................................................70
Excesso de parmetros...............................................................................................70
Grupos de dados..........................................................................................................71
Obsesso primitiva.......................................................................................................72
Comentrios (tambm conhecidos como desodorante).............................................74
Nmeros (e Strings) mgicos.......................................................................................74
Refatoraes Comuns......................................................................................................74
Renomear.................................................................................................................... 75
Extrair (introduzir) classe..............................................................................................76
Extrair (introduzir) superclasse.....................................................................................77
Extrair (introduzir) mtodo............................................................................................78
Introduzir varivel explicativa.......................................................................................80
Inverter condicional......................................................................................................80
Introduzir constante......................................................................................................82
Introduzir Objeto Parmetro.........................................................................................82
Palavras finais sobre refatoraes....................................................................................84
Bibliografia........................................................................................................................ 84
4

Licena

Parte 2: Projeto de Objetos, Princpios e Padres.....................................................................85


Captulo 3 Projeto e Modelagem de Objetos......................................................................86
Uma palavra sobre OOAD................................................................................................87
Anlise de Sistemas Orientados a Objetos..................................................................87
Projeto de Sistemas Orientados a Objetos..................................................................88
Modelagem e implementao do domnio........................................................................89
Tipos primitivos e complexos.......................................................................................90
Entidades..................................................................................................................... 90
Objetos Persistentes....................................................................................................92
Modelando Entidades do Domnio....................................................................................94
Estratgias de Validao.............................................................................................95
Mtodos comuns.......................................................................................................... 97
Associaes e Agregaes com Colees e Containers................................................100
Value Objects................................................................................................................. 107
Tipos e Objetos Imutveis..............................................................................................110
Captulo 4 Princpios de Projeto Orientado a Objetos......................................................113
Programe para uma interface no uma implementao.............................................113
Prefira composio a herana....................................................................................117
No se repita (DRY)...................................................................................................119
Princpio da Menor Surpresa (POLA).........................................................................122
Zero One Infinity Rule (ZOI).......................................................................................125
Fail-Fast Principle......................................................................................................127
Fail-Safe..................................................................................................................... 129
Separao de Comando/Consulta (CQS)..................................................................129
Princpio do Menor Privilgio (Principle of Least Privilege)........................................130
Princpio da Responsabilidade nica (SRP)..............................................................132
Princpio do Acesso Uniforme (UAP).........................................................................133
Deixe simples bundo: YAGNI, KISS, POGE, em essncia, a mesma coisa.............135
Princpio Aberto/Fechado (OCP)................................................................................136
Princpio do Reuso Comum (CRP).............................................................................141
Princpio da Substituio de Liskov (LSP)..................................................................143
Lei de Demter (LoD).................................................................................................146
Princpio da Segregao de Interfaces (ISP).............................................................148
Princpio da Inverso da Dependncia (DIP).............................................................151
SOLID........................................................................................................................ 156
Princpios, no Dogmas uma palavra final...................................................................157
Bibliografia...................................................................................................................... 157
Captulo 5 Padres de Projeto Orientado a Objetos.........................................................158
Introduo aos Design Patterns......................................................................................159
Definindo Padro de Projeto......................................................................................160
Descrio dos Padres de Projeto.............................................................................160
Padres GoF.................................................................................................................. 161
Padres Comportamentais.............................................................................................162
Observer.................................................................................................................... 162
Strategy (Estratgia)..................................................................................................166
Template Method.......................................................................................................169
Command.................................................................................................................. 173
State.......................................................................................................................... 173
Visitor......................................................................................................................... 173
Chain of Responsibility...............................................................................................173
5

Licena

Padres Estruturais........................................................................................................ 173


Composite.................................................................................................................. 173
Decorator................................................................................................................... 173
Faade....................................................................................................................... 173
Proxy.......................................................................................................................... 173
Padres Criacionais........................................................................................................174
Builder........................................................................................................................ 174
Factory Method.......................................................................................................... 174
Singleton.................................................................................................................... 175
Abstract Factory......................................................................................................... 177
Prototype.................................................................................................................... 177
Padres: viles ou mocinhos? Uma reflexo.................................................................177
Bibliografia...................................................................................................................... 177
Parte 3: Arquitetura e Projeto de Alto Nvel.............................................................................179
Captulo 6 Introduo a Arquitetura de Software..............................................................180
O que , e o que no , arquitetura?..............................................................................180
Objetivos da arquitetura..................................................................................................182
A importncia da Arquitetura e Design...........................................................................183
Consideraes para Arquitetura.....................................................................................184
Separation of Concerns (SoC)........................................................................................185
Estilos de Arquitetura......................................................................................................185
Arquitetura Cliente/Servidor............................................................................................186
Arquitetura Baseada em Componentes..........................................................................187
Arquitetura em Camadas................................................................................................188
As trs camadas tradicionais.....................................................................................189
Regra bsica da diviso em camadas........................................................................190
Tecnologias.................................................................................................................... 191
Baseadas na plataforma Java....................................................................................191
Baseadas na plataforma .NET...................................................................................192
Baseadas no PHP......................................................................................................193
Frameworks notveis para desenvolvimento Web.....................................................194
Opes emergentes...................................................................................................195
Solution Stacks.......................................................................................................... 195
Mais sobre Arquitetura....................................................................................................196
Bibliografia...................................................................................................................... 196
Captulo 7 Modularizao.................................................................................................198
API's............................................................................................................................... 198
API nas linguagens....................................................................................................200
Documentao de API's.............................................................................................201
Implementando API's.................................................................................................202
Projetando API's........................................................................................................ 204
Tratamento das entradas e excees........................................................................206
Toolkits........................................................................................................................... 206
Motivao................................................................................................................... 207
Toolkit != Framework..................................................................................................207
Utilizando Toolkits......................................................................................................207
Desenvolvendo Toolkits.............................................................................................210
Componentes de Software.............................................................................................211
Frameworks.................................................................................................................... 211
Problemas que podem ser resolvidos por frameworks...............................................211
6

Licena

Tcnicas para implementao...................................................................................211


O papel da metaprogramao....................................................................................211
Linguagens Especficas do Domnio...............................................................................211
Bibliografia...................................................................................................................... 211
Captulo 8 Padres de Arquitetura...................................................................................213
Padres de Arquitetura para Lgica do Domnio............................................................213
Padres de Arquitetura para Persistncia..................................................................215
Agora, todos juntos!...................................................................................................218
Captulo 9 Projeto e Padres de Persistncia..................................................................220
Persistncia.................................................................................................................... 220
SGBD: alguns detalhes a considerar..............................................................................221
Driver......................................................................................................................... 222
Conexes................................................................................................................... 222
Fornecedor................................................................................................................. 223
Java DataBase Connectivity (JDBC)..............................................................................225
Estabelecendo uma conexo.....................................................................................225
Padro de implementao para estabelecer conexes com o banco........................227
Carregamento de Associaes.......................................................................................231
Controle de concorrncia................................................................................................231
Ausente, a.k.a. Last Wins...........................................................................................231
Pessimista.................................................................................................................. 231
Otimista...................................................................................................................... 232
Bibliografia...................................................................................................................... 232
Parte 4: Controle da Qualidade................................................................................................233
Captulo 10 Garantia da Qualidade de Software..............................................................234
Captulo 11 Instrumentao e Depurao........................................................................235
Captulo 12 Teste de Software.........................................................................................236
Erros, Defeitos e Falhas.................................................................................................236
Heisenbugs................................................................................................................ 236
Testes............................................................................................................................. 236
Tipos de Teste........................................................................................................... 236
Estratgias de Teste..................................................................................................236
Testes estticos: PMD, Findbugs...............................................................................236
Testes unitrios: JUnit................................................................................................236
Lidando com dependncias: Fakes, Stubs e Mocks?.................................................236
Cobertura de Testes.......................................................................................................236
Statement Coverage..................................................................................................236
Branch Coverage.......................................................................................................236
Decision Coverage.....................................................................................................236
Programando com Testes...............................................................................................237
Programao Assertiva..............................................................................................237
Desenvolvimento Guiado por Testes (TDD)...............................................................237
Bibliografia...................................................................................................................... 237
Eplogo.................................................................................................................................... 238
Apndice: [[]]............................................................................................................................ 239

Prlogo

Prlogo
[[]]

Prefcio

Prefcio
Estelivrotemumpropsitobemsimples, ensinara projetarsistemas.Osmtodose
prticasabordadossopartesdaEngenhariadeSoftware(ES),quevodesdeoprojetodealto
nvelattestes.
Projetar um software (sistema, programa, aplicativo, aplicao, ) , digamos, uma
tarefaminuciosa,envolvedividiroproblemaeconsequentementeosoftwareempartesmenores
parafacilitararesoluo(eessaspartesemoutrasmenoresainda).Paraauxiliarnestaatividade
existemtcnicasdecodificao,princpiosdeprojeto,padresdeprojeto,padresdearquitetura
e heursticas, todos com o propsito de manter o software flexvel, manutenvel, estvel e
reusvel.Claro,nosoconceitosfceisdeaprenderenomenosdifceisdeensinar,acredite,
envolveoconhecimentodelinguagensdeprogramao,deorientaoaobjetos(OO)e,omais
difcil,oraciocniosobreosnveisdeabstraoerelacionamentoentreestesnveis.
Projetaredesenvolversoftwareestrelacionadoagerenciaracomplexidade,abstraindo
a, e assim a disciplina, inerentemente complexa e tem sido um desafio de ensino e
aprendizagem,relacionamentodeteoriaeprtica,eesteomotivodaexistnciadestelivro.
Esperoqueeleteajude(emeajudetambm,claro:)

Sobre este Livro

SobreesteLivro
Emboraolivrotenhaumaestruturadefinidadecaptulos,ostextosforamescritoscom
poucareviso.Podemser,esero,encottradoserosdedigitao,dogramtica,deortographia,etc,
entendacomumlivrobeta1.
Ocontedoapoiadoemrefernciasslidaseconsolidadas,sendoamaiorialivrosde
autores amplamente conhecidos e reconhecidos da rea de anlise, engenharia e
desenvolvimentodesoftware.Todossomencionadoseenumeradosnofimdecadacaptulo.A
aleituradealgunslivrosreferenciados,digamos,fortementerecomendada.
Amaioriadostemasmaisintrincados,ouconfusoseudiria,etambmaspalavraschavee
frasesmaisimportantes,possuemnotasderodapelinksparasitesqueestendemoassunto
e/ouexplicamdeoutrademaneira.
OscdigosdisponveisestonamaioriaescritosnalinguagemdeprogramaoJava,que
usadacomoreferncianestelivro,entretanto,outraslinguagenssoabordadascomfinsde
comparaoeaplicaodeprincpios,entreelas:PHP,Ruby,C#,PythoneJavaScript.No
interesse do livro (e da disciplina) ensinar estas linguagens, o interesse est em ensinar
princpiosteisparaqualquerlinguagem(emboranemsempred).
Foi intencional no seguir um modelo totalmente formal e tambm no totalmente
informal, digamos que um ponto mdio. So usados trechos tcnicos, cientficos e at
filosficos.Qualquersugestoescrevaparamim:marcio.torres@riogrande.ifrs.edu.br

Convenesusadas
Aseguiralgumasconvenesgeraisusadasnolivro,importanteentendlasesaber
uslas:

1
2

Acrnimos: algumas palavras e nomes compostos so abreviados com siglas ou


acrnimos. Na primeira vez que forem exibidos constar o nome completo e no
restantedolivro(salvoexcees)usadooacrnimo.Exemplos:AspectosAvanados
deProgramao(AAP),ProgramaoOrientadaaObjetos(POO),etc.

Ingls:nainformtica,sobretudonodesenvolvimentodesoftware,oidiomaingls
predominante2,porestemotivotermosenomesamplamenteconhecidosemingls
serografadosnasuaformaoriginal.Umatraduoserdisponibilizadanaprimeira
vez,sejaentreparntesesouemnotaderodap.Contudo,nonecessrioleitura
avanada em ingls para entender este livro, a maioria das expresses so
transparentes,comoexception(exceo),porexemplo.

Versoexperimental:http://pt.wikipedia.org/wiki/Verso_beta
Oinglsvenceu,parederesistir,sofrersmenosseforesparaoquintoestgio
10

Convenes usadas

Terminologias: terminologias consolidadas na rea sero apresentas em negrito


como em: o " processo de desenvolvimento de software faz uso frequente de
padresdeprojetoqueajudam"

Cdigos:trechosdecdigo,sejamemmeioaotextooublocos,sempreseroexibidos
usandofontedelargurafixa,comoem:usamosomtodosavepara,equando
maisextensossoapresentadosnaformaaseguir:

Oscdigofontesseroprecedidosporumttulocomoesteesucedidospelolinkparadownload
/*
* Os cdigos aparecero em fonte de largura fixa,
* dentro de retngulos como este e com destaque de sintaxe
*/
public class ClasseExemplo {
public String metodoExemplo(int parametroExemplo) {
return "Retorno #" + parametroExemplo;
}
// ...
https://gist.github.com/marciojrtorres/6159546

Este comentrio de cdigo seguido por reticncias significa cdigo omitido. s vezes
o cdigo inteiro muito longo para ser colocado na listagem, ento a parte irrelevante para o
exemplo omitida e em seu lugar so usada reticncias.
// ...

Notasimportantesquemerecematenoespecialapareceroemretnguloscomoesse

Textosemretnguloscomoessesousadosparatealertarsobremsprticasouproblemas
iminentes.algocomovocestfazendoissoerrado3

Observaesgeraisaparecemassimenormalmenteincluemdetalhesdispensveisouinformaesforado
contexto

[[ sobre os textos que aparecem entre dois colchetes, por favor ignoremos, so
comentriosdoautorparaelemesmo,ouseja,deeuparaeumesmo,umatoesquizofrnicomas
importanteparalembrardepequenasalteraeseproposies:)]]

Organizaodoscaptulos
O contedo deste livro foi, primariamente, direcionado ao ensino e aprendizagem na
disciplina de Aspectos Avanados de Programao, e mais tarde alterado para atender
Arquitetura e Projeto de Software, logo ele tenta contemplar as competncias primrias e
secundrias, segundo a minha interpretao de uma ementa resultando na compilao das
3

SenoconheceofamosoYou'redoingitwrongolheaqui:http://www.youtube.com/results?
search_query=you%27re+doing+it+wrong
11

Organizao dos captulos

competnciasdeumdesenvolvedordesoftwareempartesbemdefinidas:Codificao,Projeto,
Arquitetura,Teste.Istoresultounaseguinteestruturade12captulos:

Captulo0ConceitoseContextos:umcaptulointrodutrioqueapresentaos
conceitos e contextos bsicos necessrios para a interpretao dos captulos
posteriores. Fala de programao em geral, desenvolvimento, projeto, etc, e sua
relaocomaqualidadedesoftware.

Parte1Codificao:PrticaseTcnicas

Captulo 1 Prticas e Tcnicas de Codificao: neste captulo so


abordados conceitos de padronizao de cdigo, escrita de cdigo limpo e
legvel;

Captulo2RefatoraoeMelhoriadoCdigoExistente: nestecaptulo
treinadaahabilidadedemelhoraraqualidadedecdigolegadorealizando
refatoraes;

Parte2ProjetodeObjetos:PrincpiosePadres

Captulo 3 Projeto e Modelagem de Objetos: este captulo traz a


modelagemdeobjetosdodomnioeeseusrelacionamentos;

Captulo4PrincpiosdeProjetoOrientadoaObjetos:soapresentados
osprincpiosnorteadoresdoprojetoorientadoaobjetos,comoobjetivode
criarumaestruturadeobjetosmanutenvel,flexveledequalidade;

Captulo 5 Padres de Projeto Orientado a Objetos: so abordados


padresdeprojeto,suasmotivaesecontextos,comopropsitoderesolver
problemascomuns,recorrentes,noprojetodesistemasorientadosaobjetos.

Parte3ProjetodeAltoNvel:ArquiteturaeModularizao

Captulo6ArquiteturadeSoftware:apresentaaarquiteturadesoftware,
opapeldoarquitetoemodelosbsicosdearquiteturaparareferncia

Captulo7Modularizao:apresentaprincpiosbsicosparaelaboraruma
bibliotecadeclasses(toolkits)comumAPIconcisaeclaraetpicosparaa
construodeframeworks.

Captulo8PadresdeArquitetura: nestecaptulosodemonstradosos
padres de arquitetura tradicionais para organizar e estruturar a lgica do
sistemaseparandoadeacordocomoproblemaqueresolvem.

Captulo 9 Projeto e Padres de Persistncia: introduz conceitos


avanados de persistncia e como lidar com as diferenas entre o modelo
relacionaleorientadoaobjetos.

Parte4TestedeSoftware:ControledeQualidade

12

Organizao dos captulos

Captulo10GarantiadaQualidadedeSoftware:[[]]

Captulo11InstrumentaoeDepurao:[[]]

Captulo12TestedeSoftwarenaPrtica:entranoassuntodetestes,do
pontodevistadoprojetistaedesenvolvedor,assimsendoespecialmentetestes
estticosdecdigoetestesunitrios.Tambmtratadedetalhesavanados
comoresoluodedependnciasnostesteseousodestubsemocks;

Paraquem(eno)estelivro
EstelivrofoiinicialmenteprojetadoaosaprendizesdadisciplinadeAspectosAvanados
de Programao (AAP) e Arquitetura e Projeto de Software (APS) do curso de Anlise e
DesenvolvimentodeSistemasdoInstitutoFederaldeEducao,CinciaeTecnologiadoRio
Grande do Sul, ufa! Entretanto, se tu s um estudante de Desenvolvimento de Sistemas
OrientadosaObjetos,quedesejaconhecerasmelhoresprticas,tcnicas,princpiosepadresde
projetoeimplementao,entoestelivrotesertil.
Reiterando:emboraaorganizaoecontedodolivrotenhasidoinspiradanaementada
disciplina de APS do TADS, outras disciplinas bem como outros cursos tambm podem tirar
proveitodestelivro,porexemplo,ProgramaoOrientadaaObjetos(tambmconhecidocomo
Desenvolvimento Baseado em Objetos), Engenharia de Software, Tcnicas Avanadas de
Programao,AnliseeProjetoOrientadoaObjetos,eoutrasquedealgumaformautilizem
qualquertemaapresentadonoscaptulosanteriormenteenumerados.
Ateno, quero que fique claro que este livro no cobre construes bsicas de
programas,ouseja,elenotemporobjetivoensinaraprogramar(entendacomoconstruir ifs,
whiles, fors,funes,etc)esimaprogramarmelhor.Tambmesperadoqueoleitorentenda
osconceitosbsicosdeorientaoaobjetoscomoclasses,instncias,herana,encapsulamento,
polimorfismo,etc.SenosabesprogramarenemconhecesosconceitosbsicosdeOO,ento
estelivropodesermuitosofisticadoparati 4,enessecasosugiroaleituradoslivrosdasrieUse
acabea:Programao5eUseacabeaJava6.
OscdigoestoescritosnalinguagemJava,contudoosprincpios,padresetcnicasso
aplicveisagrandemaioriadelinguagensorientadasaobjetos:comoC#,C++,Python,Ruby,
etc,ouseja,mesmosetuprogramasemPHPaindaassim90%docontedotesertil.

Comousarestelivro
Este livro foi planejado para abordar quase todas as fases do desenvolvimento de
software, dando nfase em: Arquitetura, Projeto, Implementao e Testes. Entretanto os
captulosforamorganizadosparacomeardaImplementao(codificao)paradepoisProjeto,
depois Arquitetura e por fim Testes. Esta ordem invertida foi pensada para treinar
programadores(quemjcodifica)paraseremdesenvolvedores(quemplanejaeprojeta).Ento,
sugiro para os programadores lerem os captulos em ordem. Aqueles que j tem alguma
4

TambmnoleiaestelivrosenuncaviuosfilmesStarWars,StarTrekouMatrix:P

http://books.google.com.br/books?id=xGu1cQAACAAJ

http://books.google.com.br/books?id=cJ_YPgAACAAJ

13

Como usar este livro

experinciaemdesenvolvimento,podemleroscaptulosemqualquerordem,poisdiferentede
slides eles no tm um acoplamento temporal ou cronolgico, podem uslo como guia de
estudosouapenasparasimplesreferncia.Sempredumaatenoespecialsnotasderodape
aos hyperlinks,elesapontamparaumcontedomaisdetalhadosobredeterminadoassuntoe
visamaumentaroconhecimentosobreotema.

14

Reconhecimentos

Reconhecimentos
[[]]

15

Sobre o Autor

SobreoAutor
[[]]

16

Captulo 0 Conceitos e Contextos

Captulo0ConceitoseContextos
LeidaParcimonia7
Seemtudoomaisforemidnticasasvriasexplicaesdeum
fenmeno,aexplicaomaissimplesamelhor
WilliamdeOckham

Paracompreender,deverdade,odesenvolvimentodesoftwarenecessrioveroquadro
inteiro .Entofalaremossobreoprocessodedesenvolvimentodesoftware,aimportnciadafase
deprojeto(design)noprocesso,almdepressupostosnecessriosparaacompanharodemais
captuloscomtranquilidade.Ento,assimestecaptulo,quebuscadarabasenecessriapara
ligarospontos9etetrazerparaouniversodosdesenvolvedoresdesoftware.
8

Programador:oamadoreoprofissional
Otermoprogramadormuitosobrecarregadonosdiasdehoje.Antigamenteerauma
dasmaisconhecidasprofissesvoltadasacomputao,mashojeexistemmuitosnovostermos
como:GerentedeProjeto,DesenvolvedordeSoftware,ArquitetodeSoftware,Desenvolvedor
Web,DesenvolvedordeFrontend,EngenheirodeSoftware,etc.Paraevoluirnestelivrovamos
simplificar programador como sendo um profissional com a habilidade de escrever cdigos,
software,paraqueocomputadorresolvaumproblema.
Comaevoluodosprojetosdesoftware,linguagens,plataformas,etc,osprogramadores
devemevoluir.Programar,hoje, umaatividadecoletiva,decdigofontecompartilhado,de
desenvolvimentodesistemasheterogneos,partemobile,partewebepartedesktop,equetem
umciclodevidamuitolongo,emespecialnoperododeoperaes(manuteno).
As empresas no precisam de algum que codifique para resolver o problema, elas
precisamdealgumquecodifiquepararesolveroproblema,escrevendoumcdigofontelegvel,
fcildeentender,comboaperformanceequeinterajabemcomoutrossubsistemas,sejamoutros
cdigosdomesmosoftwareououtrossoftwares.

7
8
9

MaissobreaLeidaParcimniaaqui:http://pt.wikipedia.org/wiki/Navalha_de_Occam
Tambmconhecidocomoligueospontos:http://en.wikipedia.org/wiki/Connect_the_dots
TermoeternizadonodiscursodoSteveJobs:http://www.google.com.br/search?
q=steve+jobs+discurso+stanford

17

Captulo 0 Conceitos e Contextos

Humaenxurradadegenteingressandonomercadodedesenvolvimentodesoftware.
Tem muita gentenova ecom treinamento. Mas, infelizmente, uma seleta fatia deste grande
grupoevoluiegalgacargos(esalrios)maisatrativosdevidoaoseuprofissionalismo,porque
poroutrolado,existemuitoamadorismonodesenvolvimento(ouprogramao,comoquiser)de
sistemas.
fcilperceberadiferenaentreoprogramadoramadoreoprofissional.Oprofissional
aquelequerealmenteseimportacomoquefaz,ouseja,aquelequesempreplaneja,projetaefaz
oseumelhor.Oamadoraquelequefazomnimo,semplanejamento,semprojees,sem
importarsecomofuturo,dosistemaeseu.
Paraexemplificar,voumostraraseguir10situaes,entretantasoutras,quecolocam
ladoaladoodesempenhodoprofissionaledoamador:

Oprofissionalescreveumcdigoclaroparaqueseuscolegasentendam,eoamador
nosepreocupacomalegibilidadeecodificacomoseomesmocdigonuncamais
venhaaserreformado,nemporelemesmo.

Oprofissionalresolvenoapenasoproblemaatualmastambmosproblemasfuturos
semelhantes,eoamadorfazomnimopararesolveroproblemaatuales.

Oprofissionalcriapedaosreutilizveisdecdigo,constribibliotecasecomponentes
desoftwareosquaissoincludosecompartilhadosentreprojetos,eoamadorcria
cdigosmonolticos,imveisequandoprecisareutilizarcdigousaocopiar/colar.

O profissional conversa com seus colegas, difunde seu conhecimento, e usa o


vocabulrio tcnico adequadamente para passar suas ideias, e o amador evita se
comunicarenoconheceovocabulriotcnico,noseimportacomprincpios,nem
padresoutcnicasdeprojeto.

Oprofissionaldominaalinguagememqueestprogramando,conhecedetalhesda
sintaxeeasbibliotecasdisponveis,noreinventaaroda,eoamadorresolvetudo
usandoosconstrutosmaisbsicosefrequentementeescreveumcdigoqueresolve
umproblemaquejfoiresolvido.

O profissional usa a ferramenta certa para o problema certo, e o amador tenta


resolvertodososproblemascomamesmaabordagemsempre.

Oprofissionalacreditanapropriedadecoletivadecdigo,sugerequeseuscolegas
usemealteremseucdigoeusaealteraocdigodeseuscolegas,eoamadorno
querquemexamnoseucdigoemuitomenosaceitamexernocdigosdeterceiros,
comopensamentodecadaumcomseuproblema.

Oprofissionalllivrostcnicos,blogsdeespecialistasegurus,eoamadornose
importadeler,equandoprecisadeumaideiausaoGoogleabrindoprimeirolinkque
aparece.

Oprofissionaltestaseucdigo,projetaasentradasesadaspossveiseantecipaseaos
errosdocliente,eoamadortestaapenascomaespecificaoquerecebeu,situaes
nopensadaspeloanalistaestofadadasasorte.
18

Captulo 0 Conceitos e Contextos

Oprofissionalsabeusarferramentasdedesenvolvimento,conheceteclasdeatalho,
comandos do terminal e automatiza suas tarefas mais comuns, o amador no se
importa com atalhos, ignora comandos do console e faz repetitivamente e
manualmentesuastarefas.

Apslevantarestestpicos,gostariadefinalizarcomumespecial:existeoamadorque
amador por escolha, ou seja, ele sabe que est fazendo errado e negligente. Este tipo de
amadorismobempiorqueaquelequenotemumbomdesempenhoporignorncia.Aceiteum
conselho:abraceaprofisso,torneseprofissional.

Pedaosdemaucdigo
[[apresentarobservaespontuaissobreadistinoentreumbomeummaucdigo]]

Qualadiferenaentreprogramadoredesenvolvedor?
[[usarosargumentosexistentes]]

Projetista:opreodoamanh
[[comearafalardeprojetar]]

SoftwareDesign==ProjetodeSoftware
[[]]

Pedaosdemaudesign
[[]]

Obom,omaueoimpactonaQualidadedeSoftware
[[]]

Princpios,Padres,Tcnicas,PrticaseBruxarias
[[]]

Testando,1,2,3,teste,som[[darmelhornome]]
[[]]

Trilhandoocaminho
19

Captulo 0 Conceitos e Contextos

[[observaesimportantesantesdecomear]]

Bibliografia

20

Parte 1: Codificao de Funcionalidades e Tcnicas

PARTE1:CODIFICAODE
FUNCIONALIDADESETCNICAS
Ocontedodestapartetemoobjetivodemelhorarahabilidadedeprogramar.Otema
central o cdigofonte e a habilidade de escrevlo com qualidade, inteligibilidade,
estabilidade,performancee,porqueno,atalegncia:)

21

Captulo 1: Prticas e Tcnicas de Codificao

Captulo1:PrticaseTcnicasde
Codificao
Umaeapenasumavez
Umadascoisasqueeuestivetentandofazerfoiprocurarpor
simplificaes ou regras por trs de bons e maus projetos.
Pensoqueumadasmaisvaliosasregras evitarduplicao.
"Umaesomenteumavez"afrasedaProgramaoExtrema.
MartinFowler

Sim, eu sei que tu j sabesprogramar, masestecaptulo tratar decomo programar


melhor.Muitosprogramadorescriamcdigo,digamos,paraomomento,quecomcertezano
omelhordoscdigos.comumosprogramadoresesqueceremqueoutrosprogramadoresusaro
eprovavelmentedaromanutenonestecdigo.
Umamigomeu,empresriodareadeTI,repete:"difcilencontrarbomprogramador
hoje".Euconcordo,afinalboapartedosprogramadorespensaassim:"Sefunciona,nomexe",
e hporestemotivoqueexistetantocdigofeio,ruimedifcildemanter.
Existecdigofeioemqualquerlinguagem,claro,penso,algumasmaisdoqueoutras,
devido a permissividade e liberdade dada pela linguagem, mas ainda responsabilidade do
programador(oudesenvolvedor)escreverbomcdigo,umcdigolimpoeclaro.
Entretanto, quase sempre, no to simples assim, escrever de primeira, um cdigo
perfeito,ousuficientementebom.Anossainterpretaodoproblemaedasoluomudaacada
vezquelemos,comoescreverumamsica,etemosanecessidadedealterarocdigoparadar
lheclareza.Esseprocesso,dealterarcdigoexistenteefuncionalparadarclareza,chamadode
refatoraoetambmserabordadonestecaptulo.

QualidadedoCdigo
Codifiqueparaosoutros
Escreveteucdigocomoseapessoaqueirmantlofosseum
serialkillerpsicticoquesabeondetumoras
autordesconhecido

22

Captulo 1: Prticas e Tcnicas de Codificao

Comodiferenciarumcdigolimpodeumcdigosujo?Bem,notodifcil,digamos
que,setunoconseguesentenderaideiageraldeum,porexemplo,mtodo,eletemumcdigo
sujo.Maucdigotrazvriosmalefcios,como:

Reduo da produtividade: leva mais tempo para alterar um cdigo confuso e


conformeeleaumentaacabasetornaaindamaisdifcilattornarseimpossvelde
mantlo;

Facilidadedeintroduzirbugs:umcdigoruimpodelevaraminterpretao,mau
entendimentodeseupropsito,oquelevaafacilidadedeintroduzirdefeitosporno
entendlocorretamente.

Dificuldadedeeliminarbugs:podelevarumbomtempotentandocompreenderum
cdigoruimparadepoisacharapartequeestcomproblema;

Popularidade:seuscolegasdetrabalhovoteodiarquandopuseremamonoteu
cdigo(srio:).

Excessodetrabalho:Issopodelevarasituaescomo:novoumexernessecdigo,
dparao<nomeaqui>,elequefezeseleentende,emoutraspalavras,escrever
cdigosfeiosecomplexosvotefazertrabalharmais.

Anicamedidavlidadequalidadedocdigo:?#$@?porminuto

[[introduzirfontedaimagem]]
Hmuitomaisoqueexemplificardoquefalar,porissoestecaptuloestarlotadode
exemploscomopropsitodetefazerdiferenciarbomcdigodemaucdigo.

23

Captulo 1: Prticas e Tcnicas de Codificao

Programando
Acreditoquecomtodasasdicasdecdigolimpoerefatoraojtenhasumaboanoo
do que um cdigo claro e eficiente. Programar uma atividade que exige concentrao,
raciocniolgicoapuradoecriatividade.Assimcomoescreverumdiscurso,talvez,apartemais
difcilescolherporondecomear.Noexistemmuitasdicasdecomoiniciarocdigo,mesmoas
queexistemnoseaplicamatodososcasos.Aminhasugesto:simplesmentecomececomo
umrascunho,escrevaalgo,esenoficarbom,refatore.
bem comum, no incio, no conseguir observar quantas classes e mtodos sero
necessriosparaimplementarafamigeradafuncionalidade.Tupodesescolher,penso,entretrs
abordagens:

Amaistpicaepiorcriarumaclassecomummtodoquefaztodootrabalho.a
tpica programao adhoc,sem projeto, semplanejamento, aprimeiraescolha do
programadorinexperiente.

Amaisformal,escolhadeumprogramadorexperienteemetdiconoprogramar.
Issomesmo,aoinvsdeescreverumcdigoele desenha emumpapelasclassese
mtodosnecessriosparaimplementarafuncionalidade,usandoanotaoUMLcom
diagramasdeclasseoumesmocrculos,caixaselinhasqueseleentenda. Estes
diagramassodepoistranscritosemcdigo.

Amaisinformal,mastambmeficiente, comearcomumaclasse principal,que


identifique a funcionalidade e implementar chamadas a outras a classes e
mtodosquesequerexistem.Emoutraspalavras,ocdigoodesenho,ocdigoo
projetoeoplanejamento nohausnciadeprojeto.Aestetipodecodificao
dadoonomedeprogramaoporintuioeelebemcomumemmtodosgeisde
desenvolvimento.TambmcomumutilizarumIDEparadarassistnciaaestetipo
deprogramao.

Programandoporintuio
Programarporintuioumaprticacomumemmtodosgeisdedesenvolvimento,
comoXPeScrum.encorajadoseuusocomoutraprticaconhecidacomoDesenvolvimento
GuiadoporTestes, em ingls TestDriven Development (TDD10). Amecnica relativamente
simples,tuescrevescdigomencionandovariveis,mtodos,classeseoutrasconstruesque
aindanoexistem,expondoainteno,depoisvaicompletandoocdigoatsatisfazertodasas
dependncias.
Entendo que difcil visualizar como isso funciona, ento vamos a um exemplo.
Considereaimplementaodeumcomponentedechecagemdecrdito.Dadoumdocumentodo
clientecomoCPFouRG,tensqueverificaratravsdeumServioWeb(queretornaovalorda
dvida se houver) se ele no est negativado, e se estiver, qual o valor da dvida. Em uma
abordagem Transaction Script, pensaramos em uma classe inicial chamada CreditoService ou
CreditoBusiness,emumaabordagem DomainModel pensaramosemsimplesmenteumaclasse
10

TDDumaprticatpicadedesenvolvimentogilcomoXP,Scrum,etc:
http://pt.wikipedia.org/wiki/Test_Driven_Development
24

Captulo 1: Prticas e Tcnicas de Codificao


Credito.

Abaixo segue um exemplo que implementa essa checagem com uma classe

CreditoService:

Implementandoumafuncionalidadeprogramandoporinteno:
public class CreditoService {
public ? checaCredito(String documento) {
// ...
// ws.checaCPF(documento);
// ws.checaRG(documento);
return ?;
}
}
https://gist.github.com/marciojrtorres/6160393

NocomeodifcilvisualizarcomochecarodocumentocorretoatravsdoWebService
(ws)eatoqueretornarnomtodo.Podeserentoquetenhasaideiadeusarumparmetro
que, usando um enumerado, indique o tipo de documento e devolva uma instncia de
CreditoCheck.Ambos,oenumeradoeoCreditoCheck,noexistemeemvezdecrilosantesde
uslosvamosuslosantesdecrilos.
Usarantesdecriar,oprincpiobsicodaprogramaoporinteno
Paraprogramarporintenodevemosexporainteno:
// as classes em negrito no existem ainda
public class CreditoService {
public CreditoCheck checaCredito(TipoDocumento tipo, String documento) {
CreditoCheck creditoCheck = null ;
if (tipo == TipoDocumento.CPF) {
creditoCheck = CreditoCheck.fromDivida(ws.checaCPF(documento));
} else if (tipo == TipoDocumento .RG) {
creditoCheck = CreditoCheck.fromDivida(ws.checaRG(documento));
}
return creditoCheck;
}
}
https://gist.github.com/marciojrtorres/6160446

Esse cdigo ainda pode melhorado, mas nos atemos a ideia principal: as classes
CreditoCheckeTipoDocumentonoexistem!Estaaessnciadeprogramarporinteno,eutenho
aintenodeinformarotipodedocumentoedevolverumaclassequeencapsuleaanlisede
crdito,agoratenhoquecrilas.DuranteaedionoIDE,essaslinhasaparecemcomoerroe
felizmente o IDE d a assistncia necessria para criar estas dependncias, por exemplo, o
NetBeans exibe uma lmpada no canto onde esto as aes para resolver as dependncias
(tambmpodeserusado ALT+INSERT).Vejailustraoaseguirdecomoocdigosepareceno
NetBeans:

25

Captulo 1: Prticas e Tcnicas de Codificao

MencionamosasClassesantesmesmodeelasexistirem,oIDEfazoresto

Aprogramaoporintenopoderosasabendoutilizlacomsabedoria.Tupodesus
la para criar classes, mtodos, declarar atributos, etc. Abaixo uma imagem que ilustra uma
chamadadeummtodoinexistenteemCreditoCheck:

Intenodeusarummtodoqueretornebooleano

Seadicaforaceita,oNetBeanscriaumstub11domtodoquecumpreainteno.Claro,
issonoisentaoprogramadordecodificar,apenasauxilia,emuito,noprojeto.Vejacomoficao
stub:

11

Umstubumcdigotemporrioinseridoapenasparanoquebraracompilao:
http://pt.wikipedia.org/wiki/Stub

26

Captulo 1: Prticas e Tcnicas de Codificao

StubdemtodocriadopeloNetBeans

Sparacompletaroexemplo,aimplementaodetemDividapoderiaficarassim:
Implementandoostub:
class CreditoCheck {
boolean temDivida() {
return valorDivida > 0.0;
}
//
https://gist.github.com/marciojrtorres/6160506

Programandoporcoincidncia
Primeiro, a programao por coincidncia no uma coisa boa. O princpio da
programaoporcoincidnciaqueaoescreverumcdigo,testloeverificarqueelefunciona
no seu cenrio, o programador assuma que a lgica completamente funcional e correta,
entretanto o cdigo pode ter defeitos que, coincidentemente, no aparecero nos primeiros
testes,daaexpresso.
Voucolocarumexemplo.Considerequetenhamosdeimplementaroclculodeumadata
devencimentoquedeveserodiadadataatual,masnoprximoms.Hoje,noinstanteque
escrevo,20/01/2012eocdigopararesolveresteproblemapoderiaserassim:
Quandoumcdigofuncionaporcoincidncia:
public class Main {
public static void main(String[] args) {
VencimentoUtil venc = new VencimentoUtil();
System.out.println("hoje: " + new Date().toLocaleString());
System.out.println("venc: " + venc.proximoVencimento().toLocaleString());
// ...
class VencimentoUtil {
public Date proximoVencimento(Date dataInicio) {
return new Date(dataInicio.getYear(), dataInicio.getMonth()+1, dataInicio.getDate());
}

27

Captulo 1: Prticas e Tcnicas de Codificao

public Date proximoVencimento() {


return proximoVencimento(new Date());
}
// ...
// este cdigo fornece esta sada:
"hoje: 20/01/2012 16:58:29"
"venc: 20/02/2012 00:00:00"
// funciona!
https://gist.github.com/marciojrtorres/6160544

Funcionou, mas, ser que sempre funciona? O cdigo anterior mostra como um
vencimentocalculadocombasenadataatual.Omesmodia selecionadonomsseguinte.
Paraumleitoratentojdeveterficadoclaroqueessecdigonofuncionasempre.Noforam
previstasquestescomo:

Seadataatualfordia31eomsseguintenotemdia31?

Seadataatualformsdedezembro,asomadomsimplicanasomadoano?

Neste caso, a primeira questo falha. Se hoje fosse 31/01/2012 o vencimento seria
02/03/2012.Otesteinicialmentefuncionouporque,coincidentemente,hojenodia30ou31.
Obomprogramadordeveprevereestarcientedetodasaspossibilidadesdeentradaesadadeum
mtodooufuno.Oprogramadevesecomportarsempredemaneiraprevisvel.

necessrio testar em vrios cenrios at que todas as situaes de entrada tenham


sadasprevisveis.Noexemplo,poderamosadicionararegraqueseomsseguintenotemo
diasolicitado,useoltimodia.Vamosaoutroexemplo:
Falandoemcoincidncia,estecdigoSEMPREfunciona?
public static void armazenaEmTemporario(String texto) throws Exception {
FileWriter fw = new FileWriter("/tmp/app-temp.txt", true );
fw.write(s);
fw.flush();
fw.close();
}
https://gist.github.com/marciojrtorres/6160579

Estecdigofuncionanomeucomputador,maspossogarantirqueelefuncionanoseu?A
expresso programarporcoincidncia eosprincipaissintomasforamabordadosprimeiramente
pelo grupo do pragmatic programmers e tem um artigo muito bom disponvel aqui:
http://pragprog.com/thepragmaticprogrammer/extracts/coincidence

Programandodeliberadamente
desejvelquecriemoscdigo,deincio,comomnimodeerros,porissoomodelo
tentativa e erro claramente noo mais adequado. Devemosestar cientesdo que pode dar
errado,imaginandoosvrioscenrioseosefeitos,quasecomoumquebracabea.Segundoo
pragmaticprogrammers12algumasdicasparaprogramardeliberadamenteso:
12

Muitobomolivro,recomendo:http://pragprog.com/thepragmaticprogrammer/extracts
28

Captulo 1: Prticas e Tcnicas de Codificao

Estarsemprecientedoqueestfazendo.

Nocodifiquede"olhosfechados".Notenteconstruirumaaplicaosementender
asregrasgeraisouusandoumatecnologiaaqualnoestfamiliarizado.umconvite
paraserenganadopelascoincidncias.

Sigaumplano,mesmoquesejaescritoemumguardanapo.

Confie apenas em coisas concretas, mensurveis e confiveis. No dependa de


acidentesousuposies.Senopodespreveradiferena,assumaopiorcaso.

Nobastatestarsocdigo,tambmtestesuassuposies.

Priorizeoseuesforo.Gastemaistemponosaspectosimportantes,provavelmente
seroaspartesmaiscomplicadas.

Nosejaescravodahistria.Nodeixeocdigoexistenteditarofuturocdigo.Todo
cdigopodesersubstitudosenoformaisapropriado.

Cdigosfceisdeentender
Aclarezadocdigo
Uma diferena entre um programador esperto e um
programador profissional queoprofissional entendequea
clareza indispensvel. Profissionais escrevem cdigo que
outrospossamentender
RobertMartin

SegundoRobertMartinescrevercdigoclaro,oucdigolimpocomoelediz,umaarte.
Inclusive,muitosacreditamqueprogramarumamisturadecinciaearte.NolivrodoMartin
tem uma sriede depoimentos de profissionais renomados, sugiro que leiam, masum deles
queropublicarnantegra,nadadeparticular,nopossopublicartodos,masinteressantelero
pontodevistadeumprofissionalmaisquequalificadosobrecomoescrevercdigo.Aseguir,
MichaelFeathers,autordeWorkingEffectivelywithLegacyCode:
Eu poderia listar todas as qualidades que vejo em um cdigo limpo, mas h uma
predominantequelevaatodasasoutras.Umcdigolimposempreparecequefoiescritoporalgum
queseimportava.Nohnadadebvioquesepodefazerparatornlomelhor.Tudofoipensado
peloautordocdigo,esetentarpensaremalgumasmelhorias,vocvoltaraoincio,ouseja,
apreciandoocdigodeixadoparavocporalgumqueseimportabastantecomessatarefa
MichaelFeathers
Ward Cunningham13, cocriador da metodologia XP, lder do Smalltalk e um dos
evangelistasmaisantigosdeOOdiz: "Vocpodechamardecdigobeloquandoeletambmfaz
parecerquealinguagemfoifeitaparaoproblema".Issodifcildeatingir,noimpossvel.

Estiloseconvenesdecodificao
13

http://pt.wikipedia.org/wiki/Ward_Cunningham

29

Captulo 1: Prticas e Tcnicas de Codificao

Aslinguagensdeprogramaogeralmentetemconveneseestilosdecodificaobem
definidoseatdocumentados.OJavaporexemplo,expeosatributosdeumaclassesegundoo
padroJavaBean14,ondeosatributossoprecedidosdeget quandoparaleituraeset quando
paragravao(existeocasoespecialdotipoboleanoondeserecomenda is aoinvsdeget),
vejaexemploaseguir:
PadroJavaBean,umaclassededadoscomgettersesetters:
class Endereco {
private String rua;
private int numero;
private boolean ativo;
public String getRua() { return rua; }
public void

setRua(String rua) { this.rua = rua; }

public int

getNumero() { return numero; }

public void

setNumero(int numero) { this.numero = numero; }

public boolean isAtivo() { return ativo; }


public void

setAtivo(boolean ativo) { this .ativo = ativo; }

}
https://gist.github.com/marciojrtorres/6160600

desejvelseguiropadrodalinguagem,enoincomumprogramadoresmigraremde
linguagemeseguiremescrevendocdigocomoseestivessenalinguagemantiga.Porexemplo,
nomesdemtodossodiferentesemRuby,vejaumpequenoexemploaseguir:
PadrodenomesusadonalinguagemRuby:
class Documento
attr_accessor :titulo, :conteudo

### declarao de atributos

### mtodos escritos em minsculas com underline e,


### quando boleanos, terminam com "?"
def sem_titulo?
return @titulo .nil? || @titulo.empty?
end
end
https://gist.github.com/marciojrtorres/6160610

Asprincipaisplataformaselinguagensdisponibilizamumdocumentoderefernciapara
nomeao e organizao do cdigo. Por exemplo, a linguagem Java disponibiliza o Code
ConventionsforJavaProgrammingLanguage,disponvelnestelink:
http://www.oracle.com/technetwork/java/codeconv138413.html

14

http://download.oracle.com/otnpub/jcp/7224javabeans1.01frspecoth
JSpec/beans.101.pdf
30

Captulo 1: Prticas e Tcnicas de Codificao

, digamos, uma obrigao de um programador Java conhecer estas convenes de


cdigo. Elas definem como escrever nomes de variveis, mtodos, classes, etc, de forma
padronizada.Defato,padronizaminclusiveaslinhasembrancoeposiodaschaves.
Presteateno,istonoexclusivodalinguagemJava,todalinguagemtemconvenes
sejadefinidaspeloscriadoresoupelacomunidadededesenvolvedores.Pythonmesmo,temo
PEP8,StyleGuideforPythonCode,quetupodesveraqui:
http://www.python.org/dev/peps/pep0008/

Procuresempresabereseguirasconvenesdecdigoparaalinguagemquetuests
programando,issoimportante,programandoemPythonfaacdigoPython,programandoem
PHPfaacdigoPHP

No obrigatrio seguir a conveno determinada pela linguagem a risca. Equipes


podem definir novas convenes, apenas com a ateno de que todos osenvolvidos usem a
mesma.
Noinventeumaconvenodecdigopessoal,decidacomoscolegasdeequipe,emesmoquando
programandosozinhoprocurealgumaconvenoaceitanaindstria.

Boasprticasparaescrevercdigo
Criarumcdigolimponocomplicado,umhbito.Aseguirvoulargaralgunstpicos
queteajudaroaprogramarmelhor.Soprticassimplesmaseficientesdeorganizaoeescrita
docdigo,quevodesdedarbonsnomes,escrevermtodoseclassesfceisdelereentender,
entreoutros.

Usenomesquedeixemopropsitobemclaro
Onomedevedizerporqueexiste,oquefazecomousado.SegundoRoberMartinseum
nomerequerumcomentrio,entoelenorevelaseupropsito,porexemplo:
Nomescomumaletra,umapssimaprtica:
int d;
https://gist.github.com/marciojrtorres/6160633

Opa,masoquesignifica d?Oqueestavarivelarmazena?T,euseiqueuminteiro,
digamosqueseja12,mas12oqu?Considerequesejaumtempodecorrido,porexemplo12
dias.Noestclaro,certo?Umasoluoamadoraparaclarificar,adicionarumcomentrio:
Nomescomumaletra+comentrio==soluoamadora:
int d; // tempo decorrido em dias
https://gist.github.com/marciojrtorres/6160633

Cdigocomentado,aocontrriodoquesepensa,podeserummaucdigo,porquesefosselegvel
suficiente,noprecisariadecomentrio,noconcorda?

31

Captulo 1: Prticas e Tcnicas de Codificao

Poupeoseutempoemdarcomentrioseuseumnomequereveleainteno:
Usarnomesmaisadequadospoupamaintroduodecomentriosdesnecessrios:
int tempoDecorridoEmDias;
https://gist.github.com/marciojrtorres/6160633

Estesnomespodemsermaisaindamaisespecficossehouverumsignificadoespecialno
domnio (e geralmente h), ou seja, um sentido particular para as regras que estamos
implementando.Considerequeestetempodecorridosejacontadoapartirdaltimaalterao,
entoconsidereusarumnomeadequadoaodomniomostradonoexemploaseguir:
Osnomesdevemexpressarseusignificadoparaodomnio(regrasdenegcio):
int d; // pssimo
int tempoDecorridoEmDias; // bom
int diasDesdeUltimaAlteracao; // perfeito, expressa o significado para o domnio
https://gist.github.com/marciojrtorres/6160633

Outroexemplo:oqueocdigoaseguirfaz?
Ummtodopequenomasdifcildeentender:
public List<Conta> getCP() {
List<Conta> c1 = new ArrayList<Conta>();
for (Conta c2 : cs) if (c2.getTipo() == 2) c1.add(c2);
return c1;
}
https://gist.github.com/marciojrtorres/6160652

ummtodopequeno,imaginesefosselongo?Achoquenoconseguisteentender,por
menorqueocdigoseja.Tudomaisfcilquandoosnomestemmaissentido,noseriamelhor
assim:
Ummtodomaisfcildeentender:
public List<Conta> getContasAPagar() {
List<Conta> contasAPagar = new ArrayList<Conta>();
for (Conta conta : todasContas) if (conta.getTipo() == PAGAR) contasAPagar.add(conta);
return contasAPagar;
}
https://gist.github.com/marciojrtorres/6160652

Asalteraesfeitasnocdigoparatornlointeligvelchamaserefatoraes.Notequeas
refatoraes no alteram a funcionalidade, ou seja, o que o cdigo faz, mas torna o cdigo
expressivo.Osegredoestemcriarumcdigoexplcitoaopontodeoleitor(ouattumesmo)
noterdefazermuitoesforoparaentendlo.
Claroquefazercdigolegvelimplicaemdigitarmais,contudoesteesforomnimoe
sepaganasprximasrevisesdecdigo,acredite.

Deixeasdiferenasbemvisveiseagrupeassemelhanascriteriosamente

32

Captulo 1: Prticas e Tcnicas de Codificao

Eviteusarnomessemelhantesnomesmocontexto.Porexemplo,eupossoterquecriar
ummtodogetHistorico eoutrogetHistoricos emumaclasseUsuario.Vejaaseguir:
Nomescomdiferenasdiscretasdificultamoentendimento:
class Usuario {
// ...
Historico getHistorico() { ... }
List<Historico> getHistoricos() { ... }
// ...
}
https://gist.github.com/marciojrtorres/6160677

QualadiferenaentregetHistoricoegetHistoricos?Sehistricoretornaoltimohistrico
ehistricosretornatodos,entomelhortornasasdiferenasvisveis,porexemploassim:
Nomesdistintosfacilitamoentendimentoerevelamainteno:
class Usuario {
// ...
Historico getUltimoHistorico() { ... }
List<Historico> getTodosHistoricos() { ... }
// ...
}
https://gist.github.com/marciojrtorres/6160677

svezespodemosadicionaralgumasemelhanaparafacilitaralocalizaodosmtodos,
asemelhanainicialajudaaagruparmtodoscompropsitossemelhantes,comooexemploa
seguir:
NomescomsemelhanasediferenasclaraspodemfacilitaraedioemIDE'scomautocompletar:
class Usuario {
// ...
List<Tarefa> getTarefasRecentes() { ... }
List<Tarefa> getTarefasEmAndamento() { ... }
List<Tarefa> getTarefasCanceladas() { ... }
// ...
}
https://gist.github.com/marciojrtorres/6160805

Comnomessemelhantestambmpodeficarmaisfcildistinguirainterface(assinatura
dos mtodos) em editores de cdigo, como ambientes integrados que possuem o recurso de
autocompletar,comopodeservistonailustraoaseguirdecomoficarianoNetBeans:

33

Captulo 1: Prticas e Tcnicas de Codificao

NetBeanseorecursodeautocompletar:nomessemelhantesajudam

NailustraoanterioroNetBeansmostroutodososmtodosqueiniciamcom getTarefas,
oqueumamotivaoparadarnomessemelhantes,quandoforocaso.

Usenomespronunciveis
Evite usar siglas ou acrnimos nos nomes. Nomes legveis facilitam a leitura e a
comunicao,outuachasfcildizer:Ei,avarivelprpestcomovalorzero!
Nomespronunciveissomelhores,permitemacomunicaoentreosdesenvolvedores,
seriamelhor: Ei,avarivelpontoRelativoDePartidaestcomovalorzero! Vejaaseguiralguns
exemploscomsequnciasdebonsemausnomes:
Sequnciademausebonsnomes:
double vlrRef; // pssimo
double valorDeReferencia; // melhor
String dataNasc; // ruim
String dataDeNascimento; // melhor
int iu; // horrvel
int identificacaoUnica; // melhor
ContratoUnico cu; // indecente, sem comentrios :P
ContratoUnico contratoUnico; // assim mais educado
https://gist.github.com/marciojrtorres/6160822

Sugesto:notenhapreguiadedigitar,massetiver,aproveiteoautocompletardoseu
IDE .Aoprecisarmencionaravarivelnocdigo,digiteosprimeiroscaracteresepressione CTRL
+ ESPAO(vlidoparaoNetBeanseEclipseporexemplo);
15

SubstantivoscomonomesdeclassesVerboscomonomesdemtodos

15

IntegratedDevelopmentEnvironment(IDE),ouemportugusAmbientedeDesenvolvimentoIntegrado:
http://en.wikipedia.org/wiki/Integrated_development_environment
34

Captulo 1: Prticas e Tcnicas de Codificao

Cadalinguagempodeterumdocumentodeconvenodenomesoumesmoaequipe
podecriarumdocumentoassim.deextremaimportnciaseguirumaconvenodenomes,
onde,naorientaoaobjetos,classestemsubstantivoscomonomesemtodostemverbos,por
exemplo:
ClassessoSubstantivos,MtodossoVerbos:
class Aviao {
void decola() { ... }
void pousa() { ... }
}
https://gist.github.com/marciojrtorres/6160841

Asinterfacespodemseguiromesmopadrodenomesdeclasses,ouseja,substantivos,
como interface Endereco,ouentoseguirumpadroespecficodalinguagem,comono.NET
(C#)ondeseusaoprefixoi,ounoJavaondeseusaadjetivoeosufixodepossibilidade"vel".
Verexemplosaseguir:
Interfacesnomeadascomoclasses,usandosubstantivos:
// declarando uma interface
interface Populacao {
void contar();
}
// declarando uma interface com o padro de nomeao Microsoft C#.NET
interface IPopulacao { // note o prefixo I, de interface
void contar();
}
// declarando uma interface com o padro de nomeao Java
interface Populavel { // note o sufixo "vel"
void contar();
}
https://gist.github.com/marciojrtorres/6160851

Existemargumentosafavorecontraastcnicas,enfim,oqueimportaserconsistente,
ouseja,seasinterfacesterooprefixo"I",entotodasasinterfacesdevemteroprefixo"I",
ok?
EmlinguagensOO tradicionalos mtodosrepresentaremaeseestasaesserem
escritascomoverbosnoimperativoouinfinitivo 16.Usandoinfinitivoosmtodosficamcomoo
exemploaseguir:
Mtodosnomeadoscomoverbosnoinfinitivo:
class Mensagem {
void enviar() { ... }
}
class Documento {
void imprimir() { ... }
}
// situao de uso:
Documento documento = new Documento();
16

http://pt.wikipedia.org/wiki/Infinitivo

35

Captulo 1: Prticas e Tcnicas de Codificao

documento.imprimir();
https://gist.github.com/marciojrtorres/6160902

Outraopoescrevernoimperativo17,massempretentandomanteraconsistncia,ou
seja,todososmtodosnoimperativooutodosnoinfinitivo. Usandoimperativo,osmtodos
ficariamcomonoexemploaseguir:
Mtodosnomeadoscomoverbosnoimperativo:
class Mensagem {
void envia() { ... }
}
class Documento {
void imprime() { ... }
}
// situao de uso:
Documento documento = new Documento();
documento.imprime(); // se fosse em ingls: document.print() e no
https://gist.github.com/marciojrtorres/6160902

Outra conveno comum usar verboSujeito, como: mensagem.enviaMensagem(),


documento.imprimeDocumento(). Nestes casos foi redundante e no era necessrio, pois
mensagem.envia()jdemonstrariaainteno.Emoutrassituaespodeserbemtil,comoem:
janela.mostraTitulo(), janela.removeBorda(). Somente janela.mostra() ou janela.remove()
poderialevaraummauentendimento.AescolhadeverboouverboSujeitopodeevitarconfuses,
vejaexemploaseguir:
Mtodossoverbos:
class Cavaleiro extends Personagem {
void ataca() { ... } // o Cavaleiro ataca, ok.
void anda() { ... } // o Cavaleiro anda, ok.
void guarda() { ... } // o Cavaleiro guarda, mas guarda o qu?
void guardaEspada() { ... } // assim melhor
}
https://gist.github.com/marciojrtorres/6160919

Ingls,Portugusouem18
Esteumassuntobempolmico.Hquemsesintaconfortvelemescrevercdigoem
inglsehquemresiste.Pessoalmente,acreditoquenosejapossvelescrevercdigototalmente
emportugusoutotalmenteemingls.

17

http://pt.wikipedia.org/wiki/Modo_imperativo

18

LnguaRussa:http://ru.wikipedia.org/wiki/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9_%D1%8F
%D0%B7%D1%8B%D0%BA

36

Captulo 1: Prticas e Tcnicas de Codificao

Considere escrever em ingls: existem nomes de mtodos e classes que devido a


convenesepadresdecdigoeprojetosomelhoresescritoseconhecidosemingls,por
exemplo,osequivalentedoSQL: insert, update, delete, select, ouseusparesusadosnos
DAO's: save, update, remove e find.Palavrastpicasparaprojetarcoleessomaisfceisde
introduziremclassesquemodelemum container,como: size, clear, add, remove, parecem
melhorquetamanho, limpa, adiciona e remove.
Considere escrever em portugus: por outro lado, mtodos de negcio, parte do
domnio do aplicativo, podem ser difceisde escrever em ingls, por no representarbem o
dialetousadonaanlise.Considereumaclassequepreciseemitirumcupomfiscal,tuescreverias
ummtodoquesechame,digamos, printCouponTax?Normalmenteasclassesemtodosusados
para modelar as classes de domnio so desenhadas em diagramas, compartilhados com os
clientes,queemboranosaibamprogramarconhecerasentidadesenvolvidasnosseusistema.
Nomesem inglspodemdificultaroentendimento dosdemaismembrosdoprojeto, osno
desenvolvedores. importante que entendas que os objetos de domnio devem representar
objetosreaisdoqueseestmodelandoeosnomesdevemserosmaisprximosdosobjetosreais.
Istoimportanteparaqueequipededesenvolvimentoeclientefalemamesmalngua,ouseja,
se o cliente tem uma imobiliria e, conforme ele, trabalha com repasse de locao, talvez
tenhamosumaclasseRepasseLocacaoenoLeaseTransfer.
Resumindo, uma sugesto usar nomes em portugus para objetos de domnio e
considerar usar nomes em ingls para objetos do framework, persistncia, extenses para a
linguagem,ououtrosquenosejamrelacionadoscomonegciodocliente.
Nomeseminglssotimosparacriarutilitrios,bibliotecaseframeworks.Entreoutros,
doisargumentosapoiamnomesemingls:

Quando o cdigo est disponvel na internet (open source): se seu projeto est
disponvelparadownloadecolaborao,oscdigoseminglspermitemacolaborao
dequalquerpessoanomundo,jqueinglsalnguafranca19dosdesenvolvedorese
profissionaisdeTecnologiadaInformaoeComunicao.

Quando tu queres estender a linguagem: cdigos em ingls fazem parecer que a


funcionalidadepartedaprprialinguagemenoalgofeitoaparte,porexemplo,
parasaberseumastringcontmnmeros,considereocdigoaseguir:

EstendendoaAPIdalinguagemcommtodosutilitrios:
// em ingls:
class StringUtilities {
boolean isNumber(String string) { // ...
// situao de uso em que parece parte da linguagem:
if (StringUtilities.isNumber(var)) { // ...
// em portugus:
class UtilitarioString {
boolean ehNumero(String string) { // ...
// situao de uso em que parece algo feito para o momento:
19

Lnguaderelao:http://pt.wikipedia.org/wiki/Lingua_franca
37

Captulo 1: Prticas e Tcnicas de Codificao

if (UtilitarioString.ehNumero(var)) { // ...
https://gist.github.com/marciojrtorres/6160932

Escrevamtodospequenos
Como programadores ns solucionamos problemas e encapsulamos o cdigo para a
soluodestesproblemasemclassesemtodos(oufunescasotuusesPHPouC).Existem
boas prticas, claro, para implementar classes e mtodos, mas uma regra inicial pode ser
resumidaemumapalavra:PEQUENO.
Por exemplo, considere a implementao de um pedido no final de uma venda pela
internet.Oclientetemumcarrinho,endereo,formadapagamentoedesejafazeropedido,uma
ideiarelativamentesimples,quepodesercodificadacomummtodofazPedido(Carrinho),como
podeservistonocdigoaseguir:
UmmtodolongodemaisparafazerumPedido:
class PedidoService {
public Pedido fazPedido(Carrinho carrinho) {
if (carrinho.getItens().size() == 0) {
throw new IllegalArgumentException("Carrinho Vazio");
}
if (carrinho.getFormaPagamento() == null) {
throw new IllegalArgumentException("Forma Pagamento no selecionada");
}
if (carrinho.getFormaPagamento() == CARTAO_CREDITO) {
Cliente cliente = carrinho.getCliente();
SegurCredWS sc = new SegurCredWS();
sc.checaCredito(cliente.getCPF().replace(".", "").replace("-","."));
if (!sc.getSituacao().equals(Situacao.OK)) {
throw new NoCreditException("Cliente no tem crdito liberado");
}
}
EstoqueService estoqueService = new EstoqueService();
for (Item item : carrinho.getItens()) {
if (estoqueService.getQuantidadeEstoque(
item.getProduto().getCodigo()) < item.getQuantidade()) {
throw new SemEstoqueParaItem(item);
}
}
// ... mais 30 linhas de transao
Pedido pedido = new Pedido();
pedido.setItens(carrinho.getItens());
pedido.setCliente(carrinho.getCliente());
pedido.setFormaPagamento(carrinho.getFormaPagamento());
PedidoDAO pedidoDAO = new PedidoDAO();
pedidoDAO.salva(pedido);
}

38

Captulo 1: Prticas e Tcnicas de Codificao

}
https://gist.github.com/marciojrtorres/6160942

Mtodosmuitoalongados,commuitasinstrues,socomplexose:

dificultamaleitura:vistoquetodasaslinhasnocabemnatela;

dificultam a manuteno: visto que necessrio percorrer todo o mtodo para


localizarproblemaseintroduzirnovasfuncionalidades;

impede a reutilizao: j que todos os passos, mesmos os reaproveitveis, esto


dentrodomesmobloco(omtodo).

Mtodos com muitas instrues tambm um indcio de que fazem muita coisa, ou
melhor,maiscoisasdoquerealmentedeviamfazer(verPrincpiodaResponsabilidadenica).
Paratornarummtodolongomaisfcildeentenderatentativamaiscomum,eincua,
ir comentando cada seo do mtodo, e por vezes, num sbito de extremo amadorismo,
adicionandolinhasembranco,traos,smbolosesabelmaisoqu.Comoexemplonegativo,ou
seja,comoexemplodoquenofazer,vejaocdigoaseguir,agoracomentado:
Comentriosparatentardeixarocdigomaisinteligvel:
class PedidoService {
public Pedido fazPedido(Carrinho carrinho) {
// checar se o carrinho est vazio
if (carrinho.getItens().size() == 0) {
throw new IllegalArgumentException("Carrinho Vazio");
}
// checar se a forma de pagamento foi selecionada
if (carrinho.getFormaPagamento() == null) {
throw new IllegalArgumentException("Forma Pagamento no selecionada");
}
// ################ SE FOR CARTO DE CRDITO CHECAR SALDO
if (carrinho.getFormaPagamento() == CARTAO_CREDITO) {
Cliente cliente = carrinho.getCliente();
SegurCredWS sc = new SegurCredWS();
sc.checaCredito(cliente.getCPF().replace(".", "").replace("-","."));
if (!sc.getSituacao().equals(Situacao.OK)) {
throw new NoCreditException("Cliente no tem crdito liberado");
}
}
// CHECAR SE TODOS OS ITENS ESTO NO ESTOQUE
EstoqueService estoqueService = new EstoqueService();
for (Item item : carrinho.getItens()) {
if (estoqueService.getQuantidadeEstoque(
item.getProduto().getCodigo()) < item.getQuantidade()) {
throw new SemEstoqueParaItem(item);
}
}

39

Captulo 1: Prticas e Tcnicas de Codificao

// ... mais 30 linhas de transao (E 10 DE COMENTRIOS!!!)


// CONSTRUIR O PEDIDO !!!!
Pedido pedido = new Pedido();
pedido.setItens(carrinho.getItens());
pedido.setCliente(carrinho.getCliente());
pedido.setFormaPagamento(carrinho.getFormaPagamento());
// SALVAR O PEDIDO NA BASE DE DADOS
PedidoDAO pedidoDAO = new PedidoDAO();
pedidoDAO.salva(pedido);
}
}
https://gist.github.com/marciojrtorres/6161148

Lembre,seocdigofontelegvelosuficienteoscomentriosnosonecessrios.Emoutras
palavras,apresenadecomentriosgeralmenteummausinal.

Osegredoparacriarummtodomelhordecomporasatividades.Porexemplo,osdois
primeirosifschecamavalidadedocarrinhoepoderiamsercolocadosemummtodoseparado,
comonoexemploaseguir:
Introduzindoummtodoparachecarocarrinho:
class PedidoService {
public Pedido fazPedido(Carrinho carrinho) {
checaValidadeCarrinho(carrinho);
if (carrinho.getFormaPagamento() == CARTAO_CREDITO) {
checaCreditoCliente(carrinho.getCliente());
}
// ... restante do mtodo chamando mtodos menores
pedidoDAO.salva(pedido);
}
private void checaValidadeCarrinho(Carrinho carrinho) {
if (carrinho.getItens().size() == 0) {
throw new IllegalArgumentException("Carrinho Vazio");
}
if (carrinho.getFormaPagamento() == null) {
throw new IllegalArgumentException("Forma Pagamento no selecionada");
}
}
private void checaCreditoCliente(Cliente cliente) {
SegurCredWS sc = new SegurCredWS();
sc.checaCredito(cliente.getCPF().replace(".", "").replace("-","."));
if (!sc.getSituacao().equals(Situacao.OK)) {
throw new NoCreditException("Cliente no tem crdito liberado");
}
}
// ... outros mtodos menores
}

40

Captulo 1: Prticas e Tcnicas de Codificao


https://gist.github.com/marciojrtorres/6161148

O ideal sempre decompor um mtodo grande em, por exemplo, vrios mtodos
pequenos,quevosendoinseridosnaclasseseguindoaordemdeleitura,elegantemente.
Mtodoselegantessotolegveisquantootextodeumaredao,comincio,meioefim

Resolvaumproblemaporvez
Oidealqueomtodoexecuteumatarefaclaraesimples.Mtodosquefazemmaisde
umacoisatendemasergrandeseconfusos.VoltandoaoexemplodomtodofazPedido,eletem
umatarefabemdefinida,fazeropedido,squeexistemvriassubatividadesquedevemser
executadas,nonecessariamentepelomtodofazerpedido.Porexemplo,emdadomomento
necessrioverificarseoclientetemcrdito,istopodeextradoparaoutromtodo,vejaaseguir:
Mtodoauxiliarcomaresponsabilidadedeverificarocrditodocliente:
class PedidoService {
public Pedido fazPedido(Carrinho carrinho) {
// ... instrues iniciais
if (carrinho.getFormaPagamento() == CARTAO_CREDITO) {
checaCreditoCliente(carrinho.getCliente());
}
// ... mais instrues
}
private void checaCreditoCliente(Cliente cliente) {
SegurCredWS sc = new SegurCredWS();
sc.checaCredito(cliente.getCPF());
if (!sc.getSituacao().equals(Situacao.OK)) {
throw new NoCreditException("Cliente no tem crdito liberado");
}
}
}
https://gist.github.com/marciojrtorres/6161157

Acriaodenovosmtodosimportanteparaatribuirumaresponsabilidadeclarapara
cadamtodo.importantequecadamtodofaaapenasumacoisaeafaabem.
Cadamtododevefazerumacoisabemfeita

Aprender a decompor um grande problema em problemas menores tambm uma


prtica bsica do mtodo cientfico. Aprender a resolver subproblemas competncia
importanteparaqualquerdesenvolvedor.

Usepoucosparmetrosnosmtodos,quantomenosmelhor
Aquantidadedeparmetrosconhecidocomoaridadedeummtodo.Existemmtodos
unrios,binrios,ternrios,quaternrios,etc.Osmtodosdevemteromnimonecessriode
parmetros para cumprir sua tarefa. O ideal no mximo trs parmetros. Parmetros em
excesso dificultam a leitura e manuteno. Futuras alteraes que exijam alteraes na
41

Captulo 1: Prticas e Tcnicas de Codificao

quantidade de parmetros podem exigir a propagao da alterao em vrios pontos do


aplicativo(verRigidezeFragilidade).
Considereummtododebuscadeumaclasse DAO,ondeeupossoencontrar,digamos,
clientespelonomeousobrenome,ouambos.Vejaexemploaseguir:
ClasseDAOemtododebuscacomdoisparmetros:
class ClienteDAO {
public List<Cliente> buscaPorNome(String nome, String sobrenome) {
// ... cdigo necessrio para buscar clientes pelo nome e sobrenome
}
// ...
https://gist.github.com/marciojrtorres/6161164

Umachamadaaestemtodopoderiaser:dao.buscaPorNome("Pedro", "Perez");notequea
ordemdosparmetrosimportante,ouseja,existeumacoplamentode aridade.Vamossupor
que buscaremos um cliente pelo sobrenome "torres", a chamada do mtodo seria assim:
dao.buscaPorNome(null, "torres"); esefossepelonome "marina",achamadadomtodoseria
assim: dao.buscaPorNome("marina", null); Em linguagens orientadas a objetos possvel
sobrecarregarummtodoparaflexibilizarestasituao,porexemplo:
ClasseDAOemtodosdebuscasobrecarregados:
class ClienteDAO {
public List<Cliente> buscaPorNome(String nome, String sobrenome) {
// ... cdigo necessrio para buscar clientes pelo nome e sobrenome
}
public List<Cliente> buscaPorNome(String nome) {
buscaPorNome(nome, null );
}
public List<Cliente> buscaPorSobrenome(String sobrenome) {
buscaPorNome(null , sobrenome);
}
}
// exemplo de uso:
dao.buscaPorNome("marina", "torres");
dao.buscaPorNome("marina");
dao.buscaPorSobrenome("torres");
https://gist.github.com/marciojrtorres/6161164

Osegredodasobrecargaadelegao.Parasabermaissobresobrecargademtodos
acesseestelink:http://docs.oracle.com/javase/tutorial/java/javaOO/methods.html
Vamosparaumexemplomaiscomplexo,considereummtododebuscadeimveisque
usemuitosparmetros,sendoalgunsdomesmotipo.Estetipodeimplementaopropensaa
mausentendimentos.Vejaocdigonoexemploaseguir:
ClasseDAOparabuscadeimveisusandoummtodocommuitosparmetros:
class ImovelDAO {
List<Imovel> busca (Integer nroQuartos, Integer nroVagasCarro,

42

Captulo 1: Prticas e Tcnicas de Codificao

Double vlrMaximoCondominio, Double vlrMaximoAluguel,


Boolean comFoto, Boolean apartamento) {
// ... cdigo necessrio para fazer a busca
}
}
// uma chamada seria assim:
ImovelDAO dao = new ImovelDAO();
// o que seriam "2, 2, 800, 500, false, true" sem olhar a assinatura no mtodo?
List<Imovel> imoveis = dao.busca(2, 2, 800, 500, false, true );
https://gist.github.com/marciojrtorres/6161173

Observando apenas a chamada do mtodo busca, possvel entender o que se est


buscando?Nesteexemplodparanotarbemaambiguidade.Mtodocommuitosparmetros
soconfusos,eviteos.
Nocasodoexemplo,avalieusarumobjetocomoparmetro,umarefatoraonoto
simples mas muito poderosa. Queremos filtrar os imveis, ento podemos criar uma classe
FiltroImovel comosatributosnecessrios,vejaaseguir:
ClassedeFiltrousadacomoparmetroparabuscadeimveis:
class ImovelDAO {
List<Imovel> busca (FiltroImovel filtro) { // s um parmetro!
// ... cdigo necessrio para fazer a busca
}
}
// classe,objeto parmetro
class FiltroImovel {
public Integer nroQuartos, nroVagasCarro;
public Double vlrMaximoCondominio, vlrMaximoAluguel;
public Boolean comFoto, apartamento;
}
// uma chamada seria assim:
ImovelDAO dao = new ImovelDAO();
FiltroImovel filtro = new FiltroImovel() {{
vlrMaximoAluguel = 500;
nroQuartos = 2;
vlrMaximoCondominio = 800;
apartamento = true ;
comFoto = false ;
nroVagasCarro = 2;
}};
List<Imovel> imoveis = dao.busca(filtro);
https://gist.github.com/marciojrtorres/6161173

Maiscdigo,entretantomuitomaislegvel.Usarumobjetocomoparmetrotraztambm
o benefcio da alterao. Considere a necessidade de acrescentar um parmetro, digamos,
quartoEmpregada:boolean. Faramos a incluso do atributo na classe FiltroImovel, o que no

43

Captulo 1: Prticas e Tcnicas de Codificao

quebrariaaschamadasquejexistem,alm,paraasnovaschamadasbastaadicionaroatributo
quartoEmpregada.
Percebesnoexemplodachamadaqueachamadamaisinteligvel,sabemosoquevale
cada parmetro sem precisar abrir a classe ImovelDAO, basta ler a chamada. Outro ponto
importanteodesacoplamentodaordem,anteriormentea ordem importava20,masnestecaso
podemosdefinircadavalordeparmetroemqualquerordem.
Emqualquerprojetodesoftware,sejaOOouno,existeoobjetivodequecadamdulotenhaoomnimo
conhecimentodeoutro,comopropsitodeminimizaroacoplamento.Aordemdosparmetrosumtipode
acoplamento21,porexemplo,seeumudasseoDAOparaprimeiroleronmerodevagasparacarroedepoiso
nmerodequartos,osclientesnoquebrariamdevidoaindaserdomesmotipo,masteriamumbugmuito
difcildeencontrar.

Projeteomtodoparaquenosejapassadonulocomoparmetro
Este objetivo j foi alcanado no primeiro exemplo da seo mtodos com poucos
parmetros,masconsidereoutroexemplo,adabuscaporfaixaderenda:
ClasseDAOparabuscadeClientesporfaixaderenda:
class ClienteDAO {
List<Cliente> busca (Double rendaMinima, Double rendaMaxima) {
if (rendaMinima != null ) // inclui o mnimo na busca
else // a renda mnima ignorada
if (rendaMaxima != null ) // inclui o mximo na busca
else // a renda mxima ignorada
// ... cdigo necessrio para fazer a busca
}
}
// uma chamada seria assim:
ClienteDAO dao = new ClienteDAO();
// busca clientes com renda mnima de 2000 no importando a mxima
List<Cliente> clientes = dao.busca(2000.0, null);
// busca clientes com renda mxima de 1000 no importando a mnima
List<Cliente> clientes = dao.busca(null, 1000.0);
// busca clientes com renda entre 600 e 1200
List<Cliente> clientes = dao.busca(600.0, 1200.0);
https://gist.github.com/marciojrtorres/6161197

Chamadas com null so pouco intuitivas causando propenso a falhas. Uma soluo
simplesrefatorarintroduzindonovosmtodoseusandoasobrecarga.Vejaaseguir:
ClasseDAOparabuscadeClientesrefatorada:
class ClienteDAO {
20
21

Acoplamentoposicional:http://onestepback.org/articles/connascence/conposition.html
Oacomplamentotambmconhecidocomoconnascence:
http://en.wikipedia.org/wiki/Connascent_software_components
44

Captulo 1: Prticas e Tcnicas de Codificao

List<Cliente> buscaPorFaixaDeRenda (Double rendaMinima, Double rendaMaxima) {


if (rendaMinima != null) // inclui o mnimo na busca
else // a renda mnima ignorada
if (rendaMaxima != null) // inclui o mximo na busca
else // a renda mxima ignorada
// ... cdigo necessrio para fazer a busca
}
List<Cliente> buscaPorRendaMinima (double rendaMinima) {
buscaPorFaixaDeRenda(rendaMinima, null ); // chamada interna
}
List<Cliente> buscaPorRendaMaxima (double rendaMaxima) {
buscaPorFaixaDeRenda(null , rendaMaxima); // chamada interna
}
}
// uma chamada seria assim:
ClienteDAO dao = new ClienteDAO();
// busca clientes com renda mnima de 2000 no importando a mxima
List<Cliente> clientes = dao.buscaPorRendaMinima(2000.0);
// busca clientes com renda mxima de 1000 no importando a mnima
List<Cliente> clientes = dao.buscaPorRendaMaxima(1000.0);
https://gist.github.com/marciojrtorres/6161197

Viuaschamadas?Semnulls!

Eviteargumentosqueservemdeflag(flagarguments)
[[vercdigolimpoeartigodofowler:http://martinfowler.com/bliki/FlagArgument.html]]
[[http://martinfowler.com/bliki/FlagArgument.html]]

Escrevacomentriosteis
Comentriosnocdigotemsuautilidade,esuainutilidadetambm.Umcdigomuito
comentadonemsempreumbomsinal,svezesmuitopelocontrrio,podeserumaprtica
comumparaexplicarumcdigoquenoclaroosuficiente.SteveMcConnel22diz:
Bomcdigosuaprpria,emelhor,documentao.semprequeestiveresporadicionarumcomentrio,
pergunteasimesmo:Comoeupossomelhorarestecdigoparaqueessecomentrionosejanecessrio?
SteveMcConnel

Torneoscomentriosdesnecessrios
Alguns comentrios so inseridos no cdigo para explicar o algoritmo ou a lgica do
negcio.Algunssodefatonecessrios,outros,seocdigofossesuficientementeclaro,no.
Comotornarumcomentriodesnecessrio?Deixeocdigomaisclaro.Aseguirumexemplo:
22

SteveMcConnelescritodevrioslivrospopularesdareadedesenvolvimentodesoftwarecomoCode
Complete,RapidDevelopment,entreoutros:http://www.amazon.com/SteveMcConnell/e/B000APETRK
45

Captulo 1: Prticas e Tcnicas de Codificao


Explicandoumalgicaconfusacomcomentrios:
class Contabil {
// relatrio de lanamentos no contabilizados
void relatorio() {
// lanamentos deste ano, desde o incio do ano at a data atual
List<Lancamento> l1 = lancamentoService.lancamentos(
new Date(new Date().getYear(), 1, 1), new Date());
// lanamentos no contabilizados
List<Lancamento> l2 = new ArrayList<Lancamento>();
for (Lancamento l : l1) {
// 1: contabilizado, 2: nao contabilizado
// se est contabilizado
// 0: ativo, 1:cancelada, 2:inativo
// tem que estar no contabilizado e no cancelado para enviar
// para o relatrio
if (l.getStatus() == 2 && l.getArquivo() != 1) l2.add(l);
}
reportService.send(l2);
}
}
https://gist.github.com/marciojrtorres/6161206

Ocdigoacimatemmuitoscomentrioscomopropsitodeexplicaralgica.Estecdigo
umbomcandidatoarefatorao.Pequenasalteraesnocdigopodemeliminarcomentrios
como por exemplo, renomear o mtodo e variveis. A seguir uma verso que ainda requer
melhoriasmasquejficaestmaisclaramesmosemoscomentrios:
Explicandoumalgicaconfusacomoprpriocdigo:
class Contabil {
void relatorioLancamentosNaoContabilizados() {
Date hoje = new Date();
Date inicioAno = new Date(hoje.getYear(), 1, 1);
Intervalo anoAtual = new Intervalo(inicioAno, hoje);
List<Lancamento> lancamentosDoAno = lancamentoService.lancamentos(anoAtual);
// ...
https://gist.github.com/marciojrtorres/6161206

Excluaoscomentriosirrelevantesqueservemderudo
Algunscomentriossodefatoirrelevantes,ocupamespao,atrapalhamalegibilidadee
funcionamcomorudonocdigo.Comooexemploaseguir:
Comentriosirrelevantesatrapalhamaleitura:
class Cliente {

46

Captulo 1: Prticas e Tcnicas de Codificao

int codigo; // cdigo do cliente


String nome; // nome do cliente
// construtor padro
public Cliente() {
}
// ...
https://gist.github.com/marciojrtorres/6161222

Baseandosenoexemplo,nonecessriocomentriosparainformardequemsoos
atributos,ouinclusivequeoconstrutorvaziooconstrutorpadro,afinaljumacaracterstica
deorientaoaobjetosedalinguagemrespectivamente.Outroscomentriosirrelevantesso
aquelesinseridosnocdigopara,oupor,quemestaprendendo,porexemplo:
Comentriosqueexplicamasintaxedalinguagemsoirrelevantes:
// para cada emprstimo dos emprestimos
for (Emprestimo e : emprestimos) {
report.add(e);
if (report.hasErrors()) {
break ; // sai do for
}
}
https://gist.github.com/marciojrtorres/6161222

Adeclaraofor (Elemento e : elementos)doJavajquerdizerparacadaelementoem


elementos,qualquerprogramadorconfortvelcomalinguagemnoprecisariadestecomentrio
enemdooutro,quedizqueobreak saidolaofor(issoatumaofensa!:).

Nocomente,documente!
umaprticasaudveleprofissionaldocumentarocdigo.Algumaslinguagenscomoo
Javadispemdeumpadroparadocumentaodemtodos,atributoseclasses.
NoJava,todotextodedocumentaoinciacom/**(barraasterscoastersco)etermina
com*/ (asterscobarra).Aseguirumexemplo:
CdigoJavadocumentadonoestiloJavaDoc:
/**
* Lida com todas as atividades relacionadas ao movimento fiscal e contbil
*
* @author Mrcio Torres
* @version 1.0
*
*/
class Contabil {
/**
* Representa o instante no tempo a cada instanciao da classe
*/
public final Date agora = new Date();
/**

47

Captulo 1: Prticas e Tcnicas de Codificao

* Encerra uma lista de lanamentos de acordo com


* um intervalo de datas
*
* @param inicio Data de incio do intervalo
* @param fim Data de fim do intervalo
*
* @return RelatorioContabil com os dados dos lanamentos encerrados
*
* @throws NullPointerException se alguma das datas for nula
* @throws IllegalArgumentException se a data de incio for
* posterior a de fim
*/
public RelatorioContabil encerraIntervalo(Date inicio, Date fim) {
// ...
https://gist.github.com/marciojrtorres/6161227

importantefornecer um resumo da classebem como informar o autore verso ou


ltimaatualizao.Opcionalmenteosatributospodemserdocumentados,asugestoqueseja
feitosomentequandosopblicosevisveisforadaclasse.
Paradocumentarosmtodosexisteumanotaotodaespecial.Devehaverumresumo
daatividadeoudoproblemaresolvidopelomtodo,ainformaodacadaparmetrocomo
metadado@param,seomtodotemretorno(novoid)tambminformamosometadado@return
deixando bem claro as possibilidades de retorno (se pode retornar nulo por exemplo) e as
exceesquepodemacontecer(sejamcheckedouruntime)usandoometadado@throws(lana),a
exceoeomotivopeloqualelaacontece.
TodaadocumentaopodeserexportadaparaumdocumentoPDFouHTML,noJava
chamadodeJavaDoc23,umutilitrioquegeraoHTMLapartirdocdigo.Adocumentao do
Java24,digo,aAPI dalinguagem, baseada nestaprtica. Otextousadonadocumentao
aparecenoautocompletardeIDEs,vejailustraoaseguirdoIDENetbeans:

IDENetBeansmostrandoadocumentaoduranteadigitao

23

OJavaDocumutilitriopresentenoJavaSDK:

http://www.oracle.com/technetwork/java/javase/documentation/indexjsp135444.html
24

http://docs.oracle.com/javase/6/docs/api/

48

Captulo 1: Prticas e Tcnicas de Codificao

No necessrio documentar tudo, a minha sugesto que sejam documentadas as


classesemtodospblicos,somadosaosatributospblicosmaisconfusos.

Tcnicasavanadasdecodificao
Existem problemas recorrentes na codificao de lgicas de domnio, interface,
persistncia,etc.Estesproblemasrecorrentespodemsersolucionadosatravsdealgunspadres
de implementao bem conhecidos disponveis em boa parte das linguagens. A seguir sero
abordadosalgunspadrescomunseaplicveisnalinguagemJava(eoutras),algunsparaobter
legibilidade,outrosparaperformance,enfim,eoutrosapenaspararesolveroproblemaproposto.

ConstructorChaining(encadeamentodeconstrutores)
Asobrecargadeconstrutoresumrecursobemcomumnaslinguagensmodernase,se
usada corretamente, pode solucionar alguns problemas com elegncia. O encadeamento de
construtoresatravsdasobrecargapermitedefinirumconstrutorcompletoedemaisconstrutores
commenosargumentos.

Inteno
Permitir que um objeto seja instanciado com quantidade varivel de argumentos
caracterizandoopcionalidadeevalorespadro(defaults)poromisso.

Motivao
Umobjetopodeterumaoumaispropriedadesinicializadasopcionalmente,assumindo
um valor padro para algumas . Sobrecarregar o construtor cada um com uma quantidade
diferentedeparmetrosadicionaflexibilidadeaosoftwarefazendocomqueargumentosmenos
importantesouraramentealteradosnotenhamqueserinformadostodootempo.

Implementao

Estabeleaumconstrutorcomtodososparmetrosinicializveispresentes.

Implementenovosconstrutorescommenosparmetrosequefazemumachamadaao
construtor completo (this()) delegando os parmetros excedentes recebidos e
determinandoosdefaults.
achamadathis()usadaparaacorrentar(enchain)umconstrutoraooutro

Exemplo
Considereumtipodedadochamadodinheiro,comquatropropriedades:simbolo,nome,
inteiro ecentavo.Essaspropriedades soinicializadas comumconstrutorcontendo todosos
parmetros.Veraseguir:
Inicializaocomplicadacomconstrutorexigindotodososparmetros:
class Dinheiro {

49

Captulo 1: Prticas e Tcnicas de Codificao

private String simbolo;


private String moeda;
private int inteiro;
private int decimal;
public Dinheiro(String simbolo, String moeda, int inteiro, int decimal) {
this .simbolo = simbolo;
this.moeda = moeda;
this .inteiro = inteiro;
this . decimal = decimal;
}
public String getSimbolo() { return simbolo; }
public String getMoeda() { return moeda; }
public int getInteiro() { return inteiro; }
public int getDecimal() { return decimal; }
@Override
public String toString() {
return simbolo + " " + inteiro + "," + decimal;
}
}
// situao de uso:
Dinheiro valor1 = new Dinheiro("R$", "Real", 45, 12);
Dinheiro valor2 = new Dinheiro("", "Libra", 34, 12);
https://gist.github.com/marciojrtorres/6190208

EntoconsiderequesmboloenomedamoedasotipicamenteemReais(R$)eque
possamseromitidosnaconstruoassumindocomopadro(default),permitindoconstruiruma
instnciadedinheiroassimnew Dinheiro(11, 34),paraonzeReaiscomtrintaequatrocentavos.
Istopodesercumpridocomasobrecargadoconstrutorcomonocdigoaseguir:
Inicializaosimplificadacomconstrutorsobrecarregado:
class Dinheiro {
private String simbolo;
private String moeda;
private int inteiro;
private int decimal;
public Dinheiro(String simbolo, String moeda, int inteiro, int decimal) {
this .simbolo = simbolo;
this .moeda = moeda;
this .inteiro = inteiro;
this .decimal = decimal;
}
public Dinheiro(int inteiro, int decimal) {
this ("R$", "Real", inteiro, decimal);
}
public Dinheiro(int inteiro) {
this ("R$", "Real", inteiro, 0);

50

Captulo 1: Prticas e Tcnicas de Codificao

}
// ...
// situao de uso:
Dinheiro valor1 = new Dinheiro(45, 12); // R$ 45,12
Dinheiro valor2 = new Dinheiro(890);

// R$ 890,00

https://gist.github.com/marciojrtorres/6190208

Alternativamenteaspropriedadespoderiamserinicializadasemtodososconstrutores,
emvezdeencadearcomchamadasathis().Avantagemdoencadeamentoestnotratamento
dosparmetros,quepodemficarcentralizadosnomtodocompleto.
Comoexemplo,considerequequeiramosevitarinstnciascomvaloresnegativos.Ento
podemosaplicarassalvaguardasnoconstrutorcompleto.Vejacdigo:
Centralizaodassalvaguardas,umavantagemdoencadeamento:
class Dinheiro {
private String simbolo;
private String nome;
private int inteiro;
private int decimal;
public Dinheiro(String simbolo, String nome, int inteiro, int decimal) {
if (inteiro < 0) throw new IllegalArgumentException("inteiro negativo: " + inteiro);
if (decimal < 0) throw new IllegalArgumentException("decimal negativo: " + decimal);
this .simbolo = simbolo;
this .nome = nome;
this .inteiro = inteiro;
this .decimal = decimal;
}
public Dinheiro(int inteiro, int decimal) {
this ("R$", "Real", inteiro, decimal);
}
public Dinheiro(int inteiro) {
this ("R$", "Real", inteiro, 0);
}
// ...
https://gist.github.com/marciojrtorres/6190208

Esta mesma tcnica pode ser aplicada a mtodos com parmetros opcionais ou que
possamcaracterizarumdefaultporomisso.
[[adicionarnamedparameterswithdefaultvalue]]
[[exercciodoCubocomparmetrosopcionais]]

FluentInterface

51

Captulo 1: Prticas e Tcnicas de Codificao

[[]]
Inteno
Motivao
Implementao
Exemplo

FunesVaridicas(VARARGS)
Algunsmtodosnotemargumentos,outrostemapenasum,emaisalgunspodemter
doisargumentos.Atravsdasobrecargapossvelredefinirummtodocomomesmonomecom
(ousem)um,doisouattrsargumentos.Mascomoprocederquandoummtodopodeterde1
anargumentosou,emoutraspalavras,noqueiramosimporlimitedeargumentosaomtodo?
onde se encaixa a tcnica de nmero variveis de argumentos conhecido como Funo
(Mtodo) Varidica ou VARARG. Funes ou Mtodos Varidicos aceitam de zero a vrios
parmetros,umaformasimpleseelegantedeimplementaropcionalidadeenorestriode
parmetros.
EstatcnicaconcordantecomoPrincpiodeProjeto ZeroOneInfinityRulepoisseum
mtodopodeaceitarat10argumentosporquenoat20,30ouentoinfintosargumentos?

Inteno
Permitirachamadadeummtodocomumnmerovariveldeargumentossemterde
sobrecarreglo.

Motivao
Umdeterminadomtodopodereceberumoumaisargumentosetunoqueresdefinir
vrias sobrecargas do mtodo com um, dois, trs, ou mesmo dez argumentos. Em vez disso
pretendese flexibilizar fazendo o mesmo mtodo responder a chamadas com um nmero
variveldeargumentos,semterdesobrecarreglo.

Implementao

Escreva o mtodo definindo os argumentos obrigatrios em primeiro lugar e por


ltimoosargumentosvariveis,naJava:tipo... argv(ex.:String... argv)

Lidecom argv comoumarray,paraacessarcadaargumentouse foreach (for


argv).

arg in

Exemplo
Considere uma classe e mtodo utilitrio que permite gerar o caminho de po25
(breadcrumb)paraaplicaesWebnoformato:

25

OCaminhodePoconhecidocomonavegaoestruturalepodeservistonosprincipaiswebsites.Maisdetalhes
veraqui:http://pt.wikipedia.org/wiki/Navega%C3%A7%C3%A3o_estrutural
52

Captulo 1: Prticas e Tcnicas de Codificao

Nvel #1 separador Nvel #2 ... separador Nvel #n

Consideretambmquenohlimite(teoricamente)paraonmerodenveis,masque
obrigatrioinformaroseparador(umchar)epelomenosortulodeumnvel.
Entreasopesdeimplementaoesto:sobrecarregaromtodoparaqueaceiteat3
nveis;usarumarraydeStringsparainformarosnveis;ouentousarVARARGS.
Primeiroumasoluocomsobrecarga,quenoideal.
Implementandoargumentosvariveiscomsobrecarga:
class WebHelper {
public static String caminhoPao(String nivel1) {
return nivel1;
}
public static String caminhoPao(char separador, String nivel1, String nivel2) {
StringBuilder caminho = new StringBuilder(nivel1);
return caminho.append(" ")
.append(separador)
.append(" ")
.append(nivel2)
.toString();
}
public static String caminhoPao(char separador, String nivel1, String nivel2,
String nivel3) {
StringBuilder caminho = new StringBuilder(nivel1);
return caminho.append(" ")
.append(separador)
.append(" ")
.append(nivel2)
.append(" ")
.append(separador)
.append(" ")
.append(nivel3)
.toString();
}
}
// situao de uso:
// Home > Eletrnicos
System.out.println(WebHelper.caminhoPao('>', "Home","Eletrnicos"));
// Home > Eletrnicos > TV's
System.out.println(WebHelper.caminhoPao('>', "Home","Eletrnicos","TV's"));
// no possvel (no h quarto nvel na sobrecarga)
System.out.println(WebHelper.caminhoPao('>', "Home","Eletrnicos","TV's","LED"));
https://github.com/marciojrtorres/livroaps/tree/master/varargs

Asoluoapresentada,comsobrecarga,funciona,masnooideal.umasoluotil
paraomomento,masingnua,poisnoconsideraquepodemexistirvriosnveis,emoutras
palavras,olimitedenveisnoprevisvel(almdetercdigoduplicado).

53

Captulo 1: Prticas e Tcnicas de Codificao

Ento, uma soluo mais profissional no dar limite, deixar a obrigatoriedade de


separadoreprimeironveledeixarachamadadomtodoabertaareceberoutrosnveis,sem
limite.Aseguirumaimplementao,usandoummtodovaritico,queconcretizaestaideia:
Implementandonmerovariveldeargumentoscomummtodovaritico:
class WebHelper {
public static String caminhoPaoVar(char separador, String nivel1, String... demaisNiveis) {
StringBuilder caminho = new StringBuilder(nivel1);
for (String nivel : demaisNiveis) {
caminho.append(" ")
.append(separador)
.append(" ")
.append(nivel);
}
return caminho.toString();
}
}
// situao de uso:
// Home > Eletrnicos
System.out.println(WebHelper.caminhoPaoVar('>', "Home", "Eletrnicos"));
// Home > Eletrnicos > TV's
System.out.println(WebHelper.caminhoPaoVar('>', "Home", "Eletrnicos", "TV's"));
// Home > Eletrnicos > TV's > LED
System.out.println(WebHelper.caminhoPaoVar('>', "Home", "Eletrnicos", "TV's", "LED"));
https://github.com/marciojrtorres/livroaps/tree/master/varargs

EmJava,aimplementaodeVARARGSrealizadacom Tipo... argv.importantedizer


que o parmetro varivel sempre o ltimo do mtodo, mesmo em outras linguagens. A
implementao,jocorpodomtodooufunousadanoexemplopodevariarnaslinguagens
sendoquecadaumadisponibilizablocosdeconstruodiferentes.Vejaamesmaimplementao
docaminhodepoemPython:
ImplementandoVARARGSemPython:
def caminhoPao(separador, nivel1, *demaisNiveis):
caminho = [nivel1]
caminho.extend(demaisNiveis)
return " > ".join(caminho)
print caminhoPao(">") # este falha, o primeiro nivel eh obrigatorio
print caminhoPao(">", "Home")
print caminhoPao(">", "Home", "Eletronicos", "TV's", "LED")
https://gist.github.com/marciojrtorres/6190394

Pythonusaoasteriscocomosinalizadordeargumentovarivel.Comodisseantes,outras
linguagenstemconstruessemelhantesdeVARARGS,sempreleiaadocumentaodaAPI.

foreach(paracada)eiterabilidade

54

Captulo 1: Prticas e Tcnicas de Codificao

As instrues foreach (para cada) so usadas para percorrer colees (arrays, listas e
conjuntos)esoteisemespecialaquelasquesoindexadas.
As linguagens tradicionalmente oferecem a construo for, onde inicializado uma
varivelqueserveparaarmazenarondice,checadoseavarivelmenorqueotamanhoda
coleoeavarivelincrementada. Est tcnica bem comum na linguagem Cetodasas
linguagenscomsintaxederivada(C++,C#,Java,),aseguirumexemploemJava:
int[] numeros = {10, 30, 50, 90, 20};
// percorrendo o array atravs de seu ndice
for (int i = 0; i < numeros.length; i++) {
int n = numeros[i];
System.out.println(n);
}

Oforeachsimplificaestaatividade,comoveremosaseguir.

Inteno
Lidarcomcadaitemdeumacoleo,percorrendoasempreocuparsecomseutamanho.

Motivao
Arrayscomndicesbaseadosnozeropodemlevaraerrosdeiniciante,ondeelementos
nosoiteradosouoarrayiteradoalmdoseutamanho.Umerrocomuminicializarondice
com1:
// inicializar o ndice com 1 pularia o primeiro item (0)
for (int i = 1; i < numeros.length; i++) {
int n = numeros[i];
System.out.println(n);
}

Leralmdocomprimentodo array causariaumaexceo,porexemplo,um array de


comprimento8temitensindexadosde0a7,umainstruoassimcausariaumaleituraforados
limites:
// exceo por leitura fora dos limites (OutOfBoundsException)
for (int i = 0; i <= numeros.length; i++) {
int n = numeros[i];
System.out.println(n);
}

Aiteraoincorretadevidoalgicadetratamentodendiceeintervalosmaiscomuma
offbyoneerror26(errarporum).Ainstruoforeacheliminaapossibilidadedesteerro,tornando
osoftwaremaisseguro,confivel,menospropensoafalhas.

Implementao
26

UmOOBEumerrolgicoqueenvolvecondieslimites,acontecendoquandooprogramadorerroneamente
adicionaounooigualaumainstruomaiorqueoumenorque,causandoaabrangnciadeitensamaisou
amenos.MaissobreOffbyoneerrorpodeservistonaWikipediaEN: http://en.wikipedia.org/wiki/Offby
one_erroreaqui:http://www.catb.org/jargon/html/O/offbyoneerror.html
55

Captulo 1: Prticas e Tcnicas de Codificao

usadaasintaxe for each elemento in coleoAslinguagensquesuportamoforeach


podemterpequenasdiferenasdesintaxe,aseguirexemplosemJava,C#,PythonePHP:
ForeachemJava:
int[] numeros = {10, 30, 50, 90, 20};
// Esta instruo lida como: 'para cada n em numeros'
// O smbolo : (dois pontos) significa 'em'
for (int n : numeros) {
System.out.println(n);
}

C#temumasintaxemaisfielaopseudocdigosendobemdiferentedofortradicional:
ForeachemC#:
int[] numeros = {10, 30, 50, 90, 20};
foreach (int n in numeros) {
Console.WriteLine(n);
}

Pythontemumasintaxemaislimpa,caractersticadalinguagem:
ForeachemPython:
numeros = [10, 30, 50, 90, 20]
for n in numeros:
print n

EemPHP,comodepraxe,asintaxebemdiferentedopadro,sendoescritoemvezde
elementoemcoleo,coleocomoelemento:
ForeachemPHP:
$numeros = array(10, 30, 50, 90, 20);
foreach ($numeros as $numero) {
print($numero);
}

Paraoutraslinguagensconsulteadocumentaoaprocuradocomandoforeach.

Exemplo
ConsidereumarraycontendoClientesosquaisqueresimprimirumaumnoconsolecom
cdigo,nomeeseguidoporpontoevrgula.Usandoo for convencionalnecessrioacessaro
ndiceenquantocomforeachpossvelleroobjetoiterativamente,veraseguir:
Iterandostringsemumarrayusandooforconvencional:
class Cliente {
Integer codigo;
String nome;

56

Captulo 1: Prticas e Tcnicas de Codificao

public Cliente(Integer codigo, String nome) {


this .codigo = codigo;
this .nome = nome;
}
public Integer getCodigo() {
return codigo;
}
public String getNome() {
return nome;
}
}
Cliente[] clientes = {new Cliente(34, "Paulo"), new Cliente(12, "Renata"),
new Cliente(56, "Pablo"), new Cliente(78, "Camila")};
// index-based o mtodo tradicional de iterar um container de objetos
for (int i = 0; i < clientes.length; i++) {
System.out.println(clientes[i].getCodigo() + " - " + clientes[i].getNome() + ";");
}
// object-based o mtodo iterativo
for (Cliente cliente : clientes) {
System.out.println(cliente.getCodigo() + " - " + cliente.getNome() + ";");
}

Autilizaode foreach reduzsignificativamenteacomplexidadeemelhorabastantea


legibilidadeporacrescentarmenosrudo,ouseja,variveistemporrias,colchetes,etc.
Percorrerummapa(conhecidotambmcomodicionrioouarrayassociativo 27)tambm
bemmaissimplesusandoforeach:
Iterandomapas(dicionrios):
// percorrer mapas (tambm conhecido como dicionrios) tambm
// mais fcil com foreach
Map<Integer, String> mapaClientes = new HashMap<Integer, String>();
mapaClientes.put(34, "Paulo");
mapaClientes.put(12, "Renata");
mapaClientes.put(56, "Pablo");
mapaClientes.put(78, "Camila");
// usando iterador (mapas no so index-based)
for (Iterator itens = mapaClientes.entrySet().iterator(); itens.hasNext(); ) {
Entry item = (Entry) itens.next();
System.out.println(item.getKey() + " - " + item.getValue() + ";");
}
// usando entry-set iterado por foreach
for (Entry<Integer, String> item : mapaClientes.entrySet()) {
27

Outraslinguagensimplementamarraysassociativosdeformabemmaiselegante,maissobrearraysassociativos
aqui:http://pt.wikipedia.org/wiki/Vetor_associativo
57

Captulo 1: Prticas e Tcnicas de Codificao

System.out.println(item.getKey() + " - " + item.getValue() + ";");


}

Observaes
Muitaslinguagenssuportamforeach,inclusivemaiselegantementequeJava,aseguirum
exemploemRuby:
ForeachemRuby:
clientes = {34 => "Paulo", 12 => "Renata", 56 => "Pablo", 78 => "Camila"}
for id, nome in clientes do
puts "#{id} - #{nome};"
end

Iterators(iteradores)eIterabilidade
Algumaslinguagensdeprogramaopermitemqueclasseseobjetoscontainers,ouseja,
objetosqueagrupamoutrosobjetos,possamseriteradosatravsdoforeachsemanecessidade
de expor a estrutura interna, seus ndices e sua implementao. Eles so conhecidos como
objetositerveis,ouobjetosquedisponibilizamumIterador(Iterator).

Inteno
Disponibilizar os objetos agregados para consulta atravs de iterao sem revelar a
estruturainternaoupreocuparsecomela.

Motivao
Por vezes temos objetos tem que agregam colees internas as quais no queremos
revelar,ouseja,permitirqueclientesexternosmodifiquemouconheamaestruturadestalista.

Implementao
A implementao varia de linguagem para linguagem, em Java os containers devem
implementarumainterfacechamadaIterable<T>.Aimplementaodestainterfacetornaoobjeto
iterveleaceitvelcomooargumentorepresentantedacoleoemforeachs,porexemplo:
Implementandoumaclasseitervel:
class Exemplar {
int codigo;
}
class Livro {
String isbn;
String titulo;
Exemplar[] exemplares = new Exemplar[] {
new Exemplar() {{ codigo = 113; }},

58

Captulo 1: Prticas e Tcnicas de Codificao

new Exemplar() {{ codigo = 245; }},


new Exemplar() {{ codigo = 334; }},
};
public Exemplares getExemplares() {
return new Exemplares();
}
class Exemplares implements Iterable<Exemplar> {
@Override
public Iterator<Exemplar> iterator() {
return new Iterator<Exemplar>() {
int index = 0;
int size = exemplares.length;
@Override
public boolean hasNext() {
return index < size;
}
@Override
public Exemplar next() {
Exemplar e = exemplares[index];
index++;
return e;
}
@Override
public void remove() {
throw new UnsupportedOperationException( "No implementado");
}
};
}
}
}
// situao de uso:
Livro livro = new Livro() {{ isbn = "113344556677";
titulo = "Arquitetura e Projeto de Sistemas"; }};
// getExemplares retorna um objeto Exemplares que Itervel (Iterable)
for (Exemplar e : livro.getExemplares()) {
System.out.println(e.codigo);
}

QualquerclassequeimplementeIterablepodeserusadaem foreachs,ondeoaprpria
linguagem chama o mtodo next para obter o prximo elemento ficando implcito ao
programador.ConsideredevolverumIterableemvezdacoleocompleta.

Exemplo
ConsidereumaclasseNotaFiscalqueagrupevriositens,instnciasdeItem,ondeconstam
ocdigodoproduto,descrio,quantidade,valorunitrioesubtotal.

59

Captulo 1: Prticas e Tcnicas de Codificao

possvel fazer como na implementao anterior, criar uma classe ItemIterator que
implemente Iterable e expor uma instncia atravs de getItens, mas desta vez vamos fazer
diferente,quetalaprpria NotaFiscal seritervel?NoquetenhamosumacoleodeNotas
Fiscais,masiteraraNotaFiscalsignificaanalisarseusItensnomesmo?Apsimplementar
deveserpossvelfazerissofor (Item item : notaFiscal)ou,emleitura:paracadaitememnota
fiscalfaa
UmaoutraformadeveraIterabilidade:
class Item {
int codigo;
String descricao;
double quantidade;
double preco;
}
class NotaFiscal implements Iterable<Item> {
int numero;
String cliente;
List<Item> itens = new ArrayList<Item>();
@Override
public Iterator<Item> iterator() {
// vamos aproveitar que java.util.List define iterator() para no ter de escrever um
return itens.iterator();
}
}
// situao de uso:
NotaFiscal notaFiscal = new NotaFiscal() {{
numero = 124554;
cliente = "Joo Paulo Silva";
itens = Arrays.asList(
new Item() {{
codigo = 1; descricao = "TV LED Samsung";
preco = 1224.49; quantidade = 1.0;
}},
new Item() {{
codigo = 1; descricao = "BluRay Player Philips";
preco = 297.99; quantidade = 1.0;
}}
);
}};
// Neste caso NotaFiscal itervel retornando seus itens
for (Item item : notaFiscal) {
System.out.println(item.descricao);
}

Este exemplo tem o propsito de, alm de apresentar o uso de objetos iterveis,
demonstrarqueoobjetoitervelnoprecisadevolverumIteradordeseuprpriotipo,ouseja,
NotaFiscaldevolveumIteratordeItem.
A estrutura usada para definir objetos iterveis tambm usada para definir objetos
gerveiscomoservistoaseguiremGenerators.
60

Captulo 1: Prticas e Tcnicas de Codificao

Generators(Geradores)
EnquantoIteratorspermitempercorrerelementosagregados, existentesecontidos em
containers, Generators permitem percorrer itens ainda no computados, definidos ou
instnciados,sendogeradosacadaiteraoesomenteseforfeitaumaiterao.
Generatorssoestruturasexistenteseusadacomfrequnciaemvriaslinguagenscomo
PythoneRuby.Estaslinguagensestabelecemumprimitivoespecialchamadoyieldquepassao
controleaolaojuntocomoelementocomputado.Aseguirumexemplodecomogerarnmeros
mparesemumlao:
Geradores(Generators)emPython:
def impares(max = 2^16-1):
for n in range(max):
if n % 2 == 1:
print 'gerando ...'
yield n
# situao de uso:
for n in impares(10):
print 'percorrendo ...'
print n
# sada:
#
# gerando ...
# percorrendo ...
# 1
# gerando ...
# percorrendo ...
# 3
# gerando ...
# percorrendo ...
# 5
# gerando ...
# percorrendo ...
# 7
# gerando ...
# percorrendo ...
# 9
https://gist.github.com/marciojrtorres/6190408

importantenotarqueoprximomparnoobtidoenquantoaiteraonoavanar,
estacaractersticaessencialparaclassificarumGeneratorediferencilodeumIterator.
NalinguagemJavanohumainiciativaafavordegeradoresaopontodeintroduziro
primitivoyield(oquefacilitariamuitoascoisas),entretantopossvelimplementlosusadoa
mesmatcnicadeiteradores.

Inteno
Fornecervaloresouobjetosquesogeradosamedidaqueolaoavana.

61

Captulo 1: Prticas e Tcnicas de Codificao

Motivao
Tutensumalistadeelementosquesodispendiososemtermosderecursos(memria,
processador,)paracriareprecisasapresentarresultadosdeformamaisresponsivadecidindo
computlosetratlosumporvezamedidaquesonecessrios.

Implementao
[[]]

EAFPvsLBYL
[[http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#eafpvslbyl]]
[[http://stackoverflow.com/questions/404795/lbylvseafpinjava]]

StaticFactoryMethods(mtodosestticosdefabricao)
Mtodos estticos para fabricao servem como uma alternativa mais elegante aos
construtores. Eles oferecem algumas vantagens como comunicar a inteno, j que eles tem
nomesenquantoconstrutoresnotem,podemfabricarobjetoscovariantes(subclassesouclasses
concretas que implementam uma interface) e, inclusive, devolver uma instncia j existente,
aplicandoreaproveitamentodeobjetos.

Inteno
Disponibilizarummeioalternativoaoconstrutorparainstanciarobjetos.

Motivao
Mtodosfbricasomaislegveisqueconstrutores,podemconstruirobjetoscovariantes
(subtipos)enoprecisam,naprtica,devolverumanovainstnciacadavezquesoinvocados
(permitemcachedeobjetos).Emoutraspalavras,elessomaisflexveisqueconstrutores.

Implementao
Aimplementaosimples,criaseummtodoestticopblicoquetemcomoretornoo
objetoconstrudo.Comoopo,podesetornaroconstrutorprivado,assimoobjetospoder
serconstrudoatravsdosmtodosfbrica.

Exemplo
ConsidereaconstruodeumobjetoDadocomquantidadevariveldelados.Aprincpio
aquantidadedeladosinformadanoconstrutorequandoomitidacriadoumDadocomseis
lados.Oproblemaquenocomunicativo,verexemplo:
ClasseDadoinstanciadacomumconstrutor:
// est claro quantos lados tem o dado?
Dado dado = new Dado();
dado.joga();
System.out.println(dado);

62

Captulo 1: Prticas e Tcnicas de Codificao

// est claro que 10 significa o nmero de lados?


dado = new Dado(10);
https://github.com/marciojrtorres/livroaps/tree/master/static_factory_method

Considerando o exemplo, no est claro quantos lados tem um Dado por padro,
presumidoquesejamseis,entretantoalgoimplcito.Aconstruoparametrizada,porexemplo
Dado(10),deixaimplcitoque10sejamonmerosdelados.ObservandoocdigofontedoDado
possvelentenderaconstruo:
ClasseDadoeseusconstrutores:
public class Dado {
private int numero;
private final int lados;
public Dado() {
this(6); // cria um dado de seis lados por padro
}
public Dado(int lados) {
this.lados = lados;
}
// ...
https://github.com/marciojrtorres/livroaps/tree/master/static_factory_method

EmboraeuprogramecommaisfrequnciaemJava,tambmestouatentoeprogramoem
outraslinguagens,quemefazmelhorcomoprogramadorJava.Comoassim?Bem,aprender
diferentesculturasdeimplementaoteajudamaverosproblemasdemaispontosdevista.No
ZendoPython28humaregradeouro:Explicitisbetterthanimplicit(Explcitomelhorque
implcito).possveltornarexplcitoimplementandomtodosfbrica:
ClasseDadocommtodosfbrica:
public class Dado {
private int numero;
private final int lados;
public Dado() {
this(6); // cria um dado de seis lados por padro
}
public Dado(int lados) {
this.lados = lados;
}
public static Dado deDezLados() {
return new Dado(10); // ou return lados(10); // para acorrentar os mtodos
}
public static Dado lados(int lados) {
return new Dado(lados);
28

OZendoPythonumatimafontedeinspiraoparadesenvolverbonsprojetosdesoftware:
http://www.python.org/dev/peps/pep0020/
63

Captulo 1: Prticas e Tcnicas de Codificao

}
// ...
// mtodos estticos de fabricao tornam o cdigo legvel
Dado dado = Dado.deDezLados();
dado.joga();
System.out.println(dado);
// mtodos fbrica so mais comunicativos que construtores
dado = Dado.lados(18);
dado.joga();
System.out.println(dado);
https://github.com/marciojrtorres/livroaps/tree/master/static_factory_method

AimplementaodomtodofbricapermitequeumDadosejainstanciadodeumaforma
maisclaraelegvel,comoDado.deDezLados()melhorquenew Dado(10).
Explcitomelhorqueimplcito!

ExceptionRethrow(relanamentodeexcees)
[[]]

StringBuilderConcatenation(concatenaodestrings)
[[]]

PropertyMap(mapadepropriedades)
[[]]

LeftHandComparison(comparaonamoesquerda)
[[]]

ShortCircuitEvaluation(avaliaodecurtocircuito)
[[&e&&,IeII,mostexpensivelastorfirst]]

ArrayasList(arraycomolista)
[[]]

OnlyOneReturn(sumretorno)
[[]]

ReturnEarly(retornecedo)

64

Captulo 1: Prticas e Tcnicas de Codificao

Oretornocedoumatcnicautilizadaparasairomaisbrevementepossveldeum
mtodo, eliminando processamento adicional. Tambm muito prtico para eliminar o
aninhamentodeexpressescondicionais(if's).
Retornarcedocontrastacomoprincpiodehaverapenasumretorno,vistonotpico
anterior.Cadaumtemsuasvantagensedesvantagensaseremavaliadaspeloprogramador.

Inteno
Sairdomtodoassimquenohouvermaisnadaacomputarouovalorcomputadoj
estiverdisponvel.Diminuiroaninhamentodeexpressescondicionais.

Motivao
Sairdeummtodologoapsterovalorderetornodisponvelenoexecutaraslinhas
subsequentespodetrazerganhosdeperformance.
Quandoexistemmuitasexpressescondicionaisaninhadas(if's dentrode if's)ousodo
retornocedopodediminuiroaninhamentoeaindentao,melhorandobastantealegibilidade
domtodo.

Contraindicaes
Emmtodosmuitolongos, por exemplo,com50linhasdecdigooumais,o usode
mltiplosreturnspodedificultaradepurao(eliminaodebugs)jquetornadifcilsaberao
certoqualpontodesadaestsendousadoequaloestadofinaldomtodo,poisalgumaslinhas
nemsempresoexecutadas.

Implementao
A mecnica no complicada. Em um mtodo que executa determinadas instrues
baseadas condicionalmente na entrada, substitua a varivel que armazena o retorno por um
returnexplcito.
Emmtodos void,masquetemclusulasguarda,substituaacondiodaexecuopor
umacondiodenoexecuocomumreturn.
Observeosexemplosaseguirparaosdoiscasoscitados.

Exemplo
ConsidereumaclasseSeguranca,quetemoobjetivodedefinironveldeacessodeum
usuriosegundoalgumaspropriedades.Oexemploestaseguir:
ClasseSegurancasemaplicaroReturnEarly:
public class Seguranca {
public enum NivelAcesso {
Nenhum, Visitante, Operador, Administrador;
}
public static NivelAcesso privilegio1(Usuario usuario) {

65

Captulo 1: Prticas e Tcnicas de Codificao

NivelAcesso nivel = null ;


if (!usuario.isBloqueado()) {
if (usuario.getCargo() != null ) {
if (usuario.getCargo() == Usuario.Cargo.Gerente) {
nivel = NivelAcesso.Administrador;
} else if (usuario.getCargo() == Usuario.Cargo.Funcionario) {
nivel = NivelAcesso.Operador;
}
} else {
nivel = NivelAcesso.Visitante;
}
} else {
nivel = NivelAcesso.Nenhum;
}
return nivel;
}
// ...
https://github.com/marciojrtorres/livroaps/tree/master/return_early

Esta implementao obedece ao Only One Return, mas ao custo do aninhamento de


expresses condicionais e da existncia de uma varivel nivel. Este mtodo pode ser escrito
usandooReturnEary fazendo comquecadacondio dumretorno imediato.Aseguir as
alteraes:
ClasseSegurancaaplicandooReturnEarly:
public class Seguranca {
public enum NivelAcesso {
Nenhum, Visitante, Operador, Administrador;
}
// ...
public static NivelAcesso privilegio2(Usuario usuario) {
// se est bloqueado, sem acesso
if (usuario.isBloqueado()) return NivelAcesso.Nenhum;
// gerente admin
if (usuario.getCargo() == Usuario.Cargo.Gerente) {
return NivelAcesso.Administrador;
}
// funcionario op
if (usuario.getCargo() == Usuario.Cargo.Funcionario) {
return NivelAcesso.Operador;
}
return NivelAcesso.Visitante; // no est bloqueado e no func
}
// ...
https://github.com/marciojrtorres/livroaps/tree/master/return_early

66

Captulo 1: Prticas e Tcnicas de Codificao

Autilizaodestatcnicaimplicaemumareconstruodalgicadomtodo,embora
diferentetantoaprimeiracomoasegundaimplementaoatendemaosrequisitos.
Umaoutrautilidadeparasimplificarasclusulasguarda,comonoexemploaseguir:
SimplificandoclusulasguardacomReturnEarly:
public class Seguranca {
// ...
public static void geraSenha1(Usuario usuario) {
if (usuario != null) {
if (!usuario.isBloqueado()) {
usuario.setSenha(java.util.UUID.randomUUID()
.toString().split("-")[0]);
}
}
}
public static void geraSenha2(Usuario usuario) {
if (usuario == null) return;
if (usuario.isBloqueado()) return;
usuario.setSenha(java.util.UUID.randomUUID().toString().split("-")[0]);
}
// ...
https://github.com/marciojrtorres/livroaps/tree/master/return_early

Considerandoummtodo geraSenha,mascomasrestriesdeousurionosernuloe
noestarbloqueado.
Oprimeiromtodo(geraSenha1)guardaainstruocomdoisif'saninhados(poderiaser
usadoum&&).Notequeelesguardamacondiodeexecuo.
Osegundomtodo(geraSenha2)guardaacondiodenoexecuo,ouseja,acondio
emqueaentradanovlida.

GuardClause(clusulasalvaguarda)
[[]]

BooleanReturn(retornoboleano)
[[]]

BooleanSuccess/FailReturn(retornodesucesso/falhacomboleano)
[[]]

DefaultValueWithTernaryExpression(valorpadrocomexpressoternria)
[[]]

RegexValidation(validaocomexpressesregulares)
67

Captulo 1: Prticas e Tcnicas de Codificao

[[]]

Kluge:umaHistriaPOG
[[]]

Kluge:ConstantInterface
[[]]

Kluge:NumbertoString
[[]]

CodeGolf
[[]]

Palavrasfinaissobreprticasetcnicas
[[]]

Bibliografia
[IMPATTERNS] BECK, Kent. Padres de Implementao : Um Catlogo de Padres
Indispensvel para o Dia a Dia do Programador . 1a ed. Editora Bookman, 2013.
[CLEANCODE] MARTIN, Robert. Cdigo Limpo: Habilidades Prticas do Agile Software.
1a. ed. Editora: Alta Books, 2009.
[JAVAEFETIVO] BLOCH, Joshua. Java Efetivo. 2a. ed. Editora: Alta Books, 2008.

68

Captulo 2: Refatoraes e Melhoria do Cdigo Existente

Captulo2:RefatoraeseMelhoriado
CdigoExistente
Cdigosquehumanospossamentender
Qualquer idiota capaz de escrever cdigo que um
computador possa entender. Bons programadores escrevem
cdigoquesereshumanospodementender
MartinFowler

Nocaptuloanteriorfalamossobrecdigolimpoetcnicasparaescreverumbomcdigo.
Estetpicoestfortementerelacionadoaoquefoifaladoantes,mascomopressupostodeque
estamos trabalhando com cdigo legado, ou seja, cdigo que j existe, j foi escrito,
provavelmenteatporoutrosprogramadores.
Nemsempreescrevemosumcdigofromscratch,oudo "dozero"29,frequentemente,
enquantoprogramadoresedesenvolvedor,temosquetrabalharemcimadecdigoalheio,ouat
umcdigonossoquenemnoslembrvamosmaisdeterescrito.
Amaioriadosprogramadoresqueconheodetestamtrabalharsobrecdigolegado,em
especialseestmauescrito,masnohfuga,temosquefazlo.Esteomomentodefazeruma
escolha30:
A)segueescrevendosobreessecdigofeionomesmoestilo,ouseja,feio;
B)ou,melhoraaqualidadedestecdigoantesdeescreveroseu.

DefinindoRefatorao
A definio de refatorao simples: a alterao do cdigo sem alterar o
comportamentodosoftware.Emoutraspalavras,tualterasocdigojexistentemelhorandoa
qualidadeinternadosoftware,masparaousuriofinalosoftwareseguefuncionandocomo
estavaantes,ouseja,aqualidadeexternanoalterada.
29
30

Tambmconhecidocomodaplanilha,donada:http://en.wiktionary.org/wiki/from_scratch
MenoaquiafilosofiadoMatrix:http://en.wikipedia.org/wiki/Red_pill_and_blue_pill
69

Captulo 2: Refatoraes e Melhoria do Cdigo Existente

Da minha experincia posso dizer, j trabalhei em muito software mau escrito que,
acreditem, funcionava. Contudo, introduzir uma nova funcionalidade ou alterar uma
funcionalidadeexistenteexigiamaisprocessamentomentaldoqueonormalparaentender,alm
daregradenegcio,oshierglifos31deixadospelosmeusqueridoscolegasdeprofisso.Querum
exemplo?Tome:
Pssimocdigo32,adivinheoqueelefaz:
if ($numero_nota >= 1 && $numero_nota < 10) {
$numero_nota = '00000000' . $numero_nota;
} else if ($numero_nota >= 10 && $numero_nota < 100) {
$numero_nota = '0000000' . $numero_nota;
} else if ($numero_nota >= 100 && $numero_nota < 1000) {
$numero_nota = '000000' . $numero_nota;
} else if ($numero_nota >= 1000 && $numero_nota < 10000) {
$numero_nota = '00000' . $numero_nota;
} else if ($numero_nota >= 10000 && $numero_nota < 100000) {
$numero_nota = '0000' . $numero_nota;
} else if ($numero_nota >= 100000 && $numero_nota < 1000000) {
$numero_nota = '000' . $numero_nota;
} else if ($numero_nota >= 1000000 && $numero_nota < 10000000) {
$numero_nota = '00' . $numero_nota;
} else if ($numero_nota >= 10000000 && $numero_nota < 100000000) {
$numero_nota = '0' . $numero_nota;
} else if ($numero_nota >= 100000000 && $numero_nota < 1000000000) {
$numero_nota = '' . $numero_nota;
}
https://gist.github.com/marciojrtorres/6190421

Programadoresiniciantesachamestecdigoomximo,programadoresespertosrieme
deixampral,programadoresprofissionaisreescrevemestecdigo.Apropsito,podesusareste
cdigocomoumexerccio,apscompreenderoseupropsitorescrevao(alinguagemPHP).
Sefoifcildeentender,aquivaioutro(copieiecoleiexatamentecomoencontrei):
Esse"domal":
$colunaDifetente = $_SESSION['janelaBusca'][$_POST['idJanela']]['colunaDiferente'];
if(is_array($colunaDifetente)){
if (is_array($vet)){
foreach ($vet as $k=>$v){
foreach ($v as $k1=>$v1){
foreach ($v1 as $k2=>$v2){
foreach ($colunaDifetente as $k3=>$v3){
if ($vet[$k]['r'][$k2]['c'] == $k3) {
$vet[$k]['r'][$k2]['c'] = $v3;
}
}
}
}
}
}
}

31

http://pt.wikipedia.org/wiki/Hierglifo

32

Vejamaisaqui:http://codesmell.woompa.com.br
70

Captulo 2: Refatoraes e Melhoria do Cdigo Existente


https://gist.github.com/marciojrtorres/6190427

Aseguirfalaremosmaisderefatoraes,comojviste,elanecessria,masenfim,a
descriodasrefatoraesconsisteem:

umamotivao:oporqudeaplicar,realizararefatorao;

umamecnica:passosmaisbsicosparaexecutla(a.k.a.Receitadebolo:);

umexemplo:cdigosdeexemplo.

Porquerefatorar?
Bem,serefatorarreescreverumcdigoquefuncionaentoporqueeuvourefatorar,se
elejfunciona33?Bem,algunsargumentosdeFowler[FOWLER]afavordarefatorao:

Melhoraoprojetodosoftware:osprojetoscostumamdeteriorar.Vriosciclosde
manuteno tendem a desorganizar o cdigo (presses de gerentes de projeto e
clientes tambm). Refatorar ajuda a eliminar cdigo morto e repetido bem como
melhoraaclarezaeconsequentementeoprojetodosoftware.

Tornaosoftwaremaisfcildeentender:arefatoraoadicionaclarezaefacilitao
entendimento docdigo,nopara ti, masparaa equipeinteira. No refatoramos
pensandoemnsmesmos,refatoramospensandoemtodosqueumdiaterodelero
cdigo.Aclarezadocdigodiminuioesforomentalparaentendloepermiteque
tu consigas entender melhor o projeto inteiro. Cdigo feio atrapalha a nossa
compreensodoprojeto.

Ajudaaencontrarfalhas:algumasfalhasnocdigosodifceisdeencontrareainda
mais difceis de encontrar em cdigos bagunados. A refatorao pode dar outro
pontodevistaaocdigoedesencobrirerrosqueantesnoficavamclaros.

Ajudaaprogramarmaisrapidamente:bvioqueumcdigoconfusovaitetomar
maistempoparaentendlo,quialterlos.Cdigosclaroselimpostendemalevar
menostempoemalteraes.

Segundo pesquisas, programadores que refatoram seu cdigo tem menor tendncia a
doenascardiovasculares34.

Mauscheirosnocdigo(a.k.a.CodeSmell)
Depoisdeconheceroquerefatorareporquerefatoraragoravem"quandorefatorar"?
Umaheursticausadapararesponderessaperguntaadetecode mauscheirosnocdigo,
conhecidocomoCodeSmell35.Partesedaideiaqueaolerocdigopossvelidentificarpartes

33

34
35

Sefunciona,entotcertoPrincpiodeProgramaoOrientadaaGambiarras(PPOG):
http://desciclopedia.ws/wiki/Programao_Orientada_a_Gambiarras#PPOG
Essapartebrincadeira:)
http://martinfowler.com/bliki/CodeSmell.html
71

Captulo 2: Refatoraes e Melhoria do Cdigo Existente

estranhas,esquisitas,que,digamos,tefaatorceronariz(oudizerPQPquemescreveuessa
@#$@#).
Alguns cdigos podem ter smells que podem ir do simplesmente ambguo ao
incrivelmenteininteligvel. Estes smells foramdocumentadosporvriosautoresenestetpico
vou listar aqueles mais comuns publicados por Martin Fowler no seu livro refatorao
[FOWLER].

Cdigoduplicado
Este,penso,osmellmaisfrequentenoscdigospora.relativamentefcilidentificar
cdigoduplicado,eelenoprecisaserexatamenteidntico,masvaitedaraquelasensaode
quealgumfezumCTRL+C CTRL+V emudouumaouduaspalavras.Cdigoduplicadopssimo
paraoprojetopoisalteraesnestecdigotemdeserfeitasemtodososlugaresqueeleaparece.
Asrefatoraestpicasparacdigoduplicadointroduzirnovosmtodos,classesebibliotecas,
querepresentemdeumasvezestecdigoepermitamseureuso.

Classesemtodomuitolongos
Noexisteumamtricapadroparaotamanhodeumaclasseedeummtodo,mas
saibaquantomaiorumaclasseoumtodohmaischancedeeleterdemudaremaisdificuldade
desaberondemudar.Tentesemprequepossvelquebrarmtodoslongosemmtodosmenores
introduzindo novos mtodos. Classes muito longas podem ser subdivididas em mais classes.
Quandomenormaisfcildedaramanuteno(ver Implementemtodospequenos).AlgunsIDEs
do suporte assistido a refatorao como o NetBeans. No menu refatorao se encontram
algumasmencionadasnestelivro,vejailustraoaseguir:

FuncionalidadesdomenurefatoraonoNetBeans

Excessodeparmetros

72

Captulo 2: Refatoraes e Melhoria do Cdigo Existente

A quantidade excessiva de parmetros j foi discutida em Parmetros no tpico


Qualidade do Cdigo. Parmetros em excesso dificultam o entendimento e aumentam o
acoplamento.Arefatorao"introduzirumobjetoparmetro"podeeliminaressesmell.

Gruposdedados
Dados que andam juntos devem ter seu prprio objeto. Em muitas classes alguns
atributosparecempertenceraumoutroobjeto.Umbomtesteeliminarumdessesatributose
verseapresenadosoutrosaindafazemsentido.Gruposdedadosgeralmentesoextrados
paraumanovaclasse,quemelhoraasemnticadoprojetobemcomopromoveoreuso.Umbom
exemplodegrupodedadospodeservistonocdigoaseguir:
Sintaomaucheironessaclasse:
class Fornecedor {
int

codigo;

String nome;
String razaoSocial;
String cnpj;
String rua;
int

numero;

String bairro;
String cep;
String telefone;
String inscricaoEstadual;
// ...

Umaperguntaparaajudarnaidentificaodo smell GrupodeDados:seoatributorua


fosseremovido,queoutrosatributosficariamsemsentido?
Oatributonumero,porexemplo,podeserumtantoconfuso.Imagineasituaodeuso
desteatributo:
Usandoumatributoquepodelevaraummauentendimento:
Funcionario funcionario = dao.buscaPorNome("Celso & Silva LTDA.");
field.setText(funcionario.numero); // o nmero do funcionrio?

Algunsatributosparecequepertencemaquelaclasse,comoonmero,eapsumpouco
deobservaosepercebequerua,numero,bairroecepandamjuntosporquerepresentamum
Endereo (um substantivo, um tipo). Dadosque andam juntos devem serclasses, entretanto
vemosalguns"contornos"comoadiodecomentrios:
Comentar,infelizmenteoprimeirorecurso:
// dados do endereo do funcionrio
String rua;
int

numero;

String bairro;
String cep;
// fim dos dados do endereo do funcionrio

Outraopo,tambmdeselegante,paraesclarecerosatributosusarprefixos:

73

Captulo 2: Refatoraes e Melhoria do Cdigo Existente


Prefixar,emgeral,umasoluodeselegante:
String enderecoRua;
int

enderecoNumero;

String enderecoBairro;
String enderecoCep

Comentrioseprefixosoapenasformasdeempurraroproblema,ecaracterizamuma
resistnciaacriaodeclasses,chamadode"ObsessoPrimitiva"equeservistoaseguir.

Obsessoprimitiva
J falamos um pouco sobre tipos de dados, em especial eles se dividem em duas
categorias:tiposprimitivosecomplexos.Osprimitivossoumasimplesrepresentaobinria
deseuvalor,ocupampoucamemriasecomparadoaoscomplexos,porexemplo,otipointeiro
doJava(int)utiliza32bits(4bytes)paraarmazenarumnmero.Ostiposcomplexossoclasses
ouestruturascomdadoselgica,ocupammaismemriaetemumciclodevidadiferentedos
tiposprimitivos(namaioriadaslinguagens),comoexemplootipoIntegerdoJava(quegasta
maisde32bits).
Umdeciso,umaescolha,importantedodesenvolvedorquandousarumtipoprimitivo
ou complexo para representar uma informao. A obsesso primitiva observada quando a
maiorpartedasinformaessorepresentadascomtiposprimitivos,mesmoondeelesnoso
adequados.
NalinguagemJava,Stringssotiposcomplexos,masparticipamdosmellObsessoprimitiva

A refatorao usada para o smell Obsesso primitiva substituir o primitivo por um


complexo,ouseja,aoinvsdeusarint, double, String etc,usarumtipocomplexoadequado.
Vouilustrarmelhorcomumcdigodeexemploaseguir:
Umexemplodosmellobsessoprimitiva:
class Produto {
int

codigo;

String descricao;
int

peso;

Davemaprimeiradvida,opesoarmazenadoemqualunidadedemedida?Aseguir,a
soluomaisingnua:
Soluoingnuaparadarsignificadoaumprimitivo:adicionarumcomentrio:
class Produto {
int

codigo;

String descricao;
// o peso deve ser em gramas
int

peso;

74

Captulo 2: Refatoraes e Melhoria do Cdigo Existente

Chameidesoluoingnuaporquenopassadeumaplacebo.Porexemplo,algumque
utilizeaclasseprodutoaousarapropriedadepesoaindanosaberiaseounoemgramas,j
quenoestlendoocdigofonte.Imagineasituaodeuso:
Situaodeuso:
Produto produto = new Produto(); // at aqui tudo bem
produto.peso = 100; // o produto pesa 100 // "100 o qu"?

O cdigo anterior esclarece melhor o problema, enfim no h como saber sem ler o
cdigofontequeunidadeestsendousada.Umasoluomenospiorseria:
Soluopaliativa:
class Produto {
int

codigo;

String descricao;
int

pesoEmGramas;

}
// situao de uso:
Produto produto = new Produto(); // at aqui tudo bem
produto.pesoEmGramas = 100; // t melhor

Ficamelhor,bem,pelomenosatvirorequisitodequeopesopodeserinformadoem
kilos,gramasoulibras.Asoluomaisbsicaanveldecdigomaspssimaanveldeprojeto
adicionarumavariveldetipo,tambmprimitiva:
Aobsessoprimitivacontinua,adicionandoumavariveldetipo:
class Produto {
int

codigo;

String descricao;
int

tipoPeso; // 0: grama, 1:kilo, 3:libras

int

peso;

}
// situao de uso:
Produto p = new Produto(); // at aqui ok
p.tipoPeso = 1; // h?
p.peso = 200;

// sem conhecer o cdigo-fonte, qual o peso?

Acho que j deu para notar a obsesso primitiva, insistentemente modelando com
inteiros,doubles,strings,etc.Jdisseantes,reitero,programaoorientadaaobjetosimplicaem
criarobjetos.Asoluoadequadaintroduzirumaclasse,sendoqueclassessignificamtipos,
tiposcomplexos.Aseguiraclasse,otipo,Peso:
Introduzindonovasclasses,umremdioparaaobsessoprimitiva:
class Produto {
int

codigo;

String descricao;
Peso

peso;

}
// situao de uso:

75

Captulo 2: Refatoraes e Melhoria do Cdigo Existente

Produto produto = new Produto();


produto.peso = Peso.emKilos(2);

A classe Peso ter os atributos e mtodos necessrios para lidar com as diferentes
representaesdepeso.Oexemplousadoilustraasituaodekilos,masigualmentepodese
usarconstruesestticasparagramas,libras,etc.

Comentrios(tambmconhecidoscomodesodorante)
J deves ter uma ideia do uso correto de comentrio como visto na seo Escreva
Comentriosteis.Defato,oproblemademuitoscomentriosequeelespodemestaralipara

explicar um cdigo difcil de entender, ou seja, o cdigo no tem um bom cheiro e os


comentrios,digamos,desodorizamocdigo.Claro,comentriossomelhoresdoquenada,mas
videamxima"Bomcdigosuamelhordocumentao".

Nmeros(eStrings)mgicos
umdossmellsmaiscomunsefceisdeidentificar.Muitasexpresses,lidemelascom
textoounmeros,dependemdedadosdinmicosouestticos.Osdinmicosconhecemoscomo
variveis(daonome,d),osestticossoconhecidoscomoliteraisouconstantes.Sempreque
uma expresso faz uso de nmeros literais, e difcil entender o significado destes literais,
dizemosquesonmerosmgicos.Aseguirumpequenoexemplo:
Nmerosmgicosdeixamocdigoobscuro:
public void imprime(Documento doc) {
if (doc.getStatus() != 2) return;
if (doc.getMargemDireita() > 400) {
doc.setMargemDireita(380);
// ...

Nmeroseoutrosliteraisnocdigodificultamoentendimentoedevemsersubstitudos
porconstantes,oquenomuitocomplicado:
Dnomeaosliterais,useconstantes,novaistearrepender:
static final int NOVO = 0;
static final int ALTERADO = 1;
static final int SALVO = 2;
public void imprime(Documento doc) {
if (doc.getStatus() != SALVO) return;
// ...

Maisadiante,emrefatoraes,sermelhordiscutidaaintroduodeconstantes.

RefatoraesComuns

76

Captulo 2: Refatoraes e Melhoria do Cdigo Existente

Pararemoverosmauscheiroscitados,eoutros,existemvriasrefatoraes,quevodas
maissimples,comorenomear,atasmaiscomplicadascomointroduzirsuperclasses.Aseguir
umalistaderefatoraestpicasqueservempararemovero"maucheiro",ossmells,doprojeto.

Renomear
Alteraronomedeclasses,mtodosevariveisarefatoraomaiscomumesimples,e
quetrazmuitosbenefcios.Oprincipalmedodealteraronomedeestruturasjdesenvolvidas
criar,digamos,umaquebradeiranocdigodevidoasreferncias.Emoutraspalavras,renomear
umaclasseimplicaemreferencilapelonovonomeemtodososlocaisqueelausada,bem
comosemudaresapenasumatributo(get,set).Comcertezaumtrabalhorduoquandofeito
manualmente,masfelizmentetemosIDEsquepossibilitamarenomeaoassistidadeclasses,
membros(variveisdeinstnciaemtodos)evariveis;ouseja,oassistentedoIDEtambm
aplicar o novo nome a todas as ocorrncias da instruo renomeada. Por exemplo, para
renomear uma varivel, no NetBeans pressione CTRL+R, no Eclipse SHIFT+ALT+R. A seguir um
exemplo:
Mtododesenvolvidopelo"ladonegrodafora":
// as variveis obscuras esto em negrito
public void save(Ator a, int idu) {
Connection c1 = ConnectionFactory.newConnection();
try {
String sql = "INSERT INTO atores " +
" (nome, sobrenome, id_usuario, versao) " +
" VALUES (?, ?, ?, ?)";
PreparedStatement c2 = c1.prepareStatement(sql);
c2 .setString(1, a.getNome());
c2 .setString(2, a.getSobrenome());
c2 .setInt(3, idu);
// ...

Masoquesignifica idu?Claro,comumpoucodeobservaochegamosaoc2.setInt(3,
idu),quevemdosqlINSERT INTO atores (nome, sobrenome, id_usuario ,ah,ioiddousurio!
Mesmo assim, buscamos que o cdigo seja inteligvel sem muito esforo, sem que tenha de
realizarumabuscavisualeumraciocnioexcessivoparaumacoisatobanal,queremosnos
preocuparcomasregrasdenegcio.
Muitocdigo feio podesermelhoradousandoapenasaartededarnovosnomes.Para
renomear, no NetBeans por exemplo, basta posicionar o cursor sobre a varivel (metdo ou
classe)epressionarCTRL+R,vejacomoficaavarivelidu,c1ec2:
Mtodorefatorado:
// as variveis renomeadas esto em negrito
public void save(Ator a, int idUsuarioResponsavel ) {
Connection conexao = ConnectionFactory.newConnection();

77

Captulo 2: Refatoraes e Melhoria do Cdigo Existente

try {
String sql = "INSERT INTO atores " +
" (nome, sobrenome, id_usuario, versao) " +
" VALUES (?, ?, ?, ?)";
PreparedStatement comando = conexao.prepareStatement(sql);
comando .setString(1, a.getNome());
comando .setString(2, a.getSobrenome());
comando .setInt(3, idUsuarioResponsavel);
// ...

AmuitotempoatrstiveumcolegadeclassechamadoRailnder.Moraldahistria?Dbonsnomes!

Extrair(introduzir)classe
bastante comum para encapsular Grupos de Dados ou pelo menos mover a
responsabilidadedeumaclassequefazcoisasdemaisparaoutrasclassesmenores(vejafaauma
coisas).Amecnicabastantesimples:criarumanovaclasse,moverosatributosemtodos
paraela,eporfimreferencila.Vejaaseguirumexemplosimples:
Gruposdedadoscandidatosaextrao:
// os atributos candidatos a extrao esto em negrito
class Cliente {
Integer codigo;
String

nome;

String

tel_ddd_residencial;

String

tel_numero_residencial;

String

tel_ddd_celular;

String

tel_numero_celular;

String

CPF;

AclasseClienteapresentaatributosquepodemserresponsabilidadedeoutraclasse:os
nmerosdetelefone.Naprtica,teremososmesmosdados,queapenasserorepresentadosde
outraforma.
Repare como o atributo pode ser quebrado apenas observando o nome
tel_ddd_residencial,ondetelsugereumnovotipo, dddenmerosugerematributosdestetipoe
residencialecelularpodemserduasinstncias.Aseguir,umaversorefatorada:
Versorefatoradacomaextrao(introduo)deumanovaclasse:
class Cliente {
Integer

codigo;

String

nome;

Telefone telefoneResidencial;
Telefone telefoneCelular;
String

CPF;

...

78

Captulo 2: Refatoraes e Melhoria do Cdigo Existente

class Telefone {
String ddd;
String numero;
...

Aextrao(introduo) deuma classetrazvantagenscomo reuso, encapsulamentoe


melhornveldeabstraonoprojeto.
PoroutroladoaintroduodenovasclassesaumentaaindireoecriaumGrafode
Objetos36,ouseja,umobjetoquereferenciaoutro,queporsuavezreferenciaoutros,eassimpor
diante.Paraacessarcertaspropriedadesnecessrionavegarnografo,porexemplo:
Navegandonografodeobjetos:
Cliente cliente = new Cliente();
cliente.nome = "Joo Silva";
Telefone telefone = new Telefone("53", "32323232");
cliente.telefoneResidencial = telefone;
System.out.println(cliente.telefoneResidencial.ddd);
System.out.println(cliente.telefoneResidencial.numero);
...
// ou algo mais complexo, obtendo o nmero do telefone da empresa onde
// o cliente trabalha:
cliente.empresa.gerente.telefone.numero

casoorelacionamentoentreobjetosnosejabemprojetadoalgunsproblemaspodemocorrercomoa
refernciacircular:http://en.wikipedia.org/wiki/Circular_reference

Extrair(introduzir)superclasse
Bem semelhante a extrair classe, com algumas diferenas na mecnica, o extrair
superclasse busca mover campos (atributos) e mtodos para uma nova classe e usla como
superclasse.Amecnicaconsisteemcriarumanovaclasse,moverosatributosemtodospara
ela,eporfimestendla.Aseguirumexemplo:
Extraindoatributoscomunsparaumasuperclasse:
// atributos comuns em negrito
class Cliente {
Integer codigo ;
String

nome;

String

CPF;

String

razaoSocial;

String

CNPJ;

Date

dataCadastro ;

// ...
36

http://en.wikipedia.org/wiki/Object_graph

79

Captulo 2: Refatoraes e Melhoria do Cdigo Existente

// pode ser reestruturado assim:


abstract class Cliente {
Integer codigo ;
Date

dataCadastro ;

// ...
class ClientePessoaFisica extends Cliente {
String

nome;

String

CPF;

// ...
class ClientePessoaJuridica extends Cliente {
String

razaoSocial;

String

CNPJ;

// ...
// situao de uso:
ClientePessoaFisica cliente = new ClientePessoaFisica();
cliente.codigo = 3; // acessvel por herana

NaclasseClientealgunsatributossoopcionais,conformeotipodecliente,tornandoa
umaboacandidataarefatorao.

Extrair(introduzir)mtodo
umarefatoraotpicapararemovercdigoduplicadoouadicionarclarezaaocdigo.
Ocdigoduplicadopodeserextrado(daonome)paraumnovomtodo.
A mecnica consiste em criar um um novo mtodo com um nome que demonstre
claramenteseuobjetivo,moverocdigoparaestenovomtodoesatisfazerasdependncias
parametrizandoasnomtodo.
OsIDEsdisponibilizamassistentesqueexecutamestamecnica;noNetBeanseEclipse,
procurenomenurefatoraraopo"Extrair(ouIntroduzir)mtodo".NoNetBeans,selecioneas
instruesepressione SHIFT+ALT+M.Aseguirumexemplo:
Lgicacompartilhadaentreosmtodos,umaboacandidataaextrao:
// a lgica compartilhada est em negrito
List<Ator> buscaTodos() {
List<Ator> atores = new ArrayList<Ator>();
Connection conexao = ConnectionFactory.newConnection();
try {
String SQL = "SELECT * FROM atores";
PreparedStatement comando = conexao.prepareStatement(SQL);
ResultSet resultado = comando.executeQuery();
while (resultado.next()) {
Ator ator = new Ator();
ator.setId(resultado.getInt(1));
ator.setNome(resultado.getString( 2));
ator.setSobrenome(resultado.getString(3));
ator.setVersao(resultado.getTimestamp(4));
atores.add(ator);
}
// ...

80

Captulo 2: Refatoraes e Melhoria do Cdigo Existente

List<Ator> buscaPorNome(String nome) {


List<Ator> atores = new ArrayList<Ator>();
Connection conexao = ConnectionFactory.newConnection();
try {
String SQL = "SELECT * FROM atores WHERE nome = ?";
PreparedStatement comando = conexao.prepareStatement(SQL);
comando.setString(1, nome);
ResultSet resultado = comando.executeQuery();
while (resultado.next()) {
Ator ator = new Ator();
ator.setId(resultado.getInt(1));
ator.setNome(resultado.getString( 2));
ator.setSobrenome(resultado.getString(3));
ator.setVersao(resultado.getTimestamp(4));
atores.add(ator);
}
// ...

OsmtodosbuscaTodosebuscaPorNomecompartilhamalgicadepreenchimentodalistade
atores.Estalgicapodeserextradaparaumnovomtodoqueserexecutadoemseulugar.Este
novomtodotemquereceberasdependnciasnecessriasparaconcluirseutrabalho,quena
partedestacadoexemplosoasvariveisresultadoeatores.Aseguiraversorefatorada:
Lgicacompartilhadaextradaparaummtodo:
List<Ator> buscaTodos() {
List<Ator> atores = new ArrayList<Ator>();
Connection conexao = ConnectionFactory.newConnection();
try {
String SQL = "SELECT * FROM atores";
PreparedStatement comando = conexao.prepareStatement(SQL);
ResultSet resultado = comando.executeQuery();
resultSetParaAtores(resultado, atores);
// ...
List<Ator> buscaPorNome(String nome) {
List<Ator> atores = new ArrayList<Ator>();
Connection conexao = ConnectionFactory.newConnection();
try {
String SQL = "SELECT * FROM atores WHERE nome = ?";
PreparedStatement comando = conexao.prepareStatement(SQL);
comando.setString(1, nome);
ResultSet resultado = comando.executeQuery();
resultSetParaAtores(resultado, atores);
// ...
void resultSetParaAtores(ResultSet resultado, List<Ator> lista) {
while (resultado.next()) {
Ator ator = new Ator();
ator.setId(resultado.getInt( 1));
ator.setNome(resultado.getString( 2));
ator.setSobrenome(resultado.getString( 3));
ator.setVersao(resultado.getTimestamp( 4));
atores.add(ator);
}
}

81

Captulo 2: Refatoraes e Melhoria do Cdigo Existente

importantesalientarquearefatoraomelhoraoprojeto.Antesdarefatorao,sefosse
necessrioadicionarumcampoamaisnaclasse Ator, digamos,biografia,teramosdealterar
todososmtodospara chamar setBiografia;apsarefatorao,temosdealterarapenasum
mtodo,oresultSetParaAtores.

Introduzirvarivelexplicativa
Variveisexplicativassoteisparadeixarmaisclaraumaexpressocondicionalconfusa.
Elasdevemserintroduzidaslogoacimadasexpressesquedesejamexplicarcomopropsitode
melhoraraleitura.
A mecnica simples, crie uma varivel booleana antes da expresso condicional e
atribuaaelaoresultadodaexpresso;apssubstituaaexpressopelavarivel.Aseguirum
exemplo:
Lgicacondicionalconfusacandidataaintroduodevarivelexplicativa:
// lgica confusa em negrito
public void imprime(Documento doc) {
if (doc.getHeader().getText().trim().length() > 0) {
// ...

O objetivo de tornar desnecessrio o uso de raciocnio para entender a expresso


condicional.Oleitordevepassarosolhoselogoentenderoqueelafaz.Useocdigorefatorado
aseguirparacomparar:
Lgicacondicionalconfusacandidataaintroduodevarivelexplicativa:
public void imprime(Documento doc) {
boolean temCabecalho = doc.getHeader().getText().trim().length() > 0;
if (temCabecalho) {
// ...

Percebaaclarezaquandoocdigolido:if (temCabecalho).SetemCabealhomelhor
que Se doc.getHeader().getText().trim() Sempre que possvel o cdigo deve ser escrito de
formaaserlidocomoumtexto.

Invertercondicional
Cadacondicionalincluimaisumcaminhonalgicaeadicionamaiscomplexidadeao
programa.Tornlolegvelimportante,tefargastarmenostempoquandovoltarnocdigo.
sugeridoinverterocondicionalquandoaexpressoavaliaanegaoenoaafirmao,
ouseja,humoperadordenegao(noJavao!exclamao)nocondicional,queporolhos
cansadosepoucoatentospodepassardespercebido.Amecnicaestemremoveranegaoe
inverterasclusulas.Aseguirumexemplo:
Condicionalnegativopodedificultaraleitura:
// em negrito o condicional negativo

82

Captulo 2: Refatoraes e Melhoria do Cdigo Existente

public void imprime(Documento doc) {


if (!doc.isCarta()) {
prepareA4Paper();
} else {
prepareCartaPaper ();
}
// ...
// mais simples verificar se o doc carta do que se no carta
public void imprime(Documento doc) {
if (doc.isCarta()) {
prepareCartaPaper() ; // se carta, prepara papel carta, OK
} else {
prepareA4Paper();
}
// ...

Outra inverso de condicional usada na leitura de atributos dos objetos. sempre


indicadofazeraassertivadeumaafirmaoemvezdanegao.Aseguirumexemplo:
Asseresnegativas,umpequenomaucheiro:
class Documento {
public boolean ehWord() { return "doc".equals(extension); }
// ...
// situao de uso:
public void imprime(Documento doc) {
if (!doc.ehWord()) {
// lgica necessria apenas quando o documento no do tipo Word
// ...

Umleitorapressadopoderianovero ! epensarquealgicaexecutadaquandoo
documentodoWord.Eviteaasseronegativa,implementeummtodomaisclaroeuseo
comonocdigorefatoradoaseguir:
Faaasseresafirmativasemvezdenegativas:
class Documento {
public boolean ehWord() { return "doc".equals(extension); }
public boolean naoEhWord() { return ! ehWord(); }
// ...
public void imprime(Documento doc) {
if (doc.naoEhWord()) {
// lgica necessria apenas quando o documento no do tipo Word
// ...

83

Captulo 2: Refatoraes e Melhoria do Cdigo Existente

SeodocumentonoWordumtestecondicionalafirmativoemaisintuitivoparaquem
estlendoocdigo(mesmoquesejastumesmodaquiaalgunsmesesouanos).

Introduzirconstante
Arefatorao"introduzirdeconstante"frequentementeusadaparasubstituirnmeros
e strings mgicas. A mecnica de introduzir constante consiste em introduzir um membro
privado(geralmente),estticoefinalnaclasseondeseencontraonmero(oustring)mgicoe
atribuir o valor, aps, o prximo passo substituir todas as ocorrncias deste nmero pela
constante.Aseguirumexemplofcil:
Nmerosmgicos,eagoraMr.M,oquesignificadoc.getStatus()!=2?
// os nmeros mgicos aparecem em negrito
public void imprime(Documento doc) {
if (doc.getStatus() != 2) return;
if (doc.getMargemDireita() > 400) {
doc.setMargemDireita(380);
// ...

NmeroseStringsliteraisdevemsersubstitudosporconstantessemprequepossvel.
Cadalinguagemtemsuasintaxeparaintroduzirconstantes,aseguir,comoexemplo,omesmo
cdigoescritoemJavaerefatorado:
Constantesfazembemparaasade:
private final static int PUBLICADO = 2;
private final static int LIMITE_MARGEM_DIREITA = 400;
private final static int MARGEM_DIREITA_RECOMENDADA = 380;
public void imprime(Documento doc) {
if (doc.getStatus() != PUBLICADO) return;
if (doc.getMargemDireita() > LIMITE_MARGEM_DIREITA) {
doc.setMargemDireita(MARGEM_DIREITA_RECOMENDADA);
}
// ...

Contantestambmtrazemoutrosbenefcioscomopermitiraalteraoemapenasum
lugarcasoosvaloressejamoutros.

IntroduzirObjetoParmetro
Esta refatorao utilizada em mtodos com muitos parmetros e/ou que permita
parmetros nulos. Esta refatorao j foi abordada na seo "cdigo limpo: parmetros"
[[linkar]]masimportanteabordlanovamente.
Amecnicaconsisteemcriarumaclasseemoverosparmetrosdomtodoparaesta
novaclassecomoatributos.Aseguirumexemplosimples:
84

Captulo 2: Refatoraes e Melhoria do Cdigo Existente


Parmetrosemexcessoouanulveisdificultamaleitura:
void imprime(Documento doc, TamanhoPagina tamanhoPagina,
Integer nroCopias, Integer iniciaNaPagina,
Orientacao orientacao) {
// alguns parmetros tem um valor padro para quando forem nulos
int copias = nroCopias == null ? 1 : nroCopias;
int inicio = iniciaNaPagina == null ? 1 : iniciaNaPagina;
Orientacao ori = orientacao == null ? Orientacao.RETRATO : orientacao;
// ...
// situao de uso:
printer.imprime(doc, TamanhoPagina.A4, null, null , null);

Chamadasdemtodosquepassamnuloobscurecemoqueestsendoomitido,ouseja,
parasaberoquefoianuladonecessriocompararcomaassinaturadomtodo.Aseguiruma
versorefatoradadocdigoanterior:
Clarificandocomumobjetoparmetro:
void imprime(Documento doc, OpcoesImpressao opcoes) {
// no mais responsabilidade do mtodo imprime validar as opes
// de impresso, as prprias opes "se validam"
int copias = opcoes.getNumeroCopias();
int inicio = opcoes.getPaginaInicial();
Orientacao ori = opcoes.getOrientacaoPagina();
// ...
class OpcoesImpressao {
TamanhoPagina tamanhoPagina;
Integer nroCopias;
Integer iniciaNaPagina;
Orientacao orientacao
int getNumeroCopias() {
return nroCopias == null ? 1 : nroCopias;
}
// ...
// situao de uso:
OpcoesImpressao opcoes = new OpcoesImpressao() {{
orientacao = Orientacao.Retrato;
tamanhoPagina = TamanhoPagina.LETTER;
}};
printer.imprime(doc, opcoes);

Prestebematenotambmlgicaquefoimovidaparaanovaclasse OpcoesImpressao
quedefinequaisopesteroum default. Estetipoderefinamentonoprojetotambmtemo
propsitodedefinirmaisprecisamenteasresponsabilidadesdecadaclasse.
Algumas linguagens suportam a definio de um valor default para parmetros na
assinaturadosmtodos.AseguirumexemplodesterecursonoRuby:

85

Captulo 2: Refatoraes e Melhoria do Cdigo Existente


NoRubyevaloresdefault,umdesignmaislimpo:
def imprime(doc, tamanho_pagina, nro_copias = 1,
pagina_inicial = 1, orientacao = Orientacao::RETRATO) {
...
# situao de uso:
printer.imprime(doc)
# os parmetros omitidos receberiam seu valor default

Antesquealgumsemagoe,outraslinguagenscontamcomessafuncionalidadecomo:
PHP,C#(apartirdo4.0),ActionScript,entreoutras.

Palavrasfinaissobrerefatoraes
Esperoqueapsestecaptulotenhasentendidoqueumbomsoftwarenoaqueleque
funciona,masaquelequefuncionaebemescrito.Todoestecaptulofoidedicadoaqualidade
internadosoftware,ouseja,apartequeaequipetemacesso,ocdigo.
Essasmesmasdicasdequalidadesoabordadasnocursotcnicoerecentementeum
alunomeu,noseudiscursodeformaturadisse:agoraatminhameconseguelermeuscdigos.
essaaintenocomasdevidaspropores:)
Paraaprofundarsemaisemrefatoraosugiroa leituradocontedodestelink onde
constaumcatlogoderefatoraesbemcompleto:
http://martinfowler.com/refactoring/

Nestelinktemumarefernciamuitoboasobresmellsearefatoraoapropriada:
http://wiki.java.net/bin/view/People/SmellsToRefactorings

A seo de cdigo limpo foi inspirada no livro do tioBob [MARTIN]. Existem vrios
artigosdeledisponveisnaweb,nesteendereo:
http://butunclebob.com/ArticleS.UncleBob,eneste:http://blog.objectmentor.com/

Comosugesto,altamenterecomendvelqueleiampelomenosumdoslivroslistadosa
seguirnabibliografia.

Bibliografia
[FOWLER] FOWLER, Martin. Refatorao: Aperfeioando o Projeto de Cdigo Existente.
1a. ed. Editora: Bookman, 2004.
[MARTIN] MARTIN, Robert. Cdigo Limpo: Habilidades Prticas do Agile Software. 1a. ed.
Editora: Alta Books, 2009.
[BLOCH] BLOCH, Joshua. Java Efetivo. 2a. ed. Editora: Alta Books, 2008.
[HUNT & TOMAS] HUNT, Andrew. THOMAS, David. O programador pragmtico: de
aprendiz a mestre. 1a.ed. Bookman, 2010.

86

Parte 2: Projeto de Objetos, Princpios e Padres

PARTE2:PROJETODEOBJETOS,
PRINCPIOSEPADRES
Objeto:
Eento,Napoleo,oquefoiquevocinventoudessavez?
Euinventeiumobjetoquepermitequevocvejaatravsdas
paredes.
mesmo?perguntaomdico,ctico.Ecomosechama
esseobjeto?
Janela!
(Curtodilogoentreummdicopsiquiatraeseupaciente)

Segundo meu entendimento, o que diferencia um desenvolvedor de software de um


programadoramador37,suahabilidadeemprojetar,anteverumaestruturaedirecionlapara
obteramelhorflexibilidadeparaalteraesfuturas.Umdesenvolvedordesoftwarevalmdo
cdigo.Nestapartedolivroseroabordadosalgumastcnicaseprincpiosdemodelagemde
objetosassimcomoosfamosospadresdeprojeto(designpatternscomosoconhecidos).

37

Ouprogramadormacacocomoumqueridoamigomeucostumachamar:
http://pt.wikipedia.org/wiki/Code_monkey

87

Captulo 3 Projeto e Modelagem de Objetos

Captulo3ProjetoeModelagemde
Objetos
Planejamento:
Napreparao paraabatalha,sempreacheiqueosplanos
eraminteismasqueoplanejamentoeraindispensvel
DwightD.Eisenhower

Neste captulo veremos que programar e projetar so duas coisas bem diferentes. A
atividadedeimplementarumafuncionalidadeespecfica,umaparte,comoacriptografiadeuma
senha, no pode ser comparada com a deciso de como todas essas pequenas partes se
integraroedelas,juntas,teremosumsoftware.Claroqueataquitujdevesterumanoo
slidadoquesoobjetos,eestacompreensodecomoprogramar,implementar,criarclasses,
instncias, etc, no to til sem antes definir quais classes tero de ser criadas e o que,
exatamente,cadaclassevaifazer.
JtinhaditoqueanossafaixadeestudoestemumasubdisciplinadeEngenhariade
Software:oProjetoOrientadoaObjetos.Oprojeto,ou design emingls, sucedeumaanlise
orientada a objetos, a qual darei apenas uma pequena palavra neste captulo, por que ser
abordadanadisciplinadeESI,nestecurso.
Programadores iniciantes, e aquelesquevem de linguagensprocedimentais, tem uma
certadificuldadeementender,emoutraspalavras,pensaremobjetos,isto,quaisclassesso
necessriaseoquecadaclassedevefazer.Nestesentido,existemvriosprincpioseheursticas
quebuscamorientardecisesparaatingirumprojetocoeso,flexvel,reutilizvel.

88

Captulo 3 Projeto e Modelagem de Objetos

UmapalavrasobreOOAD
Anlise e projeto orientado a objetos uma rea com bastante literatura e aplicao
prtica. Ambos, anlise e projeto, podem ser melhor definidos, como diz Craig [LARMAN]:
AnlisedeObjetoseProjetodeObjetos.fortementerecomendadaaleituradolivrodoCraig
paraquemseinteressanarelaoentreanlise(principalmente)eprojetoorientadoaobjetos.
Nafasedeanlise,buscaseidentificar,emmeioosrequisitos,osobjetosquefaroparte
dosistema,enafasedeprojeto(design,projetar,lembra?)buscaseplanejarcomoestesobjetos
iro,digamos,colaborar,interagir,paraqueorequisitosejasatisfeito.CraigLarmanemseulivro
[LARMAN], resume anlise e projeto a: "fazer a coisa certa" e "fazer certo a coisa",
respectivamente.Nosotarefassimples(sefossemnohaveriamlivrosparaexpliclas),mas
nestetpicobuscodarumamelhornoodestasfasesparaposteriormentemergulharmosnos
princpios.
AnalisareProjetarpodeserentendidocomoFazeracoisacertaeFazercertoacoisa!

AnlisedeSistemasOrientadosaObjetos
Em poucas palavras, fazer uma anlise implica em, meio aos requisitos do software,
extrairosconceitos.Normalmenteasadadeumaanliseorientadaaobjetosumdiagrama
conceitualquerepresentao modelo conceitual de domnio.Omodeloconceitualdedomnio
exibeosprincipaisconceitosmodeladoscomoobjetoseseusrelacionamentosmaisbsicos,bem
semelhanteaummodeloconceitualusadonoprojetodebasesdedados.Vouilustrarmelhor
comumexemplogeralmenteconhecidopelamaioria,umavideolocadora.
Pensoquequalquerumqueestejalendoestelivrojtenhalocadoumfilme(edevolvido,
espero),econhece,mesmosemmuitosdetalhes,ofuncionamentobsicodeumsistemadeste
tipo.
Quaissoosrequisitosdeumsistemaparalocadora?Dalocaoadevoluo,oque
acontece?Quaissoospassos?Paralocarumfilme,enquantocliente,eupassoosfilmesparao
atendente,oatendenteperguntameucdigo,eudigoquenosei,oatendenteperguntameu
nome,localizameucadastroeregistraalocaodosfilmescomumadatadeentregadefinida.
maisoumenospora,no?
Umaheursticaparaaatividadedeanliseorientadaaobjetos:procureossubstantivos.
A partir desta heurstica podemos identificar conceitos de domnio como: Cliente, Filme,
Locao,entreoutros.Ummodeloconceitualdedomnio,queestincompletoeincorreto,mas
queexpressaosobjetoslocalizadosinicialmenteestaseguir:

89

Captulo 3 Projeto e Modelagem de Objetos

Modelodedomnio:umarepresentaoconceitualdosobjetosenvolvidosnosistema

Comoummodeloconceitualelepode,evai,mudar. Mesmojnafasedeprojeto
outros conceitos, antesimplcitos, so identificados e introduzidos. O modelo conceitual no
precisa,nemdeve,serexato,abrangenteecorreto.Omodeloanterior,porexemplo,erraem
locarofilme,poisnaprticaofilmealgoabstrato,oquelocamosoDVDouexemplar,a
locaodamdiafsica.Conseguesimaginarestaalteraonomodelodedomnio?
tambmnafasedeanlisequesoredigidososcasosdeuso,isto,independenteseo
softwareounoorientadoaobjetos.Oscasosdeusosoaconsolidaodosrequisitosem
especificaes,ouseja,elesformalizamoquedeveserconstrudo.
afasedeanlisepodeserentendidapordoispontosdevistadistintos:opontodevistadequetudodeve
sermodelado,todososdetalhesdevemseresclarecidosantesdeescreverqualquercdigo;eopontodevistade
queafasedeanlisedevelevantarapenasosprincipaisconceitos,aessnciadoquesedevedesenvolver,sem
confiareesclarecertodosdetalhes,assumindoqueosistemavaimudarcomotempo.Essesdoispontosdevista
soconhecidoscomotradicionalegil(agile)

[[introduzir exemplo de caso de uso]]

ProjetodeSistemasOrientadosaObjetos
O projeto envolve a definio dos objetos de fato e como eles devem interagir para
satisfazerasfuncionalidades.Nestafase maiscomumautilizaodediagramasdeclasses,
objetosesequncia.Estesdiagramassousadospararepresentaraimplementao,ouseja,
ummodelofsico.Existemvriaspreocupaesnestemomento,masumaemespecialmerece
destaque,adedarresponsabilidadesaosobjetos.
AprincipalresponsabilidadedosProjetistasdeSistemasOrientadosaObjetosdedar
responsabilidadesaosobjetos

Adistribuioeatribuioadequadaderesponsabilidadesentreosobjetosgeralmente
implicaemumbomprojetodesoftware.Digogeralmente,porqueaqualidadedoprojeto
melhoravaliadaquandonecessrioincluirnovasfuncionalidadesoualterarasjexistentes,
poisumsoftwarebemprojetadoflexvelenoresistenteasmudanas.

90

Captulo 3 Projeto e Modelagem de Objetos

Ummodomaissimplesdepensaremanliseeprojeto,entenderaanlisecomoafase
dedefiniodoquedeveserfeito,eentenderoprojetocomoafasededefiniodecomoser
feito.
anlise==oquprojeto==como

Fazer um projeto adequado no simples, exigeexperincia, masfelizmente existem


algunsprincpiosquesebementendidos(eaplicados)ajudamacriarumprojetorazoavelmente
bom.Projetosmaissofisticadosutilizampadresdeprojeto,quesugeremumaimplementao
dadoumproblemaeumcontexto.Obomdesenvolvedorentende,almdeOOP,tambmOOD,
pelomenososuficienteparatomardecisesacercadadecomposiodosoftwareemobjetose
estabelecerarelaoentreeles.

Modelagemeimplementaododomnio
Apartirdaanlise,comojfoifalado,soidentificadososobjetosquefazempartedo
negcio,oumelhor,dodomniodoaplicativo.Estesobjetossoconceituaisenorepresentam
exatamenteasclassesqueosistemater,emboraboapartevenhaasetornarumaclasse.Por
exemplo,umsistemaparacontroleeestoquedecomputadorespodeteroobjetoComputador.O
objeto Computador pode ser considerado uma entidade do aplicativo, aparece no modelo
conceitualdedomnioeserprovavelmenteuma classeComputadornonossosistema.Uma
representaoconceitualdeComputadorseriaapenasumretngulonomeadocomosprincipais
atributos,comonaimagemaseguir:

Modeloconceitualdecomputador

Aps uma observao, na fase de projeto, podemos decidir transformar os atributo


memriaeprocessadoremclasses.Essasclassesnoapareciamantesnomodeloconceitual,mas
podemserimplementadasquantasnovasclassesforemnecessriasparacriarumprojetobom,
reaproveitvel,coeso,preciso.

91

Captulo 3 Projeto e Modelagem de Objetos

Modelorefinado

Tipicamente, essas classes resultantesda anliseeprojeto, sopersistentes. A tcnica


maiscomumusarumbancodedadosrelacional(SGBD).Baseadonoexemploteramosde
persistirasinstnciasdaclasseComputador,MemoriaeProcessadoremtabelashomnimasno
bancodedados,masnemsemprenecessrioterumatabelaporclasse,algumasclassesso
persistidascomocamposeoutraspodemsertransientes(nosopersistidas).

Tiposprimitivosecomplexos
Percebese a resistncia de alguns programadores a criar classes. Seja por medo,
insegurana,teimosiaouseil.Tipicamente,estesprogramadores,implementamasestruturas
dedadosusandotiposprimitivoseosalgoritmosusandoblocoslongosdecdigoaglomerado.
Tiposprimitivos,sparalembrar,soostiposbsicos,como:char,int,byte,short,long,
double,float,boolean,etc(Stringnoprimitivomastobsicoquanto).Atparecequeestou
dizendoobviomasopontoqueprogramareprojetarsistemasorientadosaobjetosimplica
emconstruirestruturasdedadosbaseadasemobjetos.Estetipodeatitude,derepresentardados
sempre usando primitivos, um code smell conhecido como Obsesso Primitiva, j visto no
captuloanterior.

Entidades
VoltandoaOOPtemosquelembrarqueobjeto,defato,umaentidadequetemalgum
estado(atributos),comportamento(mtodos)eidentidade.ConsidereumobjetoTelevisao,ele
retm um estado, como ligada, desligada, canal atual, volume atual, etc, demonstra um
comportamentoquealteraesseestado,comoligar,desligar,aumentarvolume,baixarvolume,
selecionarcanal,etc,epossuiumaoumaiscaractersticasqueadistinguedeoutrastelevises,
comoonmerodesrie,cdigo,etc,istoaidentidade.

92

Captulo 3 Projeto e Modelagem de Objetos

Aidentidadedevepermitiracomparaodeduasinstnciasdeobjetosdamesmaclasse.
NoJavaistofeitopelomtodoequalse,ateno,nopelooperador==.Ooperador==,nocaso
detiposcomplexos,osobjetos,comparaseasvariveisreferenciamomesmoobjeto.Aseguirum
exemplodestecomportamento:
Identidade,umaprerrogativaspararesolveraigualdade:
class Cliente {
private Integer id;
private String

cpf;

private String

nome;

@Override

// O CPF determina a identidade

public boolean equals(Object outroObjeto) {


if (outroObjeto == null) return false ;
if (getClass() != outroObjeto.getClass()) return false;
final Cliente outroCliente = (Cliente) outroObjeto;
if (this.cpf == null && outraCliente.cpf != null) {
return false;
} else if (this .cpf != null) {
return this.cpf.equals(outroCliente.cpf);
}
return true ;
}
}
// situao de uso:
Cliente c1 = new Cliente();
c1.setCpf("66644477799");
Cliente c2 = new Cliente();
c2.setCpf("66644477799");
// imprime false, cada varivel referencia uma instncia diferente:
System.out.println(c1 == c2);
// imprime true, embora instncias diferentes considerado o mesmo objeto
System.out.println(c1.equals(c2));

Existem algumas consideraes para implementar o mtodo equals, ele deve ser
reflexivo,simtricoetransitivo,almdeoutraspropriedadesimportantesquepodes(deves)ler
aqui:
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Object.html#equals(java.lang.Object)

AcaractersticaessencialdeumaEntidadequeelatemidentidade

Toda Entidadepertencente ao domniodeve cumprir um papelbem definido e claro.


Entidadespodemounoserpersistentes,isto,seremsalvasemumafontededados(bancopor
exemplo)paraposteriorrecuperao.Entidadesdevemterumcontratodeestadoconsistente,
por exemplo, uma instncia de Cliente deve ter no mnimo nome e cpf para ser considerada
consistentevlido.

93

Captulo 3 Projeto e Modelagem de Objetos

Conformealinguagemou framework,asEntidadestambmpodemterdehonraruma
especificaodemodelagem.NoJava,porexemplo,asEntidadesseguemopadroJavaBean
comatributosprivadosemtodosacessores(gettersesetters).NoRails(frameworkparaRuby)as
Entidades devem estender uma classe base para modelos, a classe ActiveRecord::Base. A
modelagemdeEntidades,noJava,vistoemModelandoEntidades.

ObjetosPersistentes
Aimplementao,construodesoftwarecorporativoquasesempreincluimecanismos
depersistnciausandobasesdedadosrelacionais,comooMySQL,Oracle,PostgreSQL,etc.A
persistnciadedadosnecessriaparareconstruirmosoestadodosobjetos,eeisoproblema:
nsusamosclasses,oSGBDtabelas,nsusamosobjetos,oSGBDregistros,nsusamosatributos,
oSGBDcampos.Adiferenaderepresentaodosmesmosdadosentrealinguagemorientadaa
objetoseobancodedadosrelacionalchamadade ObjectRelationalImpedanceMismatch38,
algocomoDesacordodeImpednciaObjetoRelacional.
Tipicamente, nestes sistemas, partimos de duas modelagens que representam as
estruturas de dados, o Diagrama EntidadeRelacionamento e o Diagrama de Classes;
respectivamenteumparaabasededados,representandoastabelas,eoutroparaalinguagem,
representandoclasses.
Em primeiro lugar, no fato que tabela == classe. Existem classes que no so
persistentes,ouseja,quenotemtabelaoucampoparaarmazenla;Eexistemtabelasqueno
temclasses.Entretanto,boapartedomodelodedomniosetornaclassescomsuasrespectivas
tabelas.
Nestesentido,construirasclassesquerepresentaminformaespersistentesimplicaem
estarcientequehumabasededadosportrsdestasclasseseterdelidarcomabagagem;
comobagagemquerodizer:chaves primrias(primarykeys),chaves candidatas,camposno
anulveis, constraints de unicidade (unique indexes), chaves estrangeiras (foreign keys) e
relacionamentos, entre outros. Em outras palavras, classes que representam informaes
persistentes,entidades,endossamoSGBD.Porexemplo,senoSGBDhumatabelaclientescom
umcampononulo(notnull)nome,teremosumaclasseClientecomumatributonome,mas
comodiremosnaclassequenomenoanulvel?
Vamosusarumexemplopequenoparailustraraimplementaodeentidadeseobjetos
nopersistentes.Considereumaplicativoparaatenderumabibliotecaeaprimeiraseoque
iremosnospreocuparcomocatlogodelivros.Claro,umabibliotecaeocontroledeacervo
algobemcomplexo,masvamospartirdepressupostossimplescompoucasentidadeseclasses,
modelandoapenaslivros,autoreseeditoras.Umlivropodeounotereditora,masdeveterpelo
menos um autor e no mximo 8. O relacionamento e cardinalidade pode ser conferido na
ilustraoaseguir:

38

http://en.wikipedia.org/wiki/Objectrelational_impedance_mismatch

94

Captulo 3 Projeto e Modelagem de Objetos

PartesimplificadadodiagramaERparaumsistemadecontroledeacervo

Comopodesvernailustraoosistemadebasesdedadostrabalhacomoconceitode
identidadeusandochavesprimrias(PK)erelacionamentosusandochavesestrangeiras(FK).
Camposobrigatriostemaconstraint(restrio)notnull(noanulvel).Entretanto,paraimpor
arestriodecardinalidade,porexemplo,olivroternomximo8autores,teramosquerealizar
umaimplementaodecdigonoSGBD,comtriggerseprocedures.Sendoaquantidademxima
deautoresumaregradenegcio,implementlanoSGBDlevaosistemaadependerdobanco.
Deixaralgicadenegcio(domnio)nobancoumadiscussolongaechata,algunssoafavor
(DBAs39porexemplo)eoutroscontra.Implementaralgicanalinguagemdeprogramaoou
com storedprocedures40 nobancoumadecisoarquitetural(difcildeserdesfeita,lembra?),
masnopretendoaquipesarosprsecontras.NestelivrotrabalhoscomOOD,ecomotal,
modelamosestruturasdedadoselgicanosobjetos(classes),ouseja,nadadestoredprocedures.
UmdiagramadeclassesequivalenteaestediagramaERpodeservistonailustraoaseguir:

diagramadeclassesrepresentandoomodelodedomniofsico

Atenoaodetalhes:

39

ApresenadaslinhasconectandoasclassesnodiagramadeixaclaroqueLivrotem
umaeditoraeumalistadeautores,entonoserianecessrioapresentarnoLivroos
camposeditora:Editora eautores:List<Autor>.

DatabaseAdministrator:administradordebasesdedados:

http://pt.wikipedia.org/wiki/Administrador_de_banco_de_dados
40

ProcedimentoArmazenado:ummeiodeprogramarnobancocomSQLeumalinguagemespecfica:
http://pt.wikipedia.org/wiki/Procedimento_armazenado
95

Captulo 3 Projeto e Modelagem de Objetos

No SGBD representamoscolees, os nomes das tabelas geralmente so no plural


(clientes, produtos, vendas),masasclassesrepresentammoldesparaobjetosecada
uma no singular (Cliente, Produto, Venda). As classes so sempre escritas no
singular:atabelaeditorasrepresentadapelaclasseEditora.

NohumaclasseLivroAutorassimcomoexisteatabela livros_autores.OSGBDfaza
relao de muitosparamuitos usando tabelas associativas. Nas classes, basta elas
declararem uma coleo de objetos, no exemplo, um List<Autor>. Neste projeto, o
relacionamentounidirecional,ouseja,olivrotemumalistadeautores,masautor
notemumalistadelivros,importanteficarclaroqueautorpoderiaterumalista
delivrosoquetornariaorelacionamentobidirecional(emaiscomplexodemanter).

Osatributosnoprecisamnecessariamenteteromesmonomedoscamposdatabela,
porexemplo,ocampoid_autordatabelalivrosrepresentadonaclasseLivro como
id.

ModelandoEntidadesdoDomnio
Como exemplo vamos implementar a classe Editora em Java. Primeiro, somente os
atributos, depois as regras e mais tarde a carga comum de todos os objetos de domnio. O
modelosegueopadroJavaBean,ouseja,atributosprivadoscomgettersesetters,vejaaseguir:
ClasseEditoramodeladacomoumaEntidade:
// importante separar os objetos do domnio em um pacote
package br.edu.ifrs.biblionline.modelo;
public class Editora {
// construtor pblico e sem argumentos
public Editora() {

// atributos privados
private Integer id;
private String

nome;

private String

endereco;

// getters e setters
public void setId(Integer id) { this.id = id; }
public Integer getId() { return this .id; }
public void setNome(String nome) { this.nome = nome; }
public String getNome() { return this .nome; }
public void setEndereco(String endereco) { this.endereco = endereco; }
public String getEndereco() { return this .endereco; }
// faltam os mtodos hashCode, equals e toString

96

Captulo 3 Projeto e Modelagem de Objetos

asIDEsEclipseeNetBeanspossuemgeradoresdegettersesetters;noNetBeansdigiteosatributosprivados,
pressioneALT+INSERTeselecioneaquelesquedesejasexpor.

Esta implementao inicial representa bem a nossa estrutura de dados para a


representao de editoras, contudo as regras do domnio no foram implementadas, por
exemplo,todaeditoradeveterumnome,obrigatoriamente.Essaregradeveservalidadaantes
de persistir (salvar o objeto no banco) caso contrrio causar uma exceo e uma viagem
desnecessria at obanco, afinalpoderamos disparar a inserosomente se a Editora fosse
vlida.Ocdigoaseguircausariaumaexceo:
Editoradeveterumnome:
// o nome da editora no informado
Editora ed = new Editora();
ed.setId(155545);
ed.setEndereco("Rua tal, 233 - Porto Alegre, RS");
EditoraDAO dao = new EditoraDAO(); // classe de acesso ao meio persistente
dao.salva(ed); // como salvar uma editora sem nome?

Osobjetosdevemserconsistentes,lembra?necessriousarumatcnicadevalidaoe
controlaravidadosobjetos.Notpicoaseguirserdiscutidaavalidaocommaisdetalhes.

EstratgiasdeValidao
Existemduasabordagensparaasseguraravalidadedomodelo:outumantmomodelo
semprevlido,desdeocomeo,ouvalidaantesdepersistilo.Aprimeiraabordagem,demanter
oobjetovlidosempre,desdeainstanciao,exemplificadaaseguir:
ObjetosinstanciadosdaclasseEditorasosemprevlidos:
class Editora {
// para tornar o nome obrigatrio, crie um construtor
public Editora(String nome) {
this .nome = nome;
}
// ...

Criar um construtor a forma mais simples de impor a obrigatoriedade, mas nada


impedequealguminstancieumaeditoracomumnomenulo: new Editora(null); Istoainda
causariaproblemas,devemospensarsempreemtodasaspossibilidadesdequebra,nestecaso
temosdeverificarseonomenuloouno.Ocdigoaseguirestmelhor:
VerificaodeparmetrosnaclasseEditora:
class Editora {
public Editora(String nome) {
if (nome == null) {
throw new IllegalArgumentException("O Nome Obrigatrio");
}
this .nome = nome;

97

Captulo 3 Projeto e Modelagem de Objetos

}
// ...

Entretanto,aindapossoinstanciarumaeditoracomumnomeedepoissetar41umnome
nulo: editora.setNome(null); Avalidaodeveserconsolidadaemumnicolugarequalquer
alteraonoatributodevepassarporela.Vejaaclasseeditoraalteradaaseguir:
Verificaoonipresente:
class Editora {
public Editora(String nome) {
this .setNome(nome); // delega para o mtodo set
}
public final void setNome(String nome) {
if (nome == null) {
throw new IllegalArgumentException("O Nome Obrigatrio");
}
this .nome = nome;
// ...

Essescdigosilustramumavalidaoantecipada.NopossvelinstanciarumaEditora
sem dar um nome a ela. Os cdigos new Editora(), new Editora(null) e editora.setNome(null)
falham.
Asegundaabordagemtemoobjetivodeverificaraintegridadedosobjetosapenasantes
de persistilos. umaformade validao postergada,atrasada, quepodefuncionarbemem
muitoscenrios.Existemvriosmeios,masaquivaiumexemplo(noumareceita):
ClasseEditoracomavalidaopostergada:
public class Editora {
public boolean ehValida() {
try { this .valida(); }
catch (ValidacaoException ex) { return false; }
return true ;
}
public void valida() {
if (nome == null) {
throw new ValidacaoException("O Nome Obrigatrio");
}
}
// ...

importantedizerqueusandoessecdigoavalidadedoobjetoterdeserverificada
manualmente, sendo que antes de persistir seja executado if (editora.ehValida()) ou
editora.valida().
bem discutvel qual abordagem usar, validar antes ou depois. Eu, particularmente,
pensoquevalidardepoisamelhoroponamaioriadoscasos,comoumargumentoconsidere
41

Areadeinformticaest"tapada"deanglicismos:settar,zipar,upar,etc:
http://pt.wikipedia.org/wiki/Anglicismo
98

Captulo 3 Projeto e Modelagem de Objetos

queeutenhaumaclassecomdezatributosobrigatrios,entoteriadecriarumconstrutorcom
dezparmetros,certo?Issoprejudicaalegibilidadeeclarezacomojfoicomentadonaseo
CdigoLimpo.

Mtodoscomuns
fortementerecomendadoqueasclassesquerepresentamodomnioimplementam,ou
melhor,sobrescrevamalgunsmtodosimportantes: toString, equals, hashcode e compareTo.Cada
umtemumpropsitoparticular,podemoscomearcomotoString.OmtodotoStringconverte,
representaoobjeto,ainstncia,comoumaString.Estemtodoinvocadoquandofazemosuma
sada(System.out)deumobjetoparaoconsole,mastambmusadoemaplicaesWeb.Vejaa
seguircomoficariaaEditorasemsobrescreveromtodotoString:
ClasseEditorasemsobrescrevertoString:
Editora ed = new Editora();
ed.setId(22342);
ed.setNome("Bookman");
ed.setEndereco("Av Jernimo de Ornelas, 370, Santana - Porto Alegre RS");
System.out.println(ed); // imprime br.edu.ifrs.modelo.Editora@1e5e2c3

Otextobr.edu.ifrs.modelo.Editora@1e5e2c3asadadomtodotoStringherdadodaclasse
42
,oarrobaeoendereodaposiona
memria.VamossobrescreveromtodotoStringeimplementaralgomaistil:
Object,queexibeonomedaclassetotalmentequalificado

SempresobrescrevaomtodotoString:
class Editora {
@Override
public String toString() {
return "Editora id:" + id + ", nome:" + nome;
}
// ...
// situao de uso:
Editora ed = new Editora();
ed.setId(22342);
ed.setNome("Bookman");
ed.setEndereco("Av Jernimo de Ornelas, 370, Santana - Porto Alegre RS");
System.out.println(ed); // imprime Editora id:22342, nome:Bookman

PodesaproveitarogeradordecdigodoIDEparasobrescreverotoString.NoNetBeanspressione ALT
cliqueemtoStringeselecioneosatributosquefaropartedasada.

+ INSERT

SempresobrescrevaomtodotoString

Tambmdevesersobrescritoomtodoutilizadoparatestesdeigualdade,o equals.A
primeiracoisaapensarantesdesobrescreverequalsqualouquaisatributossorelevantespara
42

FullyQualifiedName o nome de uma classe, tabela, arquivo, etc, indicando todo o caminho para
encontr-lo
99

Captulo 3 Projeto e Modelagem de Objetos

acomparao.Quandoaclasseumaentidade,essaescolhaficaentreachaveprimria(umId)
eachavecandidata(campo unique).NocasodaclasseEditoraficariaentreidenome,ouseja,
duas instncias de editora com o id 5, seriam iguais mesmo se cada uma tivesse um nome
diferente? Duas instncias de editora com o nome Bookman seriam iguais mesmo com id
diferente? Bem, vamos partir do pressuposto que o nome (chave candidata) usado como
atributodeigualdade.Antesvejaoexemplodoqueacontecequandoomtodo equals no
sobrescrito:
Semequals,nohigualdadepelocontedo,apenasseforemamesmainstncia:
Editora ed1 = new Editora();
ed1.setId(22342);
ed1.setNome("Bookman");
ed1.setEndereco("Av Jernimo de Ornelas, 370, Santana - Porto Alegre RS");
Editora ed2 = new Editora();
ed2.setId(22342);
ed2.setNome("Bookman");
ed2.setEndereco("Av Jernimo de Ornelas, 370, Santana - Porto Alegre RS");
System.out.println(ed1.equals(ed2)); // imprime false

Anosobrescritadomtodoequalstambmimplicaemcomportamentoinadequadoem
colees do tipo conjunto (set) permitindo objetos duplicados 43 (o que no deveria), veja
exemplo:
Semequals,conjuntoscomelementosrepetidos:
Editora ed1 = new Editora();
ed1.setId(22342);
ed1.setNome("Bookman");
ed1.setEndereco("Av Jernimo de Ornelas, 370, Santana - Porto Alegre RS");
Editora ed2 = new Editora();
ed2.setId(22342);
ed2.setNome("Bookman");
ed2.setEndereco("Av Jernimo de Ornelas, 370, Santana - Porto Alegre RS");
Set<Editora> conjunto = new HashSet<Editora>();
conjunto.add(ed1);
conjunto.add(ed2);
System.out.println(conjunto);
// imprime incorretamente duas editoras iguais:
// {"Editora id:22342, nome:Bookman", "Editora id:22342, nome:Bookman"}

Ento, vamos sobrescrever o equals. Existe um contrato para o equals, mas no vou
abordlopoisjdeviatersidovistoemOOP.Abaixosegueaimplementaopara Editora,no
umareceita,umexemplo:

43

AindanosabecomolidarcomconjuntosnoJava?Ohhh,leiaistoagora:
http://docs.oracle.com/javase/tutorial/collections/interfaces/set.html

100

Captulo 3 Projeto e Modelagem de Objetos


Sempresobrescrevaomtodoequals:
public class Editora {
@Override
public boolean equals(Object outroObjeto) {
if (outroObjeto == null) return false ;
if (getClass() != outroObjeto.getClass()) return false;
final Editora outraEditora = (Editora) outroObjeto;
if (this.nome == null && outraEditora.nome != null) {
return false;
} else if (this .nome != null) {
return this.nome.equals(outraEditora.nome);
}
return true ;
}
@Override
public int hashCode() {
int hash = 7;
hash = 67 * hash + (this .nome != null ? this .nome.hashCode() : 0);
return hash;
}
}

PodesusarogeradordecdigodoIDEparasobrescreveroequals.Namaioriadoscasoselebomosuficiente.
NoNetBeanspressioneALT + INSERT,cliqueemequalseselecioneosatributosquefaropartedacomparao.

Fiqueatento,obrigatrioimplementaro hashCodesemprequeimplementarequals.Todo
objetoconsideradoigualdeveteromesmohashCode,entouseosmesmosatributostantopara
equalsquantoparahashCode.
sempresobrescrevaomtodoequalsehashCode

O prximo mtodo a ser implementado o compareTo. O mtodo compareTo deve ser


implementadoportodasasclassesqueimplementamainterface Comparable<T>.Eletilquando
oobjetoinseridoemumacoleoclassificada,paradefiniraordemutilizada. Considerea
ordemalfabticapornomeparaaseguintecoleo:
Semcomparable,classificaoimpossvel:
Editora ed1 = new Editora();
ed1.setId(22342); ed1.setNome("Bookman");
ed1.setEndereco("Av Jernimo de Ornelas, 370 - Porto Alegre RS");
Editora ed2 = new Editora();
ed2.setId(9233); ed2.setNome("Novatec");
ed2.setEndereco("Rua Lus Antnio dos Santos, 110 - So Paulo SP");
Editora ed3 = new Editora();
ed3.setId(4691); ed3.setNome("AltaBooks");
ed3.setEndereco("Rua Viva Cludio, 291 - Rio e Janeiro RS");

101

Captulo 3 Projeto e Modelagem de Objetos

List<Editora> editoras = new ArrayList<Editora>();


editoras.add(ed1); editoras.add(ed2); editoras.add(ed3);
Collections.sort(editoras); // essa linha no compilada (Falha)

Ainstruo sort nocompila.Omtodoesperaumainstnciade Comparable,ouseja,a


listadeeditorasspodeserclassificadaseaclasseEditoraimplementarComparable
OmtodocompareTotemumcontratosimples:dadooobjetoemquesto,deveretornar0
seforigual,positivo(1)seformaiorenegativo(1)seformenordooobjetorecebidocomo
argumento.maissimplesentendercomcdigo,segueumexemplo:
Comcomparable,classificaodisponvel:
class Editora implements Comparable<Editora> {
public int compareTo(Editora outraEditora) {
if (this.nome == null && outraEditora.nome == null) return 0;
return this .nome.compareTo(outraEditora.nome);
}
// ...
// situao de uso:
Editora ed1 = new Editora();
ed1.setId(22342); ed1.setNome("Bookman");
ed1.setEndereco("Av Jernimo de Ornelas, 370 - Porto Alegre RS");
Editora ed2 = new Editora();
ed2.setId(9233); ed2.setNome("Novatec");
ed2.setEndereco("Rua Lus Antnio dos Santos, 110 - So Paulo SP");
Editora ed3 = new Editora();
ed3.setId(4691); ed3.setNome("AltaBooks");
ed3.setEndereco("Rua Viva Cludio, 291 - Rio e Janeiro RS");
List<Editora> editoras = new ArrayList<Editora>();
editoras.add(ed1); editoras.add(ed2); editoras.add(ed3);
Collections.sort(editoras); // OK, editora implementa Comparable
System.out.println(editoras);
/* imprime:
[Editora id:4691, nome:AltaBooks, Editora id:22342, nome:Bookman, Editora id:9233, nome:Novatec]
*/

umadasmaneirasmaisprticasdelegarocompareToaoatributo,comofoinocasodaclasseEditoraque
delegaocompareToaonome,ouseja,aclassificaoserpelaordemalfabticadonome.
ConsideresempreimplementarComparableeomtodocompareTonassuasclassesdedomnio.

AssociaeseAgregaescomColeeseContainers
102

Captulo 3 Projeto e Modelagem de Objetos

Objetosrelacionamsecomoutrosobjetos,existemassociaesentreobjetos.Umobjeto
LivrotemumobjetoEditora,eacontrapartida?Digo,EditoratemLivros.Assimcomonasbases
dedadosexistemassociaesde1para1,1paramuitosemuitosparamuitosentreobjetos.A
implementaodaassociaodeumobjetorelacionadoa muitosgeralmenteimplementada
comalgumtipodecoleo,entreasmaisusadas:lista(List),conjunto(Set)emapa(Map).
Comoexemplo,considereocasodeLivroeAutores,ondealgicadedomnioregraque
livropodeterde1at8autores.Aimplementaomaiscomumesimplificada(epropensaa
falhas)estaseguir:
Associaodeumparamuitosentreobjetos:
class Livro implements Comparable<Livro> {
private List<Autor> autores;
public List<Autor> getAutores() { return autores; }
public void setAutores(List<Autor> autores) { this.autores = autores; }
// ...

Este tipo de implementao propensa a falhas e no cumpre as regras de negcio.


Contudo,porseramaissimplesdeimplementaramaisusadaporprogramadoresiniciantes.A
seguiralgunscasosdefalha:
Problemasdeexporcolees:
// este cdigo causa um NullPointerException (NPE)
livro.getAutores().add(autor);
// o mtodo "getAutores" retorna nulo causando NPE na chamada de "add"
// este funciona mas no cumpre a regra de 1 at 8 autores
List<Autor> autores = new ArrayList<Autor>();
livro.setAutores(autores);
// seta uma lista vazia de autores, inadequado segundo a regra
// adiciona mais autores do que o permitido:
livro.getAutores().add(a1);
livro.getAutores().add(a2);
// ...
livro.getAutores().add(a10); // possvel adicionar mais de 10 autores

Comojfoidito,estetipode implementaobemcomumefcil,mastemvrios
aspectosnegativos.Eudiriaqueoprincipalaquebradeencapsulamento44,dandoacessodireto
alista.Estetipodeimplementaosimplificadodemais,necessrioadicionarmaiscontrole
sobrearelaodeLivrocomAutor,como:evitarNPEinstanciandoalista,nopermitindoque
umalistasejaatribuda(semsetAutores),nopermitindoacessodiretoalista(getAutoresspara
leitura)econtrolandoaadioeremoodeautores.Vejaumexemplomelhorimplementadoa
seguir:
Adicionandocontrolearelao:
class Livro implements Comparable<Livro> {
44

Encapsulamento a prtica de esconder detalhes da implementao


103

Captulo 3 Projeto e Modelagem de Objetos

// instanciar a lista evita NPE


private List<Autor> autores = new ArrayList<Autor>();
// obrigar no construtor a informao de pelo menos um Autor
public Livro(String titulo, Autor autorPrincipal) {
this .titulo = titulo;
this .autores.add(autorPrincipal);
}
public List<Autor> getAutores() {
// o mtodo unmodifiableList retorna uma lista somente leitura
// impedindo a chamada de add ou remove na lista
return Collections.unmodifiableList(autores);
}
// impedir atribuio de novas listas removendo o setter
// public void setAutores(List<Autor> autores) {
//

this.autores = autores;

// }
// controlar a adio de novos autores segundo a lgica do domnio
public void addAutor(Autor autor) {
if (autores.size() >= 8) {
throw new IllegalStateException("j existem 8 autores");
}
this .autores.add(autor);
}
// ...

Esta implementao faz com que a classe Livro controle a relao com Autores. So
medidassimplesenecessriasparaumbommodelodedomnio,apenasprofissionaismodelam
assim,desenvolvedoresamadoresexpemtodosatributoscomgettersesetters. Umsituao
tpicadeusoapareceaseguir:
Coleescontroladas:
// OK: obrigatrio informar um autor
Autor autor = new Autor("McLaughlin", "Brett");
Livro livro = new Livro("Anlise e Projeto Orientado ao Objeto", autor);
// OK: novos autores so adicionados por intermdio do livro, no da lista
livro.addAutor(a2);
// OK: acesso direto a lista s se for para leitura
for (Autor a : livro.getAutores()) { System.out.println(a); }
// OK: acesso direto para gravao falha
livro.getAutores().add(a3); // esta instruo falha
// OK: maximo 8 autores
livro.addAutor(a3);
// ... 4,5,6,7,8
livro.addAutor(a9); // esta instruo lana IllegalStateException

Semprequepossvelimplementeoacessolimitadoscoleespertencentesaumobjeto,
comoocasodaassociaodelivroseautores.Tambmtomecuidadoparaescolheracoleo
104

Captulo 3 Projeto e Modelagem de Objetos

correta,porexemplo,ouso de List permiteelementosduplicados,logoainstruo aseguir


funcionarianosistemamasseriainconsistentecomaregradenegcio:
Coleoinadequadaparaasregras:
Autor autor = new Autor("Martin Fowler");
Livro livro = new Livro("Refatorao", autor);
livro.addAutor(autor); // opa, mesmo autor
livro.addAutor(autor); // outra vez
System.out.println(livro.getAutores());
// imprime [Autor nome:Martin Fowler,
// Autor nome:Martin Fowler, Autor nome:Martin Fowler]

permitidoincluirvriasvezesomesmoAutordevidoaclasseLivrousarumalistapara
armazenarosautores.Acoleoadequadaseriaoconjunto(Set),aseguir:
Coleoadequadaparaasregras:
class Livro implements Comparable<Livro> {
// se no pode duplicar, use conjuntos (set's)
private Set<Autor> autores = new HashSet<Autor>();

Umlivrotemumacoleodeautoresepoderiaterumacoleode,digamos,categorias.
Usarascoleespreexistentesnabibliotecadeclassesembutidanalinguagempodeserprtico
para (um chute) 80% das situaes. Por outro lado, dado os requisitos, podeser necessrio
implementarumacoleopersonalizada.Aindanoexemplodelivroseautores,digamosqueseja
necessrioalteraraordemdosautores:usando List, aordempreservada,inicialmentepela
insero,epodeseralterada,entretantoListpermiteelementosduplicados;usandoSet,no
permitidoelementosduplicados,masaordemdoselementosimprevisvel,ouseja,norespeita
aordemdeinserooupodeseralterada.
Umacoleopersonalizada,conhecidacomo container deoutrosobjetos,sendoque
nonecessrioquesuacoleoseencaixeemalgumaestruturaprdefinida,como List,Setou
Map. O container deveapenasfornecerosmtodosnecessriosparaoperarsobreoselementos
queelecontm.
Comodepraxe,pensoquemaissimplesdeentendercomumexemplo,bem,vamosa
ele:considere o controle de lanamentosem um sistema de contabilidade;cada lanamento
podeserumadespesaoureceita;existemcaixas,quesorepresentadosporumadataeum
pontodevenda(PDV).

105

Captulo 3 Projeto e Modelagem de Objetos

CaixaeLanamento:umrelacionamentodeumparamuitos

Namodelageminicialpodemserdefinidasduasclasses: CaixaeLancamento.Caixatemuma
listadeLancamento,quepodeserumadespesaoureceita.Algumasfuncionalidadestemqueser
implementadas,porexemplo:calcularototaldedespesas,totaldereceitasesaldo.Este um
exemplosimplista,usadoapenasparailustrarasituao.Aseguirumaimplementaoinicial:
ImplementaodeCaixaeLancamento:
class Caixa {
private int pdv;
private Date data;
private List<Lancamento> lancamentos = new ArrayList<Lancamento>();
// ...
class Lancamento {
private TipoLancamento tipo;
private Date dataHora;
private double valor; // o ideal seria usar BigDecimal
// ...
public enum TipoLancamento { DESPESA, RECEITA; }

EstaimplementaobemparecidacomLivro/Autor,analogamenteamesmarelao
existe entre Caixa/Lancamento. Ainda existem alguns mtodos a serem implementados:
totalDespesas():double, totalReceitas():double e saldo():double. Onde ficam estesmtodos? No
portadordacoleo,ouseja,Caixa:
MtodosdacoleonaclasseCaixa:
class Caixa {
// ...
public double totalDespesas () {
double totalDespesas = 0.0;
for (Lancamento lanc : lancamentos) {
if (lanc.getTipo() == TipoLancamento.DESPESA) {
totalDespesas = totalDespesas + lanc.getValor();
}
}
return totalDespesas;

106

Captulo 3 Projeto e Modelagem de Objetos

}
public double totalReceitas () {
// semelhante a totalReceitas - comparao com RECEITA
}
public double saldo () {
// como seria o saldo? totalReceitas() - totalDespesas()?
// at pode ser, mas h um problema de performance,
// consegues perceber?
}
}

Estaimplementaoatendebem,contudoaindahumdetalhe:digamosquebusquemos
nabasededadoslanamentosentre01/01/2011at31/03/2011equeiramossaberototalde
despesas,receitasesaldonesteperodo,com opropsitodegerarumrelatrio.Note,neste
exemplonohaexistnciade Caixa,nemtodasreceitasedespesasforamlanadasemum
PDV.Ento,paraestecasoeunotenhocomousarosmtodos totalDespesas, totalReceitas e
saldo,presentesnaclasseCaixa,anoserqueeuatribuaesteslanamentosaumcaixacomdata
nula,pdv0,etc,sparapoderusarosmtodos,ouseja,gambiarra.Poderiacopiarecolarestes
mtodosnaclasse Relatorio,masaindaassiminadequado,poisdigamosquenofuturoseo
clculo mudareu teria quefazer a alterao em nas classes Caixa e Relatorio (eoutrasque
venhamacalcularostotaisesaldo,caracterizandoviolaodoPrincpiodeProjetoDRY).No
seiseficouclaroataquiqueeutenhoquefazerestesclculosindependentedeexistirouno
umcaixa,ouseja,estesmtodosnodevempertenceraCaixa.Umasoluopossvelcriarum
objetocomopropsitodeagruparvrioslanamentoseoperarsobreeles,ouseja,umcontainer
delanamentos.Aseguirumdiagramadeclassesquerepresentaonovomodelo:

ClasseLancamentosrepresentaumacoleodeLancamento
MtodosdacoleonaclasseLancamentos:
class Lancamentos {
// ...
public double totalDespesas() {
// ...

107

Captulo 3 Projeto e Modelagem de Objetos

Assim,temosomodelodeLancamento,seuestadoecomportamentoetambmLancamentos,
no plural, seu estado e comportamento. A primeira grande dvida se fazer Lancamentos
estenderArrayList,oquecaracterizaherana,oufazercomqueLancamentostemumArrayList
comoatributo.Asegundaopo,emgeral,amaisrecomendada.Existeumaheurstica: Prefira
ComposioaHerana.Joshtrazexemplosnoseulivro[JOSH]acercadeproblemascomheranae
quebra do encapsulamento45. Ento, para este caso, vamos seguir o princpio de preferir a
composioeaimplementaopoderiasercomoestaaseguir:
ImplementaodeCaixa,LancamentoeLancamentos:
class Caixa {
private int pdv;
private Date data;
private Lancamentos lancamentos = new Lancamentos();
// ...
public double totalDespesas() {
// Caixa delega o clculo para Lancamentos
return lancamentos.totalDespesas();
}
}
class Lancamentos { // aqui est o diferencial
private List<Lancamento> lancamentos = new ArrayList<Lancamento>();
public void add(Lancamento lancamento) {
lancamentos.add(lancamento);
}
public double totalDespesas() {
double totalDespesas = 0.0;
for (Lancamento lanc : lancamentos) {
if (lanc.getTipo() == TipoLancamento.DESPESA) {
totalDespesas = totalDespesas + lanc.getValor();
}
}
return totalDespesas;
}
// ... mtodos para calcular o total de receitas e saldo
}

ComessedesignaclasseLancamentospodeserusadaemoutroslugares,nosnocaixa,
comoporexemploemumabuscanabasededadosporperodo:
ClasseLancamentosdesacoplaosmtodosdaCaixa:
Lancamentos lancamentos = contabil.lancamentosEntre(dataInicial, dataFinal);
txtDespesas.setText(lancamentos.totalDespesas());
txtReceitas.setText(lancamentos.totalReceitas());
// os clculos no dependem da classe Caixa
45

Gostadeler?Sobreheranaquebraroencapsulamento,temumbomartigoaqui
http://igstan.ro/posts/20110909howinheritanceviolatesencapsulation.html

108

Captulo 3 Projeto e Modelagem de Objetos

Um detalhe importante que no pode ser esquecido que a instncia da classe


Lancamentosnopodeserusadaemloopsdotipoforeach(for (objeto : colecao)).Seriapossvel
se Lancamentos estendesse ArrayList, mas no foi essa a abordagem utilizada. Sendo assim, o
cdigoaseguirfalha:
ColeoLanamentosnoitervel:
Lancamentos lancamentos = contabil.lancamentos(Mes.Janeiro, 2012);
for (Lancamento lanc : lancamentos) { // esse cdigo no compila
// ...

O foreach foi adicionado no Java 5 e tem como exigncia que as classes container
implementemainterfaceIterable<T>,ondeTaclassedoelementosingular.Aseguiraalterao
emLancamentosparaserusadoemforeach:
TornandoContainersiterveis:
// Lancamentos Itervel se implementar Iterable
public class Lancamentos implements Iterable<Lancamento> {
// ...
// este mtodo para honrar o contrato de Iterable
public Iterator<Lancamento> iterator() {
// delegamos o iterador para a lista
return lancamentos.iterator();
}
}
// situao de uso:
Lancamentos lancamentos = contabil.lancamentos(Mes.Janeiro, 2012);
for (Lancamento lanc : lancamentos) { // esse cdigo funciona agora

Existemmuitosdetalhesrelacionadosacoleesdeobjetoseaminhasugestoque
estudes,conformealinguagem,omodelodecolees.NoJavausadoabibliotecaCollections,
presenteemjava.util,maisaqui:
http://docs.oracle.com/javase/tutorial/collections/index.html

Por exemplo, se fores programador PHP ou aspirante a um, colees em PHP so


modeladascomoarraysassociativos,veraqui:
http://php.net/manual/pt_BR/language.types.array.php

Domineasestruturasdedadosusadasparalidarcomcolees,independentedasualinguagemde
programao,tuirsprecisardelas.

ValueObjects
J conversamos sobre Entidades, certo? Sobre um objeto que deve ter um estado,
comportamento euma identidade. Equandoosobjetosnoprecisamdeidentidade? Em
outras palavras, o objeto existe para armazenar um valor, que representa seu estado e
determinanteparaascomparaesentreinstncias,ouseja,seduasinstnciastemomesmo
valorelassoconsideradasiguais.
109

Captulo 3 Projeto e Modelagem de Objetos

Entosimplesmenteovalorqueeleguardaomesmoqueodefine,ento,estestiposde
objetossochamadosdeValueObjects46(objetosdevalor),ouVO.OsVO'ssodiferentesde
entidadesemalgunssentidos,almdenoterumcampoquedeterminaasuaidentidade,VOs
tipicamentenopossuemumacontrapartidanobancodedados,ouseja,noexisteumatabela
paraele,maselessotipicamentearmazenadosemcamposdeumatabelaparaamodelagemde
umcertotipodedadocomposto.
Porexemplo,digamosquenonossodomniotemosClienteedadosbsicosdesteCliente.
ClienteseriamodeladocomoumaEntidadee,inclusive,teriaumatabelasefosseusadoum
SGBD.Ento,digamosqueumdosatributosdeClientesejaTelefone.Inicialmente,qualquerum
incluiriaumatributonaclasseClientechamadotelefonedotipoString.Entretanto,Stringaceita
tudo,deletrasacaracteresespeciais,enonecessariamenteseguiriaaregraderepresentaode
um telefone no modelo, digamos, (xx)xxxx-xxxx ou +xx (xx) xxxx-xxxx. Alteraes na
representaolevariamamudanasnaclasseClienteeoutrasclassesquefazemusodoatributo
Telefone,comoEmpresa,Fornecedor,etc.NestasituaobemmaisvantajosomodelarTelefone
como uma classe, um tipo complexo, que serve para guardar o valor de telefone e ter a
responsabilidadedelidarcomoformato(verSingleResponsibilityPrinciple).Presteateno,a
classeTelefonerepresentaumnmero,notemtabela,maspodeserpersistidaemumcampodo
tipovarchar.Aseguirocdigoqueapresentaesteexemplo:
AtributoscompostoscomString:
class Cliente {
Integer id;
String

cpf;

String

nome;

String

telefone; // telefone como String permite qualquer contedo

// ...
// situao de uso:
cliente1.setTelefone("53 11667788");
cliente2.setTelefone("+555399441100");
// a padronizao do formato de telefone no existe, a no ser que
// alteremos o mtodo setTelefone em Cliente

Parecetentadoralteraromtodo setTelefone emClienteparadefiniroformatoaceito,


entretanto se outras classes usam o atributo Telefone, como Fornecedor, tambm teria de
reescreversetTelefone,resultandoemduplicao(verPrincpiodeProjetoDRY).Umatentativa
deresolveroproblemaseriasubiromtodo setTelefone paraumsuperclasse,comoPessoa,e
fazerClienteeFornecedor estenderem Pessoa eherdaromtodo setTelefone. Contudonem
sempreotelefonepodeestaratreladoaumaPessoa,considereumobjetoEncomenda,quetem
umnmerodetelefoneparacontato,comofazerEncomenda honraroformatodotelefone?
FazendoEncomendaestenderPessoa?Ento,usaraherananoesterrado,masimportante
saberqueaheranapodeincorreremrigideznoprojeto,umasoluomaisflexvelusara
composio(verPrefiraComposioHerana).
Dadosquetemalgumtipodearranjolgico,comotelefone,endereo,CPF,etc,pode,e
svezesdevem,sermodeladosusandotiposcomplexos,objetos,aoinvsdetiposprimitivosou
46

ExisteoutraacepodeVO,queeradepassardadosentrecamadas.EstaacepodeVOnomaisusada,noseu
lugarfoiintroduzidoDataTransferObject(DTO)
110

Captulo 3 Projeto e Modelagem de Objetos

Strings.Estestiposdedadoscomestruturasmaissimplesesemidentidadesoconsiderados
ValueObjects.Omesmoexemplo,deClienteeTelefone,usandoValueObjects,podeservistoa
seguir:
ModelandocomValueObjects:
class Cliente {
Integer id;
String

cpf;

String

nome;

Telefone

telefone;

// ...
class Telefone {
String ddd;
String numero;
public Telefone(String ddd, String numero) {
this .ddd = ddd; this.numero = numero;
}
public Telefone(String numero) {
this (null, numero);
}
// ... getters e setters
public String toString() {
return new StringBuilder().append("(").append(ddd).append(") ")
.append(numero.substring(0, 4)).append("-")
.append(numero.substring(4, 8)).toString();
}
// ...
// existe uma associao entre Cliente e Telefone
cliente1.setTelefone(new Telefone("53","32114455"));
cliente2.setTelefone(new Telefone("99774411"));
// a alterao do ddd pode ser aplicada atravs da associao
cliente2.getTelefone().setDdd("51");
// a apresentao de telefone depende unicamente da classe Telefone
System.out.println(cliente2.getTelefone()); // imprime (51) 9977-4411

desejvel,masnoobrigatrio,queVOssejamimplementadoscomoTiposImutveis,
ouseja,classessemmtodosset.Outropontoimportantequenemtodoatributodeveserum
VO, visto que a introduo de VOs adicionam indireo, ou seja, aumenta a quantidade de
classes.
H de se pesar os prs e contras, o custo e o benefcio, de introduzir novos tipos
complexos,especialmentequandohnenhumoupoucoganhoemrelaoausarumprimitivo.
Porexemplo,considerequeumaclassePedidotenhaainformaodediasparaentrega;
aquesto:usaruminteiropararepresentardias?ouusarumaclassePrazo?Osdoisservem,s

111

Captulo 3 Projeto e Modelagem de Objetos

digo para que avalies bem para no fazer sobreengenharia (overengineering47). Favorea a
simplicidadesemprequepossvel(verPrincipleofGoodEnough).

TiposeObjetosImutveis
AlgunsValueObjectspodem,oudevem,serimplementadoscomotiposimutveis,em
contraste a implementao padro, que mutvel. Mas o que imutabilidade? Em poucas
palavras,imutabilidadesignificaquequalquerrefernciaparaumobjetoimutvelnoterseu
valoralterado,emoutraspalavras,notemseuestadoalteradodepoisdecriado.
Objetosimutveissoteisemambientesdeextremaconcorrncia,ouseja,ondevrias
threadsmanipulamosmesmosobjetos.Oobjetocompartilhado,sendoimutvel,cadathreadao
alterloterumanovacpiadoobjeto,nointerferindonasdemaisthreads.Opontonegativo,
que cada alterao no objeto cria uma nova instncia, necessitando mais recursos, como
memria,processadoretendo,assim,menosperformance.
Vamosprimeirosentenderoqueumtipomutvel,ouseja,opadrodaslinguagens
orientadasaobjetos.ConsidereumexemplodeEndereo;digamosqueumFornecedortemum
Endereo,comapenasduaspropriedades:ruaenumero.Aseguirocdigoquerepresentaeste
exemplo:
Porpadroosobjetossomutveis:
class Fornecedor {
Integer

id;

String

nome;

Endereco endereco;
// ...
class Endereco {
String rua, numero;
// ...
// situao de uso:
Endereco end = new Endereco("Rua J", "998A - Ap 102");
// partimos do pressuposto de que dois fornecedores tem o mesmo endereo
forn1.setEndereco(end);
forn2.setEndereco(end);
// como ambos fornecedores tem a mesma instncia de endereo, as
// alteraes nesta instncia sempre afetar os dois fornecedores
forn1.getEndereco().setRua("Rua P");
// forn2 tambm teve os dados do endereo alterados, o que no bom
System.out.println(forn2.getEndereco()); // imprime Rua P

Amaioriadasclassesqueprojetamoseobjetosqueinstanciamossomutveis,99%da
APIdoJava(classesembutidasnalinguagemcomo Date)tambmso.Contudo,umtipobem
conhecidonossoimutvel:oString.Stringumaclasse,noumprimitivo,erepresentauma
sequnciadecaracteres(char).SendoStringimutvel,significaquealteraesnoobjeto String
47

Sobreengenharia:http://en.wikipedia.org/wiki/Overengineering
http://www.webartigos.com/artigos/asimplicidadedascoisas/4388/

112

Captulo 3 Projeto e Modelagem de Objetos

geram uma nova String, ou seja, cada modificao gera uma cpia. Isto pode gerar efeitos
interessanteseestressantesparanovosprogramadoresque,confusos,tendemnoentendero
porqudocomportamentodeString.AseguirumexemplodofuncionamentodeStrings:
Algunsobjetossoimutveis,comoString:
String texto1 = "Um teste";
String texto2 = texto1;
// cria um novo objeto "UM TESTE" sem alterar a instncia de origem
texto1.toUpperCase();
System.out.println(texto1); // imprime: Um teste
System.out.println(texto2); // tambm imprime: Um teste
// cad "UM TESTE"? Ele no foi atribudo a nenhuma varivel!
// preciso reatribuir para referenciar o objeto alterado
texto1 = texto1.toUpperCase();
System.out.println(texto1); // agora sim, imprime: UM TESTE
System.out.println(texto2); // continua imprimindo: Um teste

EstecomportamentodeStrings,deserimutvel,temassuasvantagensedesvantagens.A
principaldesvantagemsooperaesdeconcatenaofrequentesquepodemimpactarbastante
naperformance.ParaestescasosusadoaclasseStringBuilder48.
Comoseimplementaumobjeto(tipo)imutvel?Notocomplicado,normalmente
implicaemcriarumconstrutorcomoatributoprincipalenocriarmtodos setters, esecriar
fazlosretornarsempreumanovainstncia.Aseguirtemumexemploquedeixamaisclaro,
considereamodelagemdecomprimento,aprincpioemcm:
ImplementaomutveldeComprimento:
public class Comprimento {
private int centimetros;
public Comprimento(int centimetros) {
setComprimento(centimetros);
}
public int getComprimento() {
return centimetros;
}
// assim a classe mutvel:
public final void setComprimento(int centimetros) {
if (centimetros < 0) throw new IllegalArgumentException("no pode ser negativo");
this .centimetros = centimetros;
}
// ...

Paratornar Comprimento imutvelsonecessriaspoucasalteraes,defato,aprincipal


diferenaestnosmtodossetter's.Aseguirasalteraesnecessriasparatornlaimutvel:
48

MaissobreStringBuilder:http://www.devmedia.com.br/aclassestringbuilderemjava/25609
113

Captulo 3 Projeto e Modelagem de Objetos


ImplementaoIMUTVELdecomprimento:
public class Comprimento {
private int centimetros;
public Comprimento(int centimetros) {
if (centimetros < 0) throw new IllegalArgumentException("no pode ser negativo");
this .centimetros = centimetros;
}
public int getComprimento() {
return centimetros;
}
// assim IMUTVEL:
public final Comprimento setComprimento(int centimetros) {
return new Comprimento(centimetros);
}
//...
// situao de uso:
Comprimento c1 = new Comprimento(10);
Comprimento c2 = c1.setComprimento(20);
System.out.println(c1); // imprime "10 cm"
System.out.println(c2); // imprime "20 cm"

importantesalientaroseguinte:tiposimutveisdepreciamaperformancequandomuitas
operaessoexecutadassobreelesempoucotempo,porexemploemloops.Istoacontecedevidoa
criaodeumnovoobjetoacadavezqueumsetterinvocado.Esteomotivoporque,por
exemplo,Stringsnodevemserconcatenadasdentrodeumloop(for,while,dowhile...).
Nofaaalteraesemtipos(objetos)imutveisdentrodelaos(loops).

A principal vantagem do tipo imutvel a segurana em sistemas concorrentes, em


palavras tcnicas, tipos/objetos imutveis so thread safe. Raramente entidades, tipos de
referncia,soimplementadoscomoimutveis,ousodeimutabilidademuitomaiscomumem
ValueObjects(verEntidadeseValueObjects).
Tiposimutveistemumagrandevantagem,elessothreadsafe.

Linguagensquepossuemtiposdedadoschamadosdeestruturas(structs)noprecisam
detodoessejogodecinturaparaimplementarumtipoimutvel.Structs,noC,C++eC#so
imutveispornatureza.NoC#osstructssochamadosdeValueType(TipodeValor),sequiser
conhecer melhor seu funcionamento tente este link: http://msdn.microsoft.com/pt
br/library/s1ax56ch.aspx

114

Captulo 4 Princpios de Projeto Orientado a Objetos

Captulo4PrincpiosdeProjeto
OrientadoaObjetos
Experincia:
Mestre,comofaoparametornarumsbio?
Boasescolhas.
Mestre,mascomofazerboasescolhas?
Experinciadizomestre.
Ecomoadquirirexperincia,mestre?
Omestrepensaumpoucoeresponde:
Msescolhas.
(Aprendizemestreemumcurtodilogo)

Oentendimentodeprogramaoorientadaaobjetoseacapacidadedeprojetar,
planejaraquantidadedeobjetosnecessriosecomoelesserelacionampararesolverum
problema,vemcomaprticaereflexo. Digoprticae,especialmente,reflexo,porque
necessrio entrar no problema e pensar objetos e, no importa quantas vezes tu reveres o
problema,encontrarssempreoutravisodomesmoproblemaecomoresolvlo.Qualvisoa
certa? Difcil de dizer. Talvez seja por este motivo que alguns dizem que programar uma
misturadecinciaearte49.
O que pode ajudar a fazer bons projetos so alguns princpios, definidos por
programadores,desenvolvedores,arquitetoseengenheirosdesoftware,queformaram,depoisde
tanto projetar, um pensamento slido de como arranjar e escrever estes objetos. Estes
pensamentosforam,eso,tipicamentepublicadoscomoprincpiosoupadresdeprojeto.Esta
parte do livro se destina aos princpios de programao e projeto orientado a objetos. Mais
adianteserovistospadres,quesoumpoucomaiscomplexosqueprincpios,entretanto,tanto
princpioscomopadres,temumpropsitocomum,criarumbomprojeto,ecomobomprojeto,
comojfalamos,entendeseporumsoftwarefcildealterareincluirnovasfuncionalidades,
software fcil de ler e entender, software modular e reaproveitvel, entre outras tantas
qualidadesqueesperamos.

Programeparaumainterfacenoumaimplementao
49

QueodigaDonaldKnuth:http://pt.wikipedia.org/wiki/Donald_KnuthnasuasriedelivrosTheArtof
ComputerProgramming:http://www.amazon.com/ComputerProgrammingVolumes14A
Boxed/dp/0321751043
115

Captulo 4 Princpios de Projeto Orientado a Objetos

Programar para interfaces, ou seja, voltado a abstraes, uma heurstica deprojeto


orientadoaobjetospresenteemboapartedosprincpiosepadres.Masencontrarnoprojetoo
quepodeserdefinidocomoumaabstrao,umaclasseabstrataouumainterface,nouma
tarefatrivial.
Achomelhor,primeiro,justificaroesforodecriarabstraeseuslas:

Osobjetosdesconhecemosoutrosobjetos;

Osobjetosinteragemcomoutrosobjetosatravsdeumcontrato;

Asmudanasnosobjetosnoimplicaemmudanadeoutrosdesdequesuainterface
sejapreservada;

possvelmudaroobjeto,eoalgoritmo,emtempodeexecuo;

Comojdisseantes,nemsempresimplesencontrarobjetosquedevamrespeitaruma
interface,ouseja,comoencontrarumcontratodeoperaoentreobjetos?
Vouusarumexemplopequenomas,atcertoponto,clarodeaplicaodeinterfacese
porqueusarumainterface. Considereummdulodeenviodeemails,encapsuladoemuma
classe EmailService.Aprincpio,eladeveenviarmensagensparaclientes,modeladosnaclasse
Cliente.Vejaaseguirumapseudoimplementao:
Serviodeenviaremail:
class EmailService {
void envia(String assunto, String mensagem, Cliente cliente) {
if (!cliente.isAceitaEmail()) throw new MensagemNaoAutorizada();
String endereco = cliente.getEmailPessoal();
String nome = "Sr(a) " + cliente.getNome() + " " + cliente.getSobrenome();
// ... envia email para endereco, nome, com assunto e mensagem
class Cliente {
String nome, sobrenome;
String emailPessoal, emailProfissional;
boolean aceitaEmail;
// ...

Ataquitudobem.Oproblemademanutenoaparecequandonovosdestinatriosso
includos,comoFuncionrioeEmpresa:
Serviodeenviaremailcomvriostiposdedestinatrios:
class EmailService {
void envia(String assunto, String mensagem, Cliente cliente) {
if (!cliente.isAceitaEmail()) throw new MensagemNaoAutorizada();
String endereco = cliente.getEmailPessoal();
String nome = "Sr(a) " + cliente.getNome() + " " + cliente.getSobrenome();
// ... envia email para endereco, nome, com assunto e mensagem

116

Captulo 4 Princpios de Projeto Orientado a Objetos

}
void envia(String assunto, String mensagem, Funcionario funcionario) {
String endereco = funcionario.getLogin() + "@empresa.com.br";
String nome = funcionario.getNome() + " (" + funcionario.getMatricula() + ")";
// ... envia email para endereco, nome, com assunto e mensagem
}
void envia(String assunto, String mensagem, Empresa empresa) {
if (empresa.getEmailContato() == null) throw new EmpresaSemEmail();
String endereco = empresa.getEmailContato();
String nome = empresa.getNomeFantasia() + " (" + empresa.getRazaoSocial() + ")";
// ... envia email para endereco, nome, com assunto e mensagem
}
}

D para perceber que adies novos destinatrios tornarse um novo mtodo. A


mudanaemqualquerumdosdestinatriostambmimplicarnamudananoserviodeemail,
porexemplo,digamosqueocampologindefuncionriofoirenomeadopara nomeUsuario,isto
implicariaemmudanasemFuncionarioeEmailService(etalvezoutrasclasses).
No exemplo, ficam claros os pontos negativos de depender de classes concretas
(implementaes).Oserviodeemaildependedosdetalhesdasclasses,nodeveria.Como
resolver?Ora,introduzindoumaabstrao!Nosexemplosfalamosdedestinatrio,enaprticao
serviodeemaildeveriapoderenviarparaqualquerdestinatrio,indiferentedeelesercliente,
funcionrio,ououtro.Umserviodeemaildependedeumdestinatriodeemail,eisnossa
abstrao.Modelamosdestinatrioscomumainterface Destinatario,masoqueeladevecumprir
paraseraceitapor EmailService?Bem,seinvestigarmososmtodos,odestinatriochecado
quantoapossibilidadedeenvio,edepois pegooendereodeemailenomeusadoparao
contato.Ento,umainterfacepoderiasercomoaseguir:
Serviodeenviaremaildependendodeumaabstrao:
class EmailService {
void envia(String assunto, String mensagem, Destinatario destinatario) {
try {
destinatario.checaPossibilidadeDeReceberEmail();
} catch (EmailException excecao) {
logger.warn("nao foi possivel enviar email para: " + destinatario.toString());
throw excecao;
}
String endereco = destinatario.getEnderecoParaCorrespondencia();
String nome = destinatario.getNomeParaCorrespondencia();
// ... envia email para endereco, nome, com assunto e mensagem
}
}
// aqui est a interface, o contrato, a ABSTRAO:

117

Captulo 4 Princpios de Projeto Orientado a Objetos

public interface Destinatario {


void checaPossibilidadeDeReceberEmail() throws EmailException;
String getEnderecoParaCorrespondencia();
String getNomeParaCorrespondencia();
}

Opassoseguintefazercomquequalquerobjetoquepossaserumdestinatriocumprao
contrato,implementandoainterface:
Honrandoocontratocomaimplementaodainterface:
// classe Cliente honrando o Contrato:
class Cliente implements Destinatario {
// ...
public void checaPossibilidadeDeReceberEmail() throws EmailException {
if (!aceitaEmail) throw new MensagemNaoAutorizada();
}
public String getEnderecoParaCorrespondencia() { return emailPessoal; }
public String getNomeParaCorrespondencia() {
return "Sr(a) " + cliente.getNome() + " " + cliente.getSobrenome();
}
}
// classe Funcionario honrando o Contrato:
class Funcionario implements Destinatario {
// ...
public void checaPossibilidadeDeReceberEmail() throws EmailException {
// funcionrios no tem restrio
}
public String getEnderecoParaCorrespondencia() {
return login + "@empresa.com.br";
}
public String getNomeParaCorrespondencia() {
return nome + " (" + matricula + ")";
}
}
// classe Empresa honrando o Contrato:
public class Empresa implements DestinatarioEmail {
// ...
public void checaPossibilidadeDeReceberEmail() throws EmailException {
if (emailContato == null) throw new EmpresaSemEmail();
}
public String getEnderecoParaCorrespondencia() { return emailContato; }
public String getNomeParaCorrespondencia() {
return nomeFantasia + " (" + razaoSocial + ")";
}
}

118

Captulo 4 Princpios de Projeto Orientado a Objetos


EmailService agoradependedaabstrao Destinatario,qualquerobjetoqueimplemente
Destinatario

poder ser encaminhado ao EmailService. O problema proposto antes, de um


funcionrionoterloginesimnomeUsuario,agorasersimplesderesolver,bastandoalterarna
classeFuncionarioomtodogetEnderecoParaCorrespondencia.
Noseisejdisseissoantes,masdependadeabstraesnodeimplementaes

Prefiracomposioaherana
Tipicamentequalquerprogramadorquejsesintaconfortvelcomalinguagem,digamos
Java, e programao orientada a objetos, comea a introduzir reuso atravs da herana. Os
benefciospontuaisdaheranasoinquestionveis,oquecolocadoempautaatondea
heranaumbomnegcioparaoprojeto.
Josh Bloch argumenta em seu livro: prefira composio a herana. Ofundamento do
argumentodeJosh,edeoutrosautores,que,svezes,heranaquebraoencapsulamento.
importante saber, quando estendemos uma classe, se cumpriremos o contrato e
aceitaremos sua implementao. Temos de saber que dependemos de sua implementao,
dependemosdasuperclasse,eseelamudartalveznossasubclassequebre.
Paraexplicarmelhorvouusarumexemplobemclssico,abordadoporJoshBlochnoseu
livroJavaEfetivo.Considereumexpansode HashSet,queumconjuntobaseadoemtabelas
hash.Comoconjunto,HashSetnopermiteitensduplicados,istoquedizerqueseeutentarinserir
omesmoelemento(segundooequals)apenasum,defato,serinserido.Naminhaextensode
HashSeteupretendoarmazenaronmerodetentativasdeinsero,ouseja,seeutentarinserir5
vezesomesmoobjeto,o size do HashSet deveresponder1eo attempts (tentativas)5.Aideia
inicialestenderHashSetparaadicionarestecomportamentonovo:
Estendendoclassesparaadicionarcomportamento:
public class InstrumentedHashSet<T> extends HashSet<T> {
private int attempts; // varivel para armazenar o nro de tentativas
public int attempts() {
return attempts;
}
// o prximo passo sobrescrever os mtodos usados
// para adicionar elementos:
// add(T elemento) e addAll(Collection<? extends T> elementos)}
@Override
public boolean add(T elemento) {
attempts++;
return super .add(elemento);
}
@Override
public boolean addAll(Collection<? extends T> elementos) {
attempts += elementos.size();

119

Captulo 4 Princpios de Projeto Orientado a Objetos

return super .addAll(elementos);


}
}

Aperguntade1milho:oquehdeerradocomessaimplementao?Aprimeiravista,
nada.OmtodoaddincrementatentativaseomtodoaddAlladicionaecontabilizaastentativas.
Vamosaumasituaodeuso:
UsandooHashSetinstrumentado:
InstrumentedHashSet<String> palavras = new InstrumentedHashSet<String>();
palavras.add("teste"); palavras.add("livro"); palavras.add("teste");
System.out.println(palavras.size());

// imprime 2, ok!

System.out.println(palavras.attempts()); // imprime 3, ok!


// tudo bem at usar o addAll:
InstrumentedHashSet<String> palavras = new InstrumentedHashSet<String>();
List<String> lista = Arrays.asList(new String[] {"teste", "livro", "teste"});
palavras.addAll(lista);
System.out.println(palavras.size()); // imprime 2, ok!
System.out.println(palavras.attempts()); // imprime, h, 6?

Ondeestoproblema?Acontecequeomtodo addAll,herdadode AbstractCollection,


executaomtodoaddparacadaelementodacoleo.Ouseja,adicionamos3,queo size da
lisarecebida,masoaddAllchamaomtodoaddmaistrsvezes.
Quandoestendemosumaclassetemosdeestarsegurosquedependerdemtodosdesta
superclasseparacompornovasfuncionalidadespodeserperigoso,propensoafalhasededifcil
depurao. A falha no exemplo decorreu da dependncia de mtodos das superclasses, isso
legitimaaheursticaPrefiraComposioaHerana.Heranapodequebraroencapsulamento.
Ento,comoimplementaromesmoexemplousandocomposioaoinvsdeherana?
Nocomplicado.Geralmenteimplicaemimplementarainterface(ouno)eterumatributo
privadodotipoquesedesejaestender,ouseja,nsteremosestetiponacomposiodenossa
classe,maisoumenosassim:
Estendendocomportamentocomcomposio:
// implementamos a interface de HashSet (Set) em vez de estend-la
class InstrumentedHashSet<T> implements Set<T> {
private int attempts;
public int attempts() { return attempts; }
// muito importante, guardamos um conjunto para
// o qual delegaremos as chamadas

120

Captulo 4 Princpios de Projeto Orientado a Objetos

private HashSet<T> setInterno = new HashSet<T>();


public boolean add(T e) {
attempts++;
// o retorno sempre delegado para o conjunto interno
return setInterno.add(e);
}
public boolean addAll(Collection<? extends T> c) {
attempts += c.size();
return setInterno.addAll(c);
}
// todos os mtodos a seguir delegam para o conjunto interno
public int size() {
return setInterno.size();
}
public boolean isEmpty() {
return setInterno.isEmpty();
}
// ...

Serquefunciona?Faaoteste.Nosemprequecomposiopreferidaaherana,
masfatoqueacomposiotrazumaflexibilidademaior.Omaischato delegartodosos
mtodos.EmlinguagenscomooGroovy,estatcnicadedelegaoincludanadeclaraoda
classesemprecisarimplementarnamoadelegao,vejaaqui:
http://groovy.codehaus.org/Delegate+transformation

umacompetnciachavesaberestenderfuncionalidadesporgeneralizao(herana)ou
delegao(composio).
aprendaadelegar,istoimportante

Noserepita(DRY)
OprincpioDRYparecerserumdosmaisfceisdecompreendere,mearriscoadizer,de
seguir.Contudo,setulevaresaopdaletra,nosparaocdigomasparaoutrasatividades
relacionadas,elepodeserbemextenso.MasatagoraeunodisseoquesignificaDRY,disse?
DRY o acrnimo de Dont Repeat Yourself, em portugus No Se Repita (NSR seria o
acrnimo,masningumusa:).
Oprimeiroentendimento,maissimples,deDRYevitarquaisquerduplicaesnocdigo.
Porexemplo,seeutenhoumalgoritmousadoparavalidarCPF,entoestealgoritmodeveestar
emumlugarapenas,umlugarbemdefinido,livredeambiguidades.SegundoAndyHunteDave
Thomas, que so experientes programadores e escreveram um livro de muito sucesso: O
ProgramadorPragmtico:deaprendizamestre;DRYsignificaoseguinte:
cadapedaodeconhecimentodeveterumanica,noambguaeautenticarepresentaoemum
sistema

121

Captulo 4 Princpios de Projeto Orientado a Objetos

Traduolivre,vejaaorigemaqui:
http://pragprog.com/thepragmaticprogrammer/extracts/tips

Nestesentido,podemosusarumexemplo.Imaginequenossosistemaexecuteconsultas
comdatasnaformadeintervalos.Nestesentido,cadaintervalodevetersuadatainicialedata
finalmodificadasparareceberemahora00:00:00e23:59:59respectivamente:
LidandocomtemponoJava,sempreumdesafio:
class GeradorRelatorio {
Relatorio entre(Date dataInicial, Date dataFinal) {
Calendar calInicial = Calendar.getInstance();
calInicial.setTime(dataInicial);
calInicial.set(Calendar.HOUR, 0);
calInicial.set(Calendar.MINUTE, 0);
calInicial.set(Calendar.SECOND, 0);
calInicial.set(Calendar.MILLISECOND, 0);
dataInicial = calInicial.getTime();
Calendar calFinal = Calendar.getInstance();
calFinal.setTime(dataFinal);
calFinal.set(Calendar.HOUR, 23);
calFinal.set(Calendar.MINUTE, 59);
calFinal.set(Calendar.SECOND, 59);
calFinal.set(Calendar.MILLISECOND, 999);
dataFinal = calFinal.getTime();
// faz a consulta
}
}
class BuscadorMovimento {
Movimentos entre(Date dataInicial, Date dataFinal) {
Calendar calInicial = Calendar.getInstance();
calInicial.setTime(dataInicial);
calInicial.set(Calendar.HOUR, 0);
calInicial.set(Calendar.MINUTE, 0);
calInicial.set(Calendar.SECOND, 0);
calInicial.set(Calendar.MILLISECOND, 0);
dataInicial = calInicial.getTime();
Calendar calFinal = Calendar.getInstance();
calFinal.setTime(dataFinal);
calFinal.set(Calendar.HOUR, 23);
calFinal.set(Calendar.MINUTE, 59);
calFinal.set(Calendar.SECOND, 59);
calFinal.set(Calendar.MILLISECOND, 999);
dataFinal = calFinal.getTime();
// faz a consulta

Estafuncionalidade,deconfigurardatasiniciaisefinaisparaoincioefimdodia,sero
necessriosemvriaspartesdaaplicao.Omelhorafazerextralas:

122

Captulo 4 Princpios de Projeto Orientado a Objetos


Criandoumarepresentaonicadeumafuncionalidade:
class DateUtil { // classe usada para operaes com data/hora
static Date inicioDia(Date data) {
Calendar cal = Calendar.getInstance();
cal.setTime(data);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal.getTime();
}
static Date finalDia(Date data) {
Calendar cal = Calendar.getInstance();
cal.setTime(data);
cal.set(Calendar.HOUR, 23);
cal.set(Calendar.MINUTE, 59);
cal.set(Calendar.SECOND, 59);
cal.set(Calendar.MILLISECOND, 999);
return cal.getTime();
}
}

Apsterarepresentaonicadoalgoritmonsousamosereusamos:
Situaodeuso:
import static DateUtil.*;
class GeradorRelatorio {
Relatorio entre(Date dataInicial, Date dataFinal) {
dataInicial = inicioDia(dataInicial);
dataFinal = finalDia(dataFinal);
// faz a consulta
// ...
class BuscadorMovimento {
Movimentos entre(Date dataInicial, Date dataFinal) {
dataInicial = inicioDia(dataInicial);
dataFinal = finalDia(dataFinal);
// ... faz a consulta
// ...

Agoraadicionamosumaclassereusvelparalidarcomdata,masumaressalva:oideal
seriamodelarIntervalo,ouseja,criarumaclasseIntervalo.Comodatasinicialefinalandam
juntas e representam um substantivo: Intervalo, seria adequado modello como um Value
Object.
Embora normalmente o princpio DRY seja visto apenas como um incentivador para
eliminarduplicaesdecdigosefuncionalidades,elevaimaislonge,transcendeocdigo.Por
exemplo, tpico, no desenvolvimento de sistemas, documentar os mdulos, componentes,
classes,criandoumtextoacessvelparaasequipesdedesenvolvimentos,anliseeengenharia.
Antes, se editava um documento de texto compartilhado. O cdigo tambm, normalmente,
precisadedocumentao,oquefeitocomcomentrios.Emoutraspalavras,nestemodode
123

Captulo 4 Princpios de Projeto Orientado a Objetos

trabalho,odesenvolvedor tende adocumentarem dois lugares, oquefereoprincpioDRY.


Claro, este tipo de duplicao j foi solucionado, lembras como? No caso do Java, com o
JavaDoc: comentrios javadoc documentam tanto o cdigo como geram um documento de
acessogeral,aAPI,comaajudadajavadoctool.
Possodarumoutroexemplo,bemcomum,quejpasseiepassonodesenvolvimentode
sistemasparainternet.Setudesenvolvesparainternetjdeve,provavelmente,terpassadopor
esteproblema.Imagineumcadastrosimplesdeclientes,ondealgunscampossoobrigatrios,
outros devem ter um valor vlido, como cpf, data de nascimento, etc. Isto garantido com
validaes,quedevemserfeitasemvriascamadasdosistema,aprincpionalinguagemusada
noservidor(PHP,Python,Java,C#,etc),tambmnobancodedadoscomoumcamponot null,
etambmnainterfacecomJavaScript.Enfim,eutenhoqueafirmaraobrigatoriedadedeum
campoemnomnimotrslugares:nobanco,naclasseenainterfacecomousurio.Noseria
bomsepudssemosdefinirocampocomoobrigatrioemumslugareistosepropagasseentre
ascamadas?JviissofuncionarbemnoRails,teinteressacriaralgosemelhanteparaJava?Fica
adica.

PrincpiodaMenorSurpresa(POLA)
POLA tambm conhecido como Princpio da Menor Surpresa (Principle of Least
Surprise, POLS), mas a traduo literal de POLA Principle of Least Astonishment, em
portugusPrincpiodoMenorEspanto.OPOLAtilnaimplementaodemtodosefunes,e
tambmnodesigndeinterfacesdousurio.Aideiabembsica:implementar(mtodos/ui)de
forma com que interao e resposta no causem surpresa ao utilizador. O propsito no
abordar a arquitetura da informao e design de interfaces, mas aqui vai um exemplo de,
digamos,surpresanositedaSamsung:

ViolaodoPOLAnoprojetodeinterface

ConseguesveraviolaodoPOLA?Ento,medizquenopensastequeoemailera
invlidoparaocadastro?Poiseupensei.Naminhapercepo,pensoquefuiinduzidoaoerro

124

Captulo 4 Princpios de Projeto Orientado a Objetos

peloavisoestaremvermelho,quedizquemeuemailvlidoenovlido.fatocomprovado
queosusuriosnoleematelainteira,emvezdissoeles(incluindoeu)discernematravsde
formas,cores,posio,etc,soprincpiosbsicosde ArquiteturadaInformao50.Segostaste
destetemasugiroaleituradolivroNomefaapensar51dedeSteveKrug52.
Mas agora vamos ao ponto principal deste tpico, o POLA aplicado ao projeto e
implementaodemtodosefunes.Aprogramao,emsi,estcheiade,digamos,violaes
doPOLA.Vamosaumprimeiroexemplocomumaassertivasimples: 0.1 + 0.1 + 0.1 == 0.3,
correto?No.Dvidas?ExperimenteocdigoaseguirnoJava:
ClculosdePontoFlutuantetipicamenteviolamPOLA:
// surpreendentemente imprime false
System.out.println(0.1 + 0.1 + 0.1 == 0.3);
System.out.println(0.1 + 0.1 + 0.1); // imprime 0.30000000000000004

A maioria das linguagens apresenta este comportamento no clculo com nmeros


decimais e, bem, isto nem pode ser considerado um defeito, pois uma caracterstica de
implementaodoclculocomnmerosreaisusandoaaritmticadepontoflutuante 53.Contudo,
nomudaofatodasurpresa,eelapodeaumentarcasofaamosclculosdedinheiro,quepodem
darmuitoerrado54 equenoscausarammaissurpresaquandoonossoclientenonospagar
(desculpeohumornegro).
VamospensaremummtodoquevioleoPOLA.UmmtodoquerecebaumaStringe
convertaparainteiro.Aseguirumaimplementaoinicial:
MtodoqueconvertedeStringparaInteiro:
static int strToInt(String string) {
try {
return Integer.parseInt(string);
} catch (NumberFormatException nfe) {
return 0;
}
}
// situao de uso:
System.out.println(strToInt("3")); // imprime 3, ok!
System.out.println(strToInt("a")); // imprime 0, ok!
System.out.println(strToInt("2")

+ strToInt("3"));

// imprime 5, ok!

System.out.println(strToInt(" 2") + strToInt(" 3")); // imprime 0, como?

OnossomtodoesperaqueaStringcontenhaumanmerointeirosemespaosantesou
depois.Entretanto,aString" 2 "(comespaos)novaleria2damesmamaneiraque "2"(sem
espaos)?Espaossoimportantesnaconverso?Umoutroprogramadorqueutilizassenosso
mtodosaberiadeantemoqueteriaqueremoverosespaosantesdeconverter?Provavelmente
estaimplementaocausariasurpresanestasituaoeoutras,conseguesprever?
50

http://pt.wikipedia.org/wiki/Arquitetura_de_informao

51

http://www.livrariacultura.com.br/scripts/resenha/resenha.asp?nitem=2590021

52

http://www.amazon.com/SteveKrug/e/B001KHCFUU

53

NovemaocasonestelivromassequiseresinformaesvejanaWikipedia:
http://pt.wikipedia.org/wiki/Ponto_flutuanteounadocumentaodoPython:
http://docs.python.org/tutorial/floatingpoint.html

54

PorestemotivoprefiraBigDecimalparaclculosprecisos,comoDinheiro
125

Captulo 4 Princpios de Projeto Orientado a Objetos

Nosepreocupe,comumnopensaremtodosassituaesdeusoeprevertodasas
sadaspossveis.Seservedealento,vejaainstanciaodeDate:
ClasseDate,pssimoamigo:
Date data = new Date(2012, 03, 15);
System.out.println(data); // imprime "Mon Apr 15 00:00:00 BRT 3912", h?

Nomesmocontexto,vamostrabalharcomdatas,que umproblemanoJava,srio.
Vamosimplementarummtodoquefuncionebemquandopassamosoano,msedia.Vejaa
seguir:
MtodoparainstanciarDatasapartirdeinteiros:
static Date date(int ano, int mes, int dia) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, ano); calendar.set(Calendar.MONTH, mes);
calendar.set(Calendar.DATE, dia); return calendar.getTime();
}
// situao de uso:
System.out.println(date(2012, 03, 15)); // "Sun Apr 15 11:01:46 BRT 2012", bom!

Atagoratudobem.Masvamosimaginarumasituaodiferente.Digamosqueano,ms
ediavenhamdeumformulriowebcomcaixasdetexto:dia[]ms[]ano[],todoscom
doisdgitos.Jdevesterpassadoporumcadastrodestetipo.Parainstanciaradatanecessrio
receberosdadosdarequisio,ondetudoString,convertereminteiroeentoemdata,sendo
maisoumenoscomoaseguir:
Equandoascoisasnovemcomooesperado?
int ano = strToInt(request.getParameter("ano"));
int mes = strToInt(request.getParameter("mes"));
int dia = strToInt(request.getParameter("dia"));
// digamos que ano, mes e dia sejam, em inteiros,
// respectivamente: "82", "8" e "23"
Date dataNascimento = date(ano, mes, dia);
// pergunta de um milho de reais, quanto vale dataNascimento?
// ou: quanto deveria valer dataNascimento?

Concordas queo esperado a data 23/08/1982? Masno est claro no contratodo


mtodooqueretornaquandooanocomdoisdgitos.Mesmovaloressupostamenteinvlidos
podemnoserprevisveis,comoodia36,ms15,etc.Sparasaber,adatafica23/08/82,
ateno,82oano82DC,ouseja,seemoutracaixadetextoapareceaidadecalculada,entoo
sujeitotem1930anos:)
Para implementar funcionalidades concordantes com o princpio da menor surpresa
semprepergunteasimesmo:seoparmetroxforrecebido,oqueochamadoresperariaqueeu
devolvesse?
UmexemploaseguiralinguagemRuby.Matz,segundodizem,crioualinguagemcom
base no POLS (Principle of Least Surprise), tu podes ler nesta entrevista
http://akitaonrails.com/2006/10/09/entrevistacomyukihiromatsumotopartei. Ruby tem suas
126

Captulo 4 Princpios de Projeto Orientado a Objetos

crticas55, como todas asoutraslinguagens no consegue agradar gregos e troianos, mas no


chega a obscurecer a clareza e simplicidade da linguagem, por exemplo, o que esperas da
expresso"#" * 10?NoJavaseriaumerrodesintaxe,masnoRubymultiplicarumaStringcom
umInteiro,resultanareproduodoscaracteres,logo:
"#" * 10 == "##########"

Tem um vdeo excelente sobre o comprometimento (ou no) das linguagens com o
PrincpiodaMenorSurpresa.FoigravadoemumaminipalestradeGaryBernhardt,comottulo
WAT(alusoaWhat?!umqu?confusoesurpreso).Olinkparaovdeoestaqui,divirtase:
https://www.destroyallsoftware.com/talks/wat

ZeroOneInfinityRule(ZOI)
ZeroOneInfinity(zerouminfinito),ouZOI,umprincpiodeprojetocunhadopelo
pioneiroCientistadaComputaoWillemLouisvanderPoel.
Eleargumentaquenodeveserpermitidoqualquerlimitearbitrriodeinstnciasde
qualquerentidade.Emoutraspalavras,podeserquenosejapermitido(zero),ouumainstncia
sejapermitida(one),casocontrrioqualquernmerodeveserpermitido.
O propsito no assumirmos limites arbitrrios quando, de fato, o limite no
conhecido,emoutraspalavrasoualgonopermitido,oupermitidoapenasum,ouento
indefinido.
UmexemplodeviolaodesteprincpiopodeserconsideradonaestruturadeumHTML,
adicionandoolimitede,digamos,4096elementos.Olimitenuncaalcanado,porissomotivo
elenotrazdesvantagensimediatas,masemumfuturoprximopodesernecessriomaisde
4096elementosdentrodeumHTML,oquenoserpossveldevidoaolimitedefinido,limite
quenofarnenhumsentido(considerandoquehrecursossuficientesparaprocessarmaisde
4096elementos).
Outraformadepensar,outroexemplo:considerequenenhumargumentopermitido,
entodecidirmosiralmeaceitarumargumentoNemvezdenenhum,contudosedecidirmosir
maisalmepermitirN+1,entoporquenoN+2?N+3?Eassimpordiante?Nohdesculpa
parapermitirqualquerN,ouinfinitosN's.
ComooutraviolaodesteprincpioconsidereolimitedocomprimentodeumaURLno
InternetExplorer8de2083caracteres56.AregulamentaosegundoaRFC2616(Hypertext
TransferProtocolHTTP/1.1)diz:TheHTTPprotocoldoesnotplaceanyapriorilimitonthe
lengthofaURI.Maseventualmenteos browser podemoptarpornotratarURLs/URIsmuito
longas,estabelecendolimites.Mas,noseriamaissimplessenoprecisssemosficarpensando
emqualolimitedaquelebrowser...?
55

CrticasaoRubyvemdevriasfontesmasadvindamaisfrequentementededesenvolvedoresapaixonadosde
Python(Pythonistas)comoemhttp://madhadron.com/acriticismofrubye
http://peepcode.com/blog/2010/whatpythonistasthinkofruby,mastambmdealguns
descontentamentoscomoframeworkRubyonRailscomoemhttp://www.drdzoe.com/2007/06/13/a
criticismofruby/

56

Estelimiteumadordecabeaparaosdesenvolvedoresweb.Aespecificaopodeservistanestesite:
http://support.microsoft.com/kb/q208427
127

Captulo 4 Princpios de Projeto Orientado a Objetos

OprincpioZOIpodeseraplicadoemmtodos,argumentosdelinhadecomando,enfim,
qualquer alimentao de parmetros. Considere um exemplo simples de um container para
objetosdetamanhofixo(Bolsa)quedisponibilizeomtodoadiciona.Digamosqueaprimeira
versodestaclassedisponibilizeomtodoadiciona(Object):
ClasseBolsaemtodoadiciona(o):
public class Bolsa implements Iterable {
private Object[] objetos;
private int indice = 0;
public Bolsa(int tamanho) { objetos = new Object[tamanho];

public void adiciona(Object obj) { objetos[indice++] = obj; }


// ...
// situao de uso - adicionando duas Strings:
Bolsa bolsa = new Bolsa(10);
bolsa.adiciona("C#");
bolsa.adiciona("Java");
https://github.com/marciojrtorres/livroaps/tree/master/zoi

Veja que os objetos so adicionados um a um, entoconsidera a ideia de permitira


adiodedoisobjetosdeumasvez:
ClasseBolsaemtodoadiciona(o,o):
public class Bolsa implements Iterable {
private Object[] objetos;
private int indice = 0;
public Bolsa(int tamanho) {
objetos = new Object[tamanho];
}
public void adiciona(Object obj) {
objetos[indice++] = obj;
}
public void adiciona(Object obj1, Object obj2) {
this .adiciona(obj1);
this .adiciona(obj2);
}
// ...
// situao de uso - adicionando dois objetos de uma vez:
Bolsa bolsa = new Bolsa(10);
bolsa.adiciona("C#", "Java");
https://github.com/marciojrtorres/livroaps/tree/master/zoi

Aquesto :sepossoadicionar dois objetos de uma vez, por que no3? 4? n? a


premissadoZOInoaceitarargumentos,aceitarumargumento,ouentoinfinitos.Aseguiruma
implementaoconcordantecomoZOI:
128

Captulo 4 Princpios de Projeto Orientado a Objetos


ClasseBolsaemtodoadiciona(Object...):
public class Bolsa implements Iterable {
private Object[] objetos;
private int indice = 0;
public Bolsa(int tamanho) {
objetos = new Object[tamanho];
}
public void adiciona(Object obj) {
objetos[indice++] = obj;
}
public void adiciona(Object obj1, Object... objs) {
this .adiciona(obj1);
for (Object o : objs) {
this.adiciona(o);
}
}
// ...
// situao de uso - adicionando dois, trs ou n objetos de uma vez:
Bolsa bolsa = new Bolsa(10);
bolsa.adiciona("C#", "Java", "Python", "Ruby");
for (Object o : bolsa) { System.out.println(o); }
https://github.com/marciojrtorres/livroaps/tree/master/zoi

Nocrielimitesquenofaamsentido(mandamentodoZOI).

FailFastPrinciple
Naturalmente,osprogramadoresnoqueremqueseusprogramascaiam,desapareamna
frente do usurio. Contudo isto pode ser necessrio na maior parte das vezes, para que o
programanosigaoperandoemumestadoinvlido,ouseja,frequentementemelhorfazero
programacairdoquedeixlooperandodeformaincorreta,oquepodeaumentarosdanos.
OprincpiodeprojetoqueargumentaestaideiachamadodeFailFast,quesignifica
falherpido.Tantooconceitocomoimplementaosorealmentesimples,fazeroprograma
cairaodetectarumaoperaoilegal.
Comoumpequenoexemplo,considereummtodo(oufuno)querealizaoperaesde
somasobrenmeros.Poderiaserqualqueroperao,masnesteexemplovoutrazerasimples
adiodedoisnmeros:
Mtodoparasomardoisnmeros:
class Numeros {
public static int soma(int a, int b) {
return a + b;
}
}
// situao de uso:
int s = Numeros.soma(34, 23); // s == 57

129

Captulo 4 Princpios de Projeto Orientado a Objetos

Esta implementao parece funcionar bem, em vrios testes ela d um resultado


previsvelecorreto,massesomarmosquaisquernmerosquedcomorespostaumnmero
maiorque2147483647(ovalormximoaceitopelotipoINT)entoteremosumasurpresa:
Quandoaoperaoestincorreta:
class Numeros {
public static int soma(int a, int b) {
return a + b;
}
}
int s = Numeros.soma(1000000000, 2000000000); // deveria dar 3000000000 (3 bilhes)
System.out.println(s); // mas imprime -1294967296

EstetipodeerrochamadodeBufferOverflow 57.Quandoasomaultrapassarolimitedo
Inteiro,aconteceamudanadesinaleadiferenadevalor.Notequeestaoperaonocausa
falha,ouseja,seoprogramadependedesteclculoentoelerecebeovalorincorretoesegue
funcionando com base neste valor, provavelmente levando a mais operaes incorretas e
causandomaisdanos.
Este exemplo um candidato a aplicao do Princpio do FailFast, onde tentaremos
lanarumaexceosemprequeovalortransbordar(overflows).
bemsimples,semprequeforemsomadosdoisnmerospositivosentoarespostadeve
serpositivaeseforemsomadosdoisnmerosnegativosentoarespostadevesernegativa.O
mtodoseriaimplementadoassim:
ProtegendocontraBufferOverflowfazendoaaplicaocair(Exception):
class Numeros {
public static int soma(int a, int b) {
int r = a + b;
if (a > 0 && b > 0 && r < 0) throw new RuntimeException("BufferOverflow");
if (a < 0 && b < 0 && r > 0) throw new RuntimeException("BufferOverflow");
return r;
}
}
int s = Numeros.soma(1000000000, 2000000000);
// deveria dar 3000000000 (3 bilhes),
// mas daria -1294967296, logo se o resultado no correto
// ento o ideal lanar uma exceo e deixar o programa cair:
Exception in thread "main" java.lang.RuntimeException: BufferOverflow
at javaapplication556.Numeros.soma(Main.java: 58 )
57

BufferOverflowtambmumafalhaexplorada,ondecrackersouhackerspodemtentarlevarumprogramaa
causarumBufferOverflowecomissoabrirumabrechanosistemadesegurana.MaissobreBufferOverflow
podeserlidoaqui:http://pt.wikipedia.org/wiki/Transbordamento_de_dados
130

Captulo 4 Princpios de Projeto Orientado a Objetos

at javaapplication556.Main.main(Main.java: 17 )
Java Result: 1

Existe um excelente artigo sobre FailFast escrito por James Shore


(http://www.jamesshore.com/)disponvelaqui:
http://martinfowler.com/ieeeSoftware/failFast.pdf

Jamesdizquealgumaspessoasrecomendamfazerumsoftwarerobustoquecontornaos
problemaseresultanafalhagradativa.Isto,oprogramacontinuafuncionandoapsoerromas
acabafalhandomaisadiante,entretantodeumamaneiraestranha.Umsistemaquefalharpido
fazjustamenteocontrrio.Aspessoasrelutamemaplicarpoisfazparecerqueosoftwaremais
frgil,masjustamenteocontrrio.
Jimcolocaumexemploondeconsideradaaleituradeumapropriedadeemumarquivo
deconfigurao,epodeserqueapropriedadenoestejapresenteentodevolvidoumvalor
padro:
UmmtodoqueNOfalharpido(emC#):
public int maxConnections() {
string property = getProperty(maxConnections);
if (property == null) return 10;
else return property.toInt();
}

Emcontraste,ummtodoquefalharpidoseriaescritoassim:
UmmtodoqueFALHARPIDO(emC#):
public int maxConnections() {
string property = getProperty("maxConnections");
if (property == null) {
throw new NullReferenceException("maxConnections property not found in " +
this .configFilePath);
} else {
return property.toInt();
}
}

Escolherseasoperaesemumsistemadevemfalharouseguiroperandomesmocom
valores incorretos e resultados imprevisveis uma deciso de projeto importante. Cabe ao
desenvolvedoravaliarosriscosenvolvidoseutilizaramelhorestratgia.

FailSafe
[[]]

SeparaodeComando/Consulta(CQS)

131

Captulo 4 Princpios de Projeto Orientado a Objetos

Command Query Separation (Separao ComandoConsulta) [[texto a adicionar]]


[[avaliarnecessidade]][[http://martinfowler.com/bliki/CommandQuerySeparation.html]]

PrincpiodoMenorPrivilgio(PrincipleofLeastPrivilege)
Oprincpiodomenorprivilgiomuitoaplicadonareadeinfraestrutura.Oprincpio
alertaqueoacessoaqualquerrecursodeveseromaisrestritopossvel,emoutraspalavras,tudo
quenoexplicitamentepermitidodeveserproibido.Umexemplo,dareadeinfra,onvelde
acessodousurio.Seumusurioforcadastradocomonveldeacessoomitidoquepartesdo
sistemaeledeveriaacessar?Seguindooprincpio,todasasreassobloqueadasatinformar
quesoliberadas.Esseotipicofuncionamentodesistemasservidoresdedomnioeoutros
recursoscompartilhadoscomonoWindowsServeresistemas*nix(Linux,BSD,etc).
PrincpiodoMenorPrivilgio:numambientecomputacional,cadamdulopoderacessarsomente
asinformaeserecursosquesonecessriosparaseupropsitolegtimo

Naprogramaoesteprincpioseaplicaaescritadeclasses,seusatributosemtodos.
Segundooprincpio,todaclassedeveteracessodefault(dopacote)atquesejulguenecessrio
que ela seja pblica, cada atributo e mtodo deve ser privado at que surja um argumento
plausvelparatornlosdefault(dopacote)oupblicos.
EsteprincpioencorajaacriaodemdulosquetenhamumaAPImnima,ouseja,a
quantidadedeinformaespblicas,comoatributosemtodos,sominimizadas.
Acreditoquetodosqueleemesselivrojsabemqueasvariveissosempreprivadase,
senecessrio,sodisponibilizados mtodosacessores (getters e setters).Umoutroexemplo,um
poucomaiscomplexo,aimplementaodeumaclassequelidacomnotificaes,caixasde
mensagem,deentrada,dilogosemgeral,maisoumenoscomoaseguir:
Lidandocomcaixasdedilogo:
import javax.swing.JOptionPane;
import static javax.swing.JOptionPane.*;
public class Dialogo {
public static void aviso(String mensagem) {
showMessageDialog(null, "Aviso", mensagem, INFORMATION_MESSAGE);
}
public static void erro(String mensagem) {
showMessageDialog(null, "Erro", mensagem, ERROR_MESSAGE);
}
}

Deu para ver que ela bem simples, eu poderia mostrar um aviso assim
Dialogo.aviso("Login OK").Mas,humdetalherelacionadoaonveldeacesso.Odilogouma
funcionalidaderelacionadaainterfacedeusurioesomentedeldeveriaserinvocada,ouseja,
o princpio arquitetural de que cada camada acessa as camadas inferiores mas as camadas
inferioresnoacessamassuperiores.Contudo,umaclassedodomnio,quedeveriaserignorante
dainterfacedousurio,poderiainvocarumaviso:

132

Captulo 4 Princpios de Projeto Orientado a Objetos


AtondeaclasseDialogodeveriaseracessvel:
public class Cliente {
// ... atributos, getters e setters
public void sendMail(String texto) {
// classe de domnio usando interface do usurio? NUNCA FAA ISSO
if (email == null) Dialogo.aviso("cliente no tem e-mail");
// ... cdigo para enviar e-mail

Asclassesdedomnioepersistncianodevemutilizarclassesdeinterfacedousurio.J
pensouseumdiaosistemamudaparaumainterfaceweb,comovaiusarum JOptionPane?O
corretoasclassesdedomnioepersistncialanaremexceesadequadasaoseunvelena
apresentaotratadocomoasexceesseroexibidasparaousurio.Umaimplementao
maisadequadaapareceaseguir:
ClassesdoDomnioePersistncianodevemteracessoaclassesdaApresentao:
public class Cliente {
// ... atributos, getters e setters
public void sendMail(String texto) {
if (email == null) {
throw SemEmailException("O cliente no possui e-mail");
}
// ... cdigo para enviar e-mail
// ...
public class JanelaCadastroCliente extends JFrame {
// ... comportamento padro da janela
// ... em algum mtodo de ao de um boto
try {
cliente.sendMail(CONVITE);
} catch (SemEmailException e) {
Dialogo.aviso("Cliente no possui endereo cadastrado");
}
// ...

Claroqueestediscernimento,deondeinvocarquaisclassesemtodos,ficanobomsenso
doprogramador.Poroutrolado,tupodes,digamos,coibiroudirecionarodesenvolvimento,o
queseriaoinciodeumframework.Vamosaograndefinal:euqueropermitiroacessoaclasse
Dialogo apenas pela as classes relacionadas a interface do usurio. Classes de domnio e
persistncianoteroacessoaclasseDialogo.Como?Assim:
Restringindooacessoeaplicandooprincipiodomenorprivilgio:
package br.com.company.apresentacao; // importante definir o pacote
import javax.swing.JOptionPane;
import static javax.swing.JOptionPane.*;
class Dialogo { // note a ausncia do escopo public na classe e nos mtodos
static void aviso(String mensagem) {
showMessageDialog(null, "Aviso", mensagem, INFORMATION_MESSAGE);

133

Captulo 4 Princpios de Projeto Orientado a Objetos

}
static void erro(String mensagem) {
showMessageDialog(null, "Erro", mensagem, ERROR_MESSAGE);
}
}

Com esta implementao a classe Dialogo e seus mtodos no so visveis fora do


pacote br.com.company.apresentacao. Paraseguiroprincpiodomenorprivilgiosempre declare
suasclassescomo default (privadodopacote), sem o public,seusmtodosevariveiscomo
privadosoudefault.Usepublicsseforjustificado(judiciosamente).

PrincpiodaResponsabilidadenica(SRP)
[[melhorar esta seo]]
O Single Responsibility Principle (Princpio da Responsabilidade nica) um dos
princpios mais importantes no Projeto Orientados a Objetos (OOD). A mxima do SRP foi
cunhadapeloTioBob[MARTIN]efazpartedeumasriadeartigossobreOODchamadosde
SOLID.SRPoSdeSolid.Amximaesta:
PrincpiodaResponsabilidadenica:nuncadeverhavermaisdeumarazoparaumaclasse
mudar

Oconceitoderesponsabilidadeassociadoarazoparamudar,ouseja,seumaclasse
temmaisdeumarazoparamudareladevetermaisdeumaresponsabilidade.Opropsito
principaldoSRPdecomporasfuncionalidadesparaproporcionarreusoefcilmanuteno.
Comoexemplo,imagineumaclassequecompilaeimprimeumrelatrio,entoestaclassetem
duasrazesparamudar,primeiroporqueocontedodorelatriopodemudar,segundoporque
oformatodorelatriopodemudar.Umoutroexemplo,queserexibidoocdigoaseguir,
casoeutenhaumaclassedeleituraeexibiodatemperaturaeumidaderelativadoarapartir
deumsensor,seaclasseresponsvelporapresentarosdadosecomunicarsecomosensor,
entoelatemduasrazesparamudareduasresponsabilidades:
Classecommaisdeumaresponsabilidade
import net.umed.hardware.Sensor;
public class MonitorTemperaturaUmidade {
private int temperatura;
private int umidade;
private Sensor sensor = new Sensor(Porta.COM4, "e3a456f789ea4b3345a32");
public static void main(String[] args) throws Exception {
new MonitorTemperaturaUmidade().run();
}
private void run() {
while (true) {
Thread.sleep(1000);
// digamos que a temperatura lida pelo sensor

134

Captulo 4 Princpios de Projeto Orientado a Objetos

// seja retornada de fahrenheit para celsius


int templida = (int) ((sensor.readTemp()) - 32 / 1.8);
int urlida = sensor.readRU();
if (templida != temperatura) {
temperatura = templida;
show();
}
if (urlida != umidade) {
umidade = urlida;
show();
}
}
}
private void show() {
System.out.println("Temperatura: " + temperatura + " C");
System.out.println("Umidade relativa: " + umidade + "%");
}
}

Aclassedoexemplotemmaisdeumaresponsabilidade.Emboraelafuncionebem,como
umaimplementao adhoc elaseapoianaspremissasdequeatemperaturaeumidadeso
sempreexibidasnoconsoleenesteformato,oSensorestnaCOM4etemumachavedeacesso,
doismtodosfazem aleitura,a temperatura lida emFahrenheit (precisadeconverso), o
intervalodeatualizaodeumsegundo.Sequalquerumdestascaractersticasmudaraclasse
terdeseralterada,violandoassimoSRP.
Oidealseriaqueelaapenasinicializasseoutrasclassescomresponsabilidadesdefinidas,
umaclasseparaapresentarainformao,outraparainteragircomosensor,outraparaconverter
temperaturaeumaoutraparaorquestrarotempo.
[[talvezincluirocdigorefatoradoeconcordantecomoSRP]]
ParaaderiraoSRPsempreanalisesuasclassesevejaseelatemmaisdeumarazopara
seralterada.Mas,importantefazerumaressalva,nestasrazesnoseiincluipropriedades,ou
seja,atributosmaismtodosacessores.
OartigoescritopeloTioBobestaqui:
http://www.objectmentor.com/resources/articles/srp.pdf

PrincpiodoAcessoUniforme(UAP)
O Uniform Access Principle, em portugus Princpio do Acesso Uniforme, teve seu
"mandamento"cunhadoporBertrandMeyer58,criadordalinguagemdeprogramaoEiffel59e
escritordoaclamadolivroObjectOrientedSoftwareConstruction:
http://www.amazon.com/gp/product/0136291554

58
59

MaisinformaesarespeitodoilustreBertrandMeyerhttp://en.wikipedia.org/wiki/Bertrand_Meyer
http://en.wikipedia.org/wiki/Eiffel_(programming_language)
135

Captulo 4 Princpios de Projeto Orientado a Objetos

PrincpiodoAcessoUniforme:todososservios(mtodos)oferecidosporummdulo(classe)devem
estardisponveisatravsdeumanotaouniforme,quenorevelaseelessoimplementadospor
meiodearmazenamentooucomputao

O UAP especialmente aplicvel a Value Objects, mas tambm pode ser aplicado a
objetos"normais".Nocomplicadodeimplementlo,altamenteligadoaoencapsulamento.
Porexemplo,podemosteremumaclasseClienteatributoscomoidadeedatadenascimento.O
pontoquesabendoadatadenascimentoaidadepodesercalculada.Atentaoinicialter
acessores(get/set)paradataNascimentoeummtodocalculaIdade,ERRADO!Oprincpionorteia
que deve ter uma notao uniforme, ou seja, se eu uso get/setDataNascimento tambm
disponibilizogetIdade,emconformidadecomanotaouniforme.
Partindoparaumexemplomaisprtico,comovistoemSRP,pensenaimplementaoda
representaodeTemperatura.Atemperaturapodeserrepresentadaem3unidadesbsicas:
Celsius(C),Fahrenheit(F)eKelvin(K).Umprogramadorsemconhecimentodeprojetopode
pensar em armazenar a temperatura nas 3 unidades, contudo no necessrio, na verdade
usamosumaunidadeparaarmazenamentointerno,tipicamenteamaiscomumoumaissimples
easdemaissoresolvidasporclculo.Quemutilizaraclasseteracessoas3unidadesmasno
sabercomoosvaloressoarmazenadosouobtidos,eisoprincpioaplicado:
ClasseTemperaturaimplementadacomoValueObjectmutveleconcordantecomoUAP:
class Temperatura {
private double celsius;
// construtores privados
private Temperatura() { this.celsius = 0.0; }
private Temperatura(double celsius) { this.celsius = celsius; }
// mtodos fbrica
public static Temperatura celsius(double celsius) {
return new Temperatura(celsius);
}
public static Temperatura fahrenheint(double fahrenheit) {
Temperatura temp = new Temperatura();
temp.setFahrenheit(fahrenheit);
return temp;
}
public static Temperatura kelvin(double kelvin) {
Temperatura temp = new Temperatura();
temp.setKelvin(kelvin);
return temp;
}
// acessores
public void setCelsius(double celsius) { this.celsius = celsius; }
public void setFahrenheit(double fahrenheit) {
// eis o segredo, internamente armazenado em celsius
this .celsius = (fahrenheit - 32) / 1.8;
}

136

Captulo 4 Princpios de Projeto Orientado a Objetos

public void setKelvin(double kelvin) {


// outra vez, armazenado em celsius
this .celsius = kelvin - 273;
}
public double getCelsius() {
return this .celsius;
}
public double getFahrenheit() {
// convertido e retornado
return this .celsius * 1.8 + 32;
}
public double getKelvin() {
// convertido e retornado
return this .celsius + 273;
}
}
// situao de uso:
Temperatura temp = Temperatura.kelvin(300);
System.out.println(temp.getCelsius()); // imprime 27.0
System.out.println(temp.getFahrenheit()); // imprime 80.6

Ousuriodocdigo,isto,outrodesenvolvedor,senoolhaocdigofontedaclasse
Temperatura,nosaberseosmtodos get/set Celsius/Fahrenheit/Kelvin soarmazenadosou
computados. ParaconcordarcomoUAPdisponibilizemtodosuniformes,noJavatipicamente
get/set,pararepresentarainformao,escondendoseelaarmazenadaoucomputada.

Deixesimplesbundo:YAGNI,KISS,POGE,emessncia,amesmacoisa
PrincpiodaPerfeio
Parece que a perfeio alcanada no quando no resta
nadaaadicionar,masquandonorestanadaaremover
AntoinedeSaintExupry60

YouAintGonnaNeedIt,emportugusVocAindaNoPrecisaDisto,dizrespeitoa
saberquandoparar,ouseja,implementaroquenecessriopararesolveroproblema.YAGNI
noumprincpioparacriarcdigoadhoc,pelocontrrio,ocdigoeleganteebemprojetado
encorajado,oquenoindicadoainclusodefuncionalidadesdesnecessrias.
RonJeffries,consultorrespeitadoeumdosfundadoresdoeXtremeProgramming,diz:sempre
implementecoisasquandovocrealmenteprecisardelas,nuncaquandovocacaboudepreverque
precisardelas

ComoexemploutilizemosaindaoproblemadaTemperatura.Aindapossvelrepresent
laemgrausRankine(Rk),Raumur(R),Newton(N),Rmer(R)eDelisle(D).Masseria

60

http://pt.wikipedia.org/wiki/Antoine_de_SaintExupry

137

Captulo 4 Princpios de Projeto Orientado a Objetos

interessanteimplementarestasunidadeseseusclculosdeconversonaclasseTemperatura?
Talvezno.TalveznemmesmoKelvinsenoconstassenalistadefuncionalidades.
Cadapeadefuncionalidadedevesertestada,documentadaeleva,claro,tempopara
implementar.SoargumentossuficientesparajustificaroYAGNI,prticausadanoXPquetem
simplicidadecomoumdeseusvalores.
YAGNI tambm conhecido na comunidade Unix como KISS, acrnimo de Keep It
SimpleStupid (deixesimplesmenteidiotaemumatraduolivre)eemoutrosnichoscomo
POGE, acrnimode PrincipleofGood Enough,emportugus:PrincpiodoSuficientemente
Bom.
KISS foi proposto por Kelly Johnson e muitas pessoas traduzem de "Keep It Simple,
Stupid", o que significa "Deixe Simples, Idiota". Segundo a histria, no bem isso, na
wikipedia,eminglstemtimoartigosobreohistriadoacrnimo:
http://en.wikipedia.org/wiki/KISS_principle

ToyotismoesuarelaocomYAGNI,KISSePOGE
Ainda,YAGNI,KISSePOGEsocomumenteassociadosaoToyotismo61 noaspectodo
sistemaJustInTime62,ouseja,incentivaaproduoenxutaouconhecidocomoLean.Boaparte
dasprticasexistentesnosmodelosgeisdedesenvolvimentoincentivamoLeaneh,inclusive,
umbomlivrosobreotema: ImplementandooDesenvolvimentoLeandeSoftware,deMarye
TomPoppendieck.SugirodarumalidanositedoVincius,aqui:
http://improveit.com.br/xp/valores/simplicidade

OLivrosobreDesenvolvimentoLeanpublicadopelaeditoraGrupoA:
http://www.grupoa.com.br/livros/engenhariadesoftwareemetodosageis/implementandoo
desenvolvimentoleandesoftware/9788577807567

PrincpioAberto/Fechado(OCP)
OPrincpioAberto/Fechado,Open/ClosePrincipleemingls,foipropostopeloTioBob,
DavidMartin,quebuscaincentivaroprojetodesistemasdeformaconscientedasmudanasque
viro. OCP integrante da srie SOLID. A descrio do princpio, no entanto, vem de uma
declaraodeBertrandMeyer,em1988:
PrincpioAberto/Fechado:entidadesdesoftware(classes,mdulos,funes,etc)devemestarabertos
paraextenso,masfechadosparamodificaoBertrandMeyer

Estaheursticatentaevitarsintomascomunsdeprojetosruins,comofragilidade,rigidez,
imprevisibilidade e noreusabilidade. O foco do OCP bem simples, direcionado a projetar
mdulosquenosoframmudanas,ento,quandomudaremosrequisitos,tuadicionascdigo
paraestenderafuncionalidadedomdulo,masnuncaalteraocdigoquejfunciona.
SegundoRobertMartin[MARTIN],achaveaabstrao.Ummdulopodeestarsempre
fechado para modificao se depender de abstraes. Assim, sempre possvel estender a
61
62

ModeloEnxutodeProduo:http://pt.wikipedia.org/wiki/Toyotismo
TambmassociadoaoModeloToyota:http://pt.wikipedia.org/wiki/Just_in_time
138

Captulo 4 Princpios de Projeto Orientado a Objetos

funcionalidade ou alterla se o mdulo depender de abstraes. Este princpio, geralmente,


resulta na aplicao prtica das heursticas: Programe para uma Interface, no uma
implementaoePrefiraComposioaHerana.
Para compreender melhor vamos utilizar um exemplo. Imagine que estejamos
implementandoumeditordetextoonline,comooGoogleDocs,dadaaproporoclaro,que
permita incluir texto e operar sobre ele, como alterar fonte, tamanho, localizar palavras,
substituir e verificar ortografia. Vamos nos concentrar na verificao de ortografia. Eu vou
simplificarumpoucoparaoexemplonoficarmuitoextenso,entotudoserrealizadoemuma
classeTexto:
ClasseTexto,umrecipienteparaocontedo
public class Texto {
private StringBuilder conteudo;
public Texto() { conteudo = new StringBuilder(); }
public void addTexto(String texto) { conteudo.append(texto); }
@Override
public String toString() {
return conteudo.toString();
}
}

Aclasseestbem,bemsimplesmesmo.Faltaimplementaraverificaodeortografia.A
seguirummtodoverificaOrtografiaqueretornaumalistadepalavrasincorretasencontradasno
texto:
Adicionandoaverificaoortogrfica
public class Texto {
private StringBuilder conteudo;
public Texto() { conteudo = new StringBuilder(); }
public void addTexto(String texto) { conteudo.append(texto); }
@Override
public String toString() {
return conteudo.toString();
}
public List verificaOrtografia() {
List palavrasIncorretas = new ArrayList();
List palavrasCorretas = new ArrayList();
String[] palavrasNoTexto = conteudo.toString().split("\\s");
try {
InputStream inputStream = this.getClass().getResourceAsStream("palavras");
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader reader = new BufferedReader(inputStreamReader);
String linha = null;

139

Captulo 4 Princpios de Projeto Orientado a Objetos

while ((linha = reader.readLine()) != null ) {


Collections.addAll(palavrasCorretas, linha.split("\\s"));
}
reader.close();
inputStreamReader.close();
inputStream.close();
} catch (Exception ex) {
ex.printStackTrace();
}
for (String palavra : palavrasNoTexto) {
if ( ! palavrasCorretas.contains(palavra)) {
palavrasIncorretas.add(palavra);
}
}
return palavrasIncorretas;
}
}

Noaindaodesejado,masfunciona,aseguirumasituaodeuso:
SituaodeusodaclasseTextoeverificaoortogrfica
Texto texto = new Texto();
// todas estas palavras esto cadastradas:
texto.addTexto("exemplo de um documento de texto");
// imprime [], ou seja, no h erros.
System.out.println(texto.verificaOrtografia());
// introduzindo erros:
texto.addTexto("exeplo de um docunento de texto");
// imprime [exeplo, docunento]
System.out.println(texto.verificaOrtografia());

Tudofunciona,qualoproblema?AclasseviolaoOCPquandoloarquivocomas
palavras,nodemonstrandoumexemploclarodedecomposiodefuncionalidades.
Ataquideveterficadoclaroquetratamosdeproblemasdeprojetobemmaisquede
programao.Esteexemplodeixaclaroqueumcdigobemprogramadononecessariamente
bemprojetado.
Saibaentenderadiferenaentreprogramareprojetar,algunscdigospodemserbemprogramados
emauprojetados

A palavrachave essencial que norteia o projeto mudana. Digamos que um novo


requisitofoiintroduzido,averificaoortogrficaemingls,efuturamenteesperamseoutras
lnguas.Comoimplementarestanovafuncionalidade?Claramenteteremosquealteraraclasse
Textoeomtodo verificaOrtografia,ouseja,elanoestfechadaparamodificaoeviolao
OCP.

140

Captulo 4 Princpios de Projeto Orientado a Objetos

Para que este projeto esteja de acordo com o OCPteremosqueseparar averificao


ortogrfica do gerenciamento do contedo, o texto. Mas como permitir que a verificao
ortogrficasejafeitaemvriosidiomas?Primeiro,vamossepararaaverificaoortogrfica:
SeparandoaverificaoortogrficadaclasseTexto
public class Texto {
// ...
VerificadorOrtografico verificador = new VerificadorOrtografico();
public List<String> verificaOrtografia() {
List<String> palavrasIncorretas = verificador.verifica(conteudo.toString());
return palavrasIncorretas;
}
}
// classe VerificadorOrtografico
public class VerificadorOrtografico {
public List<String> verifica(String texto) {
List<String> palavrasCorretas = new ArrayList<String>();
List<String> palavrasIncorretas = new ArrayList<String>();
String[] palavrasNoTexto = texto.split("\\s");
try {
InputStream inputStream = this.getClass().getResourceAsStream("palavras");
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader reader = new BufferedReader(inputStreamReader);
String linha = null;
while ((linha = reader.readLine()) != null ) {
// carregando as palavras do dicionrio
Collections.addAll(palavrasCorretas, linha.split("\\s"));
}
reader.close();
inputStreamReader.close();
inputStream.close();
} catch (Exception ex) {
ex.printStackTrace();
}
// comparando e separando as incorretas:
for (String palavra : palavrasNoTexto) {
if ( ! palavrasCorretas.contains(palavra)) {
palavrasIncorretas.add(palavra);
}
}
}
}

A responsabilidade foi dividida, mas no muda a necessidade de alterar a classe


VerificadorOrtograficoparaincluirnovosidiomas,outalvezincluirumaopoparaselecionaro
idioma, etc. Existe uma dependncia clara entre as classes Texto e VerificadorOrtografico. O
projetoaindanoestconformeoOCP.Paraadequlo,oprimeiropassofazeraclasseTexto
depender de uma abstrao no de uma implementao. s pensar no que qualquer

141

Captulo 4 Princpios de Projeto Orientado a Objetos

verificador ortogrfico, independente do idioma, deve fazer para a classe Texto, neste caso,
receberumaStringedevolverumalistadepalavrasincorretasdestaString.Vamosprojetar:
Introduzindoumaabstraocomousodeumainterface
public class Texto {
// ...
IVerificadorOrtografico verificador;
public List<String> verificaOrtografia() {
List<String> palavrasIncorretas = verificador.verifica(conteudo.toString());
return palavrasIncorretas;
}
}
public interface IVerificadorOrtografico {
List<String> verifica(String texto);
}

isso,simplesassim,masfaltapoucoparafuncionar.Aclasse Texto agoradependede


umaabstrao,oqueseriaum VerificadorOrtografico agoraidentificadocomumainterface
(porissooprefixo"i"emIVerificadorOrtografico63).Vamosfazerassim:porpadrovamosusar
o verificador em portugus e dar a opo de trocar o verificador. Para isso teremos de
implementarainterfaceeimplementarumverificadorconcreto 64:
Adicionandoumverificadorconcreto
public class Texto {
// ...
// podemos usar por padro o verificador em PT_BR
IVerificadorOrtografico verificador = new VerificadorOrtograficoPTBR();
// para alterar o verificador podemos setar outra classe concreta:
public void setVerificador(IVerificadorOrtografico novoVerificador) {
this .verificador = novoVerificador;
}
public List<String> verificaOrtografia() {
List<String> palavrasIncorretas = verificador.verifica(conteudo.toString());
return palavrasIncorretas;
}
}

public class VerificadorOrtograficoPTBR implements IVerificadorOrtografico {


public List<String> verifica(String texto) {
// ... cdigo de leitura do dicionrio pt-br e verificao
}
}

Agora sim, o projeto est aberto para extenso e fechado para modificao. Vamos
colocarocasodeadicionarumdicionrioenUS:
63

64

NoumaprticacomumnoJavausaroprefixo"i"parainterfaces,naverdadeumaprticadoC#.NETqueeu
trouxeparaestecdigocomopropsitodetornlomaisexplicativo
Classesconcretassoaquelasquenosoabstratas,emoutraspalavras,soclassesquenotemapalavrachave
abstractnonomeequetambmnosointerfaces.
142

Captulo 4 Princpios de Projeto Orientado a Objetos


AdicionandooverificadoreminglssemalteraraclasseTexto
// deve seguir o contrato da abstrao
public class VerificadorOrtograficoENUS implements IVerificadorOrtografico {
public List<String> verifica(String texto) {
// ... todo o cdigo de verificao
}
}
// situao de uso:
Texto texto = new Texto();
// introduzindo erros:
texto.addTexto("exeplo de um docunento de texto");
// esta parte importante, incluindo o suporte a verificao em
// ingls:
texto.setVerificadorOrtografico(new VerificadorOrtograficoENUS());
System.out.println(texto.verificaOrtografia());
// imprime [exeplo, de, um, docunento, de, texto], afinal est em ingls

Agora eu posso adicionar novos verificadores em novos idiomas ou que usem outras
tcnicasmaiseficientesdeverificaosemalteraraclasseTexto.IstoOCP.
Comojfoifalado,oOCPfortementebaseadonadependnciadeabstraes,oque
implicanadeclaraodeinterfaces(noJava)eclassesabstratas.Outraslinguagenstemoutras
formas de aplicar este princpio, em especial linguagens que implementem o paradigma de
programao funcional. No Java, extremamente importante que o programador ou
desenvolvedorentenda"arazodeexistir"dasinterfacesesaibaapliclas.
OartigodotioBob[MARTIN]sobreOCPestaqui:
http://www.objectmentor.com/resources/articles/ocp.pdf

PrincpiodoReusoComum(CRP)
Common ReusePrinciple (PrincpiodoReusoComum) umprincpiobem simples,
relativamentefcildeserentendidoedesercolocadoemprtica.
Um software , tipicamente, composto de vrias classes, havendo a necessidade de
agruplasporassuntooutipodeproblemaqueresolvem.Estadivisofeita,noJava,com
pacotes (packages) e, por exemplo, em C++, ActionScript e C# com namespaces 65. Ento,
quandocriamosumaclasse,decidimosemquepacote(ounamespace)devemoscolocla,e
nestadecisoqueusamosoCRPcomoguia.AheursticadoCRPaseguir:
PrincpiodoReusoComum:asclassespresentesemumpacotesoreusadasjuntas,sevocreusa
umadasclassesdessepacote,entovocreusatodas.

65

ExistenteatnalinguagemPHP(5.3emdiante)
143

Captulo 4 Princpios de Projeto Orientado a Objetos

Opropsitodoprincpioencorajaracriaodequantospacotesforemnecessriospara
agruparclassesquefaampartedeummesmocontexto.Emumexemplosimples,considereque
estamosdesenvolvendoumsistemadecontrolededvidasepagamentos.Emcertomomento
temosquelidarcomarredondamentosecriamosumaclasseparalidarcomnmerosemum
pacotechamadoutil:
br.com.empresa.util.Numero

Estepacotedeutilidadescresceconformenovasfuncionalidadessorequeridas,podemos
terutilitrioparaStrings,Datas,etc,entoopacotecresce:
br.com.empresa.util.Numero
br.com.empresa.util.Strings
br.com.empresa.util.Data

Novasfuncionalidadesaparecem,comolidarespecialmentecomhoraseaplicarjuros,
mas onde ficam estas classes? A classe Hora poderia ficar claramente no mesmo util,
entretantopoderamosespecializarolocaldeDataeHoracomotempo,assim:
br.com.empresa.util.tempo.Data
br.com.empresa.util.tempo.Hora

Eoclculodejuros?Bem,umaclasseTaxapoderiasercolocadaemutil,masserque
ficariadentrodeumcontexto?Pense,seestoudesenvolvendoagoraumsistemadelancheria,e
precisodearredondamentodevalores,bem,euimportariaopacote br.com.empresa.util,ecom
isso, as classes que vem nele: Numero, Strings, Data e Taxa? Conseguiu captar? Taxa est
descontextualizado,nosentidodequemprecisalidarcomtiposcomonmeros,stringsedatase
horasnecessariamentenoprecisarialidarcomTaxas.
Considereoutroexemplo,contrriodoanterior:construirumsoftwaredeinterfacerica
paraumterminaldeacessoparaocliente,ondesocalculadosjuros.Ondeest Taxa?Juntocom
nmeros,stringsedatas.
Sugestominha,mastalvez Taxa ficassemelhoremumpacoteparaleloao util,como
br.com.empresa.financeiro.Taxa

Um detalhe importante, que estes pacotes podem ser implementados em projetos


diferentes,gerandobibliotecasseparadas(noJavaarquivos .jar,noC#arquivos .dll),oque
trariaavantagemdeatualizarouresolverqualquerbugapenassubstituindooarquivo(jarou
dll).
DigamosqueTaxa estivesseemutil quedisponibilizadocomoumjarutil-1.0.1.jar,e
ento tenhamos que modificar Taxa para resolver um bug, compilar e redistribuir o projeto
(pacote).Poderiaserquevriosprojetosquesoconstrudoscomadependnciadoprojetoutil
tenhamqueserredistribudos,recompilados,semnemaomesmousaraclasse Taxapresenteem
util.
Pacotes,oumelhor,projetosquepodemserincludosemoutrosprojetos(bibliotecasjar,
dll,etc),quesomuitosgrandesepossuemmuitasclasses,podemserumaspectonegativo.Se

144

Captulo 4 Princpios de Projeto Orientado a Objetos

eutenhoumprojetoquepreciseapenas,porexemplo,lidarcomTempo,porqueeuincluiriaum
jaroudllcomcentenasdeclassesutilitrias?
Adependnciadebibliotecascommuitosmdulos(classes)poucocontextualizadospodetrazero
malefciodaatualizaodesnecessria,almdeconsumodesnecessriodeespaoemdiscoe
memria

Foramcolocadasapenasalgumasdasvantagensdedividirempacoteseprojetosmenores
edesvantagensdeusarpacoteseprojetosmuitograndes.Saibatambmquedividirdemaispode
levaraproblemasdegerenciamentodocontedo,aopontoatdenoencontraroqueprocurae
acabarcriandooutravezumaclasse,gerandoduplicaeseretrabalho.

PrincpiodaSubstituiodeLiskov(LSP)
LSP acrnimo de Liskov Substitution Principle, em portugus "Princpio de
SubstituiodeLiskov".Onomedoprincpioderivadode estudosepesquisasde Barbara
Liskov66,quegraduadaemmatemticaedoutoraemcinciadacomputao.Oprincpio
ligadoaorientaoaobjetosnoquedizrespeitoasubstituibilidade.LSP integrantedasrie
SOLID.
Substituibilidadeumprincpiobsicoemorientaoaobjetos.Afirmaqueseeutenho
umsubtipoSdeumtipoT,entoobjetosdotipoTpodemsersubstitudosporobjetosdotipoS
semalterarpropriedadesessenciaisdefuncionalidadeecorretude.
Ostiposesubtipos,noJava,sorepresentadosporclassesesubclasses.Emumexemplo
simples,querdizerqueseeutenhoumaclasseAnimalesubclassescomoGato,Cachorro,etc,
ondehouver ummtodoouvariveldotipoAnimal,qualquersubtipo(Gato,Cachorro,etc)
podemserinseridoscomoargumento,enfim,GatoumAnimal.
Todosdevemconhecerateoriaeprticadesubclassificao,fundamentalemPOO.O
queBarbaraLiskoveseuprincpioadicionamumadendonarelaodetipoesubtipochamado
subtipagemcomportamentalforte(strongbehavioralsubtyping).OLSPdeterminaque:
PrincpiodeSubstituiodeLiskov:seq(x)umapropriedadedemonstrveldosobjetosxdetipoT.
Entoq(y)deveserverdadeiroparaobjetosydetipoSondeSumsubtipodeT

RobertMartinreescreveessemesmoprincpiodeformamaissimples:
RobertMartindiz:funes(mtodos)queusamponteiros(referncias)declassesbasedevempoder
usarobjetosdeclassesderivadassemconheclas

OmesmoRobertMartin(TioBobcomoseautointitula)demonstranessefamosoartigo
http://www.objectmentor.com/resources/articles/lsp.pdfumaviolaosegundoasuainterpretao
deLSP.OcdigofoiescritoemC++epodeservistoaseguir:
TpicaviolaodoLSP,omtodoconheceassubclasses
void DrawShape(const Shape& s) {

66

http://en.wikipedia.org/wiki/Barbara_Liskov

145

Captulo 4 Princpios de Projeto Orientado a Objetos

if (typeid(s) == typeid(Square)) {
DrawSquare(static_cast <Square&>(s));
} else if (typeid(s) == typeid(Circle)) {
DrawCircle(static_cast <Circle&>(s));
}
}

SegundooLSP,afuno DrawShape (desenharfigura),quedependeumponteiropara


Shape(figura),nodeveriaconhecerassubclassesdeShape.Noexemplonooqueacontece,
o corpo da funo faz coero de tipos para Square (quadrado) e Circle (crculo). O que
aconteceriasemaistiposdefigurasfossemincludos,comoLosango,Tringulo,etc?Com
certezatornariaseuminfernodeifseelses.
Outrasviolaes,maissutis,usadaspontualmentecomoexemplos,soos problemas:
crculo/elipseequadrado/retngulo.Oproblemaquadrado/retngulo,quevouilustrar,diz
respeitoateoriadequetodoquadradoumretngulo.Qualquerum,baseadonaspropriedades
essenciaisdequadradoeretngulo,afirmariaquetodoquadradoumretnguloequenemtodo
retnguloumquadrado.Implementarestestiposimplicariaemcriarumaclasse Retanguloe
umaclasseQuadradoqueestendeRetangulo,tendoemmentequequadrado,comoretngulo,
tempropriedadesdelarguraealturacomadiferenadealarguraealturaseremsempreas
mesmas.Vamosimplementaresteexemplo:
ProblemaQuadrado/Retangulo,umaviolaodoLSPmaisdifcildevisualizar
public class Retangulo {
protected int largura, altura;
public int getLargura() { return largura; }
public void setLargura(int largura) { this.largura = largura; }
public int getAltura() { return altura; }
public void setAltura(int altura) { this.altura = altura; }
}
// como quadrado um retngulo ele herda as propriedades de largura
// e altura, entretanto h a regra de igualdade de largura e altura
public class Quadrado extends Retangulo {
@Override
public void setLargura(int largura) {
this .largura = largura;
this .altura

= largura;

}
@Override
public void setAltura(int altura) {
this .altura

= altura;

this .largura = altura;


}
}

146

Captulo 4 Princpios de Projeto Orientado a Objetos

Estaimplementaoparecefuncionarperfeitamente.Vejaaseguirumasituaodeuso:
SituaodeusodasclassesRetanguloeQuadrado
Retangulo r1 = new Retangulo();
Retangulo r2 = new Quadrado();
// imprime 200x300, perfeito
r1.setLargura(200); r1.setAltura(300);
System.out.println(r1.getLargura() + "x" + r1.getAltura());
// imprime 300x300, perfeito
r2.setLargura(200); r2.setAltura(300);
System.out.println(r2.getLargura() + "x" + r2.getAltura());

Narefernciar2,paraumquadrado,alarguraealturadevemsersempreasmesmas.A
alturade300foialtimaserdefinida,entoredefiniutambmalargurapara300.Ataquitudo
bem,masdigamosquetenhamosummtodoqueajusteadimensodeumobjeto,baseadoem
umretngulo,paraotamanhodatela:
SituaodeusodotipoRetanguloondeumQuadradoinadequado
public static Retangulo ajustaParaTela(Retangulo ret) {
// digamos que seja 1280
int larguraTela = Toolkit.getDefaultToolkit().getScreenSize().getWidth();
// digamos que seja 800
int alturaTela = Toolkit.getDefaultToolkit().getScreenSize().getHeight();
ret.setLargura(larguraTela);
ret.setAltura(alturaTela);
return ret;
}
// Situao de uso:
Retangulo r1 = ajustaParaTela(new Retangulo());
// imprime 1280x800, perfeito
System.out.println(r1.getLargura() + "x" + r1.getAltura());
// vlido, quadrado um retngulo, ento pode ser passado no mtodo
Retangulo r2 = ajustaParaTela(new Quadrado());
// imprime 800x800, OPA! No posso passar um Quadrado para este mtodo
// mesmo que ele aceite Retangulos
System.out.println(r2.getLargura() + "x" + r2.getAltura());

QuadradonoumRetngulo,noemOOsegundooLSP.Quadradotemasmesmas
propriedadesdeRetngulo(larguraealtura)masnoomesmocomportamento.Quadradono
honraumdetalhecomportamentalessencialdeRetngulo,deterlarguraealturaindependentes.
Como sugesto de leitura acerca de problema na subtipagem leia estebom artigo na
wikipedia:http://en.wikipedia.org/wiki/Circleellipse_problem
OartigodoBobsobreLSPestaqui:
http://www.objectmentor.com/resources/articles/lsp.pdf

147

Captulo 4 Princpios de Projeto Orientado a Objetos

LeideDemter(LoD)
ALeideDemeter(LawofDemeter)tambmconhecidacomooPrincpiodoMenor
Conhecimento.Temopropsitodediminuiroacoplamentoentremdulos(classes)baseandose
emumaheursticasimples:
*Umaunidadedeveterumconhecimentolimitadoacercadeoutrasunidades
*Cadaunidadedeveconversarapenascomseusamigos,nocomestranhos
*esomenteconversarcomseusamigosimediatos
LoDtambmconhecidocomo:falescomseusamigos

ViolaesdaLoDpodemservistasemummaucheiroconhecidocomoacidentecom
trem ."Vagesdetrem"sovistosquandoumobjetoinvocaummtododeumoutroobjeto,
queporsuavezestdentrodeoutroobjeto.Parececomplicado,no?Vamosaumexemplo
simples:
67

ExemplodeviolaodeDemeter
class NotaFiscal {
LoginService login = LoginService.instance();
public void emite(DadosNota dados) {
// registrando a operao no log
login.getUsuarioLogado().getOperacoes()
.registra("Emisso NF #" + dados.nro, new Date());
// ... instrues para emitir a nota
}
}

AclasseNotaFiscaldependedeoutrasclasses,quais?Dependede LoginService, Usuario


(devidoaogetUsuarioLogado)eOperacoes(devidoaogetOperacoes).Aincurso,opercorrerdo
caminhonogrficodeobjetosaumentaoacoplamento,amedidaqueumaclasseconheceas
classesdentrodeoutrasclasses.EstaumaviolaotpicadaLeideDemeter.
Segundo Demeter, um mtodo (ou funo) M de um objeto O pode invocar outros
mtodosapenas:

67

doprprioO(thisouself)

doobjetosrecebidoscomoparmetronoM

qualquerobjetocriadoouinstanciadodentrodoM

outrosobjetospertencentesaO

variveisglobaisacessveisporOevisveisporM

DesculpeatraduolivredeTrainWreck.Aexpressotipicamentenorteamericana,aquiexplicamelhor:
http://en.wikipedia.org/wiki/Train_wreck

148

Captulo 4 Princpios de Projeto Orientado a Objetos

SeaplicarmosestasregrasaoexemplodaNotaFiscal,entoomtodoemitepodeapenas
invocarmtodosdeNotaFiscal,LoginServiceeDadosNota,quesosuasrelaesdiretas.
Qual o problema, ento, de invocar mtodos das relaes de suas relaes? o
conhecimento.Noexemplo,aclasse NotaFiscal sabeque LoginService temumobjetochamado
Usuario eque esseobjetotemumobjeto Operacoes eque oobjeto Operacoes temomtodo
registra. Futuras mudanas nas classes Usuario ou Operacoes podem exigir mudanas em
NotaFiscalmesmoqueestanotenhaumarelaodiretacomestasclasses.Comoexemplo,seno
registrodeOperacoesfornecessriotambmoIDdasesso,comoficaraclasseNotaFiscal?Ela
teriadeincluiroIDdasessonoregistro,vejaabizarrice:
Efeitoscolateraisdoacoplamentoindevido
class NotaFiscal {
LoginService login = LoginService.instance();
public void emite(DadosNota dados) {
login.getUsuarioLogado().getOperacoes().registra("Emisso NF" + dados.nro, new Date(),
login.getSessao().getId());
// ... instrues para emitir a nota
}
}

EstaimplementaoviolatambmoSRP,fazendocomque NotaFiscalconheadetalhes
quenosopertinentesasuaresponsabilidade.Seoregistrodeoperaesfeitoatravsdo
usuriologadoeinclusiveusaoidentificadordesessodesteusurio,porquenoinvocareste
registroemLoginService,seuconhecido?Ento,LoginServicepodedelegarparaseusconhecidos,
eassimpordiante.Exemplo:
Fazendoumprojetomaislimpo
public class NotaFiscal {
LoginService login = LoginService.instance();
public void emite(DadosNota dados) {
// instruo em conformidade com o LoD
login.registraOperacao("Emisso NF" + dados.nro);
// ... instrues para emitir a nota
}
}
// na classe LoginService
public class LoginService {
private Usuario usuario;
private Sessao

sessao;

public void registraOperacao(String operacao) {


// quem conhece sessao o LoginService, a arte de delegar:
usuario .registraOperacao(String operacao, sessao.getId());
}
}

149

Captulo 4 Princpios de Projeto Orientado a Objetos

public class Usuario {


private Operacoes operacoes;
public void registraOperacao(String operacao, String idSessao) {
operacoes.registra(this , operacao, idSessao);
}
}

O LoD interpola com outroprincpio, menos conhecido, "Tell, Dont Ask" (diga, no
pea),muitoconhecidopelodesenvolvedoresqueadotamoTDD, desenvolvimentoguiadopor
testes.Opontochavequepedirtentador,comoaseguir,eupeo Canvas (getCanvas)eopero
sobreoobjetodevolvido:
Tela.getCanvas().adiciona(figura);
Tela.getCanvas().redesenha();

Mas "dizer" maissignificativoque "pedir",diminuioconhecimentodaestruturade


objetos(eoacoplamento),aseguir:
Tela.desenha(figura); // "diga, no pea" em ao

EnaclasseTela:
// "diga, no pea" em ao, outra vez:
canvas.adiciona(figura); canvas.redesenha();

PrincpiodaSegregaodeInterfaces(ISP)
ISP o acrnimo de Interface Segregation Principle, em portugus: Princpio da
SegregaodeInterfaces.ISPfoidefinidoporRobertMartin(TioBob)enquantotrabalhavaem
projetosnaXerox.Existiaemseutrabalhoumaclasse Job (Trabalho)queeraestendidapor
quasetodasasfunes,sendoqueparaqualquercoisaquefossefeitaumoumaismtodosde
Job eram invocados. Como a classe Job era usada em uma diversidade de aparelhos com
funcionalidades diferentes, presentes ou no, acabava que todas as suas funes no eram
utilizadasportodososdependentes(subclasses);Emais,ainclusodeumanovafuncionalidade
emJobimplicavaemreescrever,oupelomenosrecompilar,osdependentesde Job.Asoluo
encontrada porMartinfoidividirasuperclasse Job empequenasinterfaces,asquaistinham
subconjuntos coesos de funcionalidades que eram usadas apenas pelas subclasses que as
necessitassem.
No seu artigo, este: http://www.objectmentor.com/resources/articles/isp.pdf, ele cunha a
expressoInterfacePollution(PoluiodeInterface)comoummaucheirotpicodeviolaodo
ISP.Eledizqueumainterfacecommuitosmtodospodefazercomquenemtodososclientes,os
queimplementamainterface,precisemdetodosestesmtodos,oqueresultaemmtodosque
notemutilidadeemalgunsclientes.
Podemos usar um exemplo bem simplista mas fcil de compreender. Considere um
sistemaparaumtelefonecelularesuasfuncionalidades.Entodefinimosumainterface,comotu
sabes,umcontratoparaaoperao:

150

Captulo 4 Princpios de Projeto Orientado a Objetos


InterfacedeTelefone
public interface Telefone {
void liga();
void desliga();
void fazLigacao(String numero);
void encerraLigacao();
void ligaCamera();
void capturaImagem();
void desligaCamera();
void ligaTocadorMusica();
void desligaTocadorMusica();
void ligaGPS();
Posicao encontraPosicao();
void desligaGPS();
// ... outros mtodos

EstaumainterfaceresumidadedeTelefone.Umaimplementaodeveimplementar
todosestesmtodos:
ClasseconcretadeTelefone
public class TelefoneXingLing2210 implements Telefone {
public void liga() {
// ... implementao
}
public void ligaGPS() {
throw new UnsupportedOperationException("GPS no suportado");
}
// ... outros mtodos suportados ou no

A questo chave que nem todos os telefones suportam todas as funcionalidades


definidas em Telefone, o que resulta em mtodos vazios ou que disparam uma exceo de
funcionalidadenosuportada.
Umainterface,ousuperclasseabstrata,quedefinemuitasfuncionalidadescomunsanem
todasassubclasses(implementaes)chamadadeinterfacegorda.
Asituaopodepiorarcomotempo.Digamosquenovostelefonesteroafuncionalidade
de acelermetro, que poder ser lido e ter eventos que sero recebidos at pelo prprio
telefone.
AlteraesnainterfacedeTelefone
public interface OuvinteAcelerometro {
void acelerometroMudou(MudancaAcelerometro mudanca);
}
public interface Telefone extends OuvinteAcelerometro {
void liga();
void desliga();
// ... outros mtodos j existentes
EstadoAcelerometro getAcelerometro();
}

151

Captulo 4 Princpios de Projeto Orientado a Objetos

Bem,todosostelefonescomacelermetrosebeneficiarodainterface,mascomofica
aquelesquenotemacelermetro?OTelefoneXingLing2210agorateriamaisdoismtodoscom
implementaoinexistente:
Alteraesnainterfaceimplicamemalteraesnasclassesconcretas
public class TelefoneXingLing2210 implements Telefone {
// ...
public EstadoAcelerometro getAcelerometro() { return null ; }
public void acelerometroMudou(MudancaAcelerometro mudanca) { // vazio }
}

ApropostaeheursticadoISPbemsimples:
PrincpiodaSegregaodeInterfaces:clientesnodeveserforadosadependerdeinterfacequeeles
nofazemuso

Ousodeinterfacesouclassesabstratasgordasaltamentedesencorajado.Umapequena
mudananainterfacecriarumamudanaemcascataemtodososseusclientes,oquenecessita
reescritaerecompilaodepacotesesubprojetos.Istofazcomquealgunsproblemasinerentesa
dependncia descontrolada e desnecessrias sejam imprevisveis. A soluo do problema
segregar,separar,asinterfaces:
Segregandointerfaceecriandoumagranularidademaisfina
public interface Telefone {
void liga();
void desliga();
void fazLigacao(String numero);
void encerraLigacao();
// ... outros mtodos pertinentes a todos telefones
}
// mtodos pertinentes apenas aos telefones equipados com cmera
public interface Camera {
void ligaCamera();
void capturaImagem();
void desligaCamera();
}
// mtodos pertinentes apenas aos telefones equipados com player
public interface TocadorMusica {
void ligaTocadorMusica();
void toca();
void para();
void desligaTocadorMusica();
}
// mtodos pertinentes apenas aos telefones equipados com gps
public interface GeoPosicionamento {
void ligaGPS();
Posicao encontraPosicao();
void desligaGPS();
}

152

Captulo 4 Princpios de Projeto Orientado a Objetos

// mtodos pertinentes apenas aos telefones equipados com acelermetro


public interface Acelerometro extends OuvinteAcelerometro {
void ligaAcelerometro();
void desligaAcelerometro();
public EstadoAcelerometro getAcelerometro();
public void acelerometroMudou(MudancaAcelerometro mudanca);
}

Assim, cada aparelho pode implementar um conjunto coeso de interfaces segundo as


funcionalidadequeeledisponibiliza. Oprincpiofoiresumido,noartigomencionadoantes,do
TioBob, tem um exemplomaiscomplexocom ousodeadaptadoreseouvintes,ospadres
adaptereobserverrespectivamente.

PrincpiodaInversodaDependncia(DIP)
OPrincpiodaInversodaDependncia(DependencyInversionPrinciple)usadona
construodeframeworkseprojetosquenecessitamdeumaimplementaobasedeumcdigo
comum,etambmdaabstraodedetalhes.AheursticadoDIPpodeservistaaseguir:
PrincpiodaInversodaDependncia:
A.Mdulosdealtonvelnodevemdependerdemdulosdebaixonvel,ambosdevemdependerde
abstraes.
B.Abstraesnodevemdependerdedetalhes,detalhesdevemdependerdeabstraes.

Atendncianaturalqueclassesdealtonveldependamdeclassesdebaixonvel,em
outraspalavras,humacoplamentoentreasclassesdonvelmaisaltoaomaisbaixo.Oque
o princpio DIP intenta desacoplar mdulos de alto nvel dos mdulos de baixo nvel,
geralmenteintroduzindoumaabstrao,umcontratodeoperao,sejaatravsdeinterfacesou
classesabstratas.
Considereum exemplopara facilitaroentendimento: para um aplicativodeedioe
gestodedocumentosnecessrioverificaraortografia.Digamosquenossoprojetocontecom4
classes: Documento, VerificadorOrtografico, Dicionario e RepositorioPalavras. Nesta estrutura,
Documento
contm o texto e um VerificadorOrtografico para verificar a ortografia,
VerificadorOrtografico tem um Dicionario para checar as palavras, Dicionario tem um
RepositorioPalavras deondeaspalavrassolidasdeumarquivoououtrafonte.Nestesentido,
fica claro um acoplamento do nvel mais alto, Documento, ao nvel mais baixo,
RepositorioPalavras.Vejaimagemaseguir:

153

Captulo 4 Princpios de Projeto Orientado a Objetos

Dependnciasentreclasses

[[redesenhar este diagrama (Gliffy)]]


AclasseDocumentotemumareferncia,eumadependncia,de VerificadorOrtografico,que
temrefernciaaoDicionario,quetemrefernciaaRepositorioPalavras.
Ainversodadependnciageralmentealcanadaadicionandoumnveldeabstrao.
Para ilustrar vamos pegar uma parte do problema: a relao entre Dicionario e
RepositorioPalavras.Digamosqueocdigosejaeste:
RelaoentreDicionarioeRepositorioPalavras:
public class Dicionario {
// aqui est a dependncia
private RepositorioPalavras repositorio = new RepositorioPalavras();
public boolean existe(String palavra) {
return repositorio.getListaPalavras().contains(palavra);
}
}
class RepositorioPalavras {
private static List<String> palavras;
static {
palavras = Arrays.asList(new String[] {
"programa", "programao", "programador",
"sistema", "complexo", "anlise"
});
}
public List<String> getListaPalavras() {
return Collections.unmodifiableList(palavras);
}
}
// situao de uso:

154

Captulo 4 Princpios de Projeto Orientado a Objetos

Dicionario dic = new Dicionario();


System.out.println(dic.existe("anlise")); // imprime true
System.out.println(dic.existe("pograma")); // imprime false

Aimplementaofunciona,masdigamosqueprecisemosusaroutro RepositorioPalavras,
que leia as palavras de um arquivo ao invs de serem hardcoded68. Vamos chamlo de
RepositorioPalavrasEmArquivo:

Adicionandoumnovorepositriodepalavras:
public class RepositorioPalavrasEmArquivo {
private static final List<String> palavras = new ArrayList<String>();
static {
try {
InputStream inputStream = RepositorioPalavrasEmArquivo.class
.getResourceAsStream("palavras");
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader reader = new BufferedReader(inputStreamReader);
String linha = null;
while ((linha = reader.readLine()) != null ) {
Collections.addAll(palavras, linha.split("\\s"));
}
reader.close();
inputStreamReader.close();
inputStream.close();
} catch (Exception ex) {
throw new ExceptionInInitializerError(ex);
}
}
public List<String> getListaPalavras() {
return Collections.unmodifiableList(palavras);
}
}

A questo : como eu fao Dicionario usar RepositorioPalavrasEmArquivo? Claro, na


estrutura atual teremos que alterar a classe Dicionario para instanciar
RepositorioPalavrasEmArquivo:

AlterandoaclasseDicionarioparausarrepositrioemarquivo:
public class Dicionario {
// alteraes nos mdulos de baixo nvel implicam
// em alteraes nos mdulos de nvel mais alto
private RepositorioPalavrasEmArquivo repositorio =
new RepositorioPalavrasEmArquivo();
public boolean existe(String palavra) {
return repositorio.getListaPalavras().contains(palavra);
}
68

Hardcoded a incluso de dados de configurao ou de entrada diretamente, fixo no cdigo, e considerada


uma inconformidade arquitetural devido ao software no ser configurvel, ou seja, necessrio recompilar o
software para mudar, digamos, a senha do banco
155

Captulo 4 Princpios de Projeto Orientado a Objetos

Adependncia que Dicionario tem deum Repositorio faz comqueaclasse Dicionario


tenhadeseralterada.Noqueromaisalteraraclasse Dicionario paramudarde Repositorio,
ento,tereiqueinverteradependncia.Oqueeusei: Dicionario dependedeum Repositorio,
qualquerum,desdequetenhaumalistadepalavras.
Introduzindoumaabstraonecessriaparainverteradependncia:
// abstrao:
public interface IRepositorioPalavras {
List<String> getListaPalavras();
}
public class Dicionario {
// abstrao em ao:
private IRepositorioPalavras repositorio;
public Dicionario(IRepositorioPalavras repositorio) {
this .repositorio = repositorio;
}
public boolean existe(String palavra) {
return repositorio.getListaPalavras().contains(palavra);
}
}

NestenovoexemploDicionarionodependedeumrepositrioconcreto,dependedeuma
abstraomodeladacomainterface IRepositorioPalavras. Qualquerrepositriopodeserusado
desdequecumpraocontrato:
Implementandoaabstraofornecendoumrepositrioconcreto:
// repositrio concreto:
class RepositorioPalavrasWeb implements IRepositorioPalavras {
private static final List<String> palavras = new ArrayList<String>();
static {
try {
URL url = new URL("http://if.mtiads.net/palavras.txt");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
Scanner scan = new Scanner(con.getInputStream());
while (scan.hasNextLine()) {
Collections.addAll(palavras, scan.nextLine().toLowerCase());
}
scan.close();
} catch (Exception ex) {
throw new ExceptionInInitializerError(ex);
}
}
public List<String> getListaPalavras() {
return Collections.unmodifiableList(palavras);
}

156

Captulo 4 Princpios de Projeto Orientado a Objetos

}
// situao de uso:
Dicionario dic = new Dicionario(new RepositorioPalavrasWeb());
System.out.println(dic.existe("desenvolver"));

Fazendo a engenharia reversa do cdigo usado nos exemplos teramos o seguinte


diagramadeclassesemapadedependncias:

Dependncia invertida: programe para uma interface

Emalgumlugarumrepositrioconcretoterqueserinstanciado,este"lugar"podeser
naclasseclienteouusandoalgumpadrodeprojetocomoServiceLocatorouAbstractFactory
[[linkar]](queserovistosnoprximocaptulo).Masparaadependnciaserinvertidadefatoa
classeDicionarionodeveinstanciarorepositrio
ODIPintensamenteusadonaconstruodeframeworks,implicandonaconstruode
diversasclassescominformaesecomportamentocomumedeixandoosdetalhesparaserem
implementadospeloprogramador.IstoalcanadoatravsdoDIPeOCP.
Usandoumexemplo,considerequetodososDAOscompartilhemumcomportamento
comum:contaronmeroderegistros.Estafuncionalidadesempreigual,ainstruosempre
amesma: select count(*) from tabela,sendoquesmudaonomedatabela.Apartirdeste
conhecimentopodemoscriarumDAOgenrico,abstrato,aserestendidoportodososDAOs
especficos,concretos:
InversodaDependnciaaplicadoaumframeworkdepersistncia:
public abstract class DAO {
public long conta() {
Connection con = null ;
try {
con = DB.openConnection();

157

Captulo 4 Princpios de Projeto Orientado a Objetos

// instruo depende de mtodo abstrato


ResultSet rs = con.createStatement()
.executeQuery("SELECT COUNT(*) FROM " + nomeTabela());
if (rs.next()) return rs.getInt(1);
} catch (Exception e) {
e.printStackTrace();
} finally {
try { if (con != null ) con.close(); }
catch (Exception e) { throw new RuntimeException(e); }
}
return 0;
}
// mtodo a ser implementado pelas classes
public abstract String nomeTabela();
}

O exemplo ilustra o princpio da inverso da dependncia aplicada na construo de


frameworks bsicos,queconsisteemimplementartodoocomportamentocomumedeixaras
lacunas,detalhes,paraseremespecializados.UmaimplementaoeusodesteDAOseriaassim:
Utilizandooframeworkdepersistncia:
class ClienteDAO extends DAO {
@Override
public String nomeTabela() {
// passando uma informao para a superclasse
return "clientes";
}
}
// situao de uso:
DAO clientes = new ClienteDAO();
// imprime a contagem de registros
System.out.println(clientes.conta());

ODIPumprincpioimportanteporfazerusodeumadasmaisimportantesheursticas,
eexistemuitoassuntoe"porns"adiscutirsobreDIP.Cabedizerqueosprincipaisframeworks
comerciaisecorporativosnomercadofazerusodesteprincpio,porexemplo,Spring(paraJava),
ASP.NET MVC (para Microsoft .NET), Cake (para PHP), Rails (para Ruby), Django (para
Python),entretantosoutros.ConsidereleroartigodoRobertMartin:
http://www.objectmentor.com/resources/articles/dip.pdf

SOLID
Cincoprincpioslistadosnestetpicofazempartedeumasequnciadeartigosescritos
porRobertMartin,chamadosdeSOLID(slido),umacrstico69:
69

http://pt.wikipedia.org/wiki/Acrstico

158

Captulo 4 Princpios de Projeto Orientado a Objetos

SingleResponsabilityPrinciple

Open/ClosePrinciple

LiskovSubstitutionPrinciple

InterfaceSegregationPrinciple

DependencyInversionPrinciple

OsprincpiosSOLIDestodisponveisnositedoTioBob(lembrandoqueelemesmose
chamaassim):
http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod

Princpios,noDogmasumapalavrafinal
Todososprincpioslistadosecomentadosnestecaptulosoheursticas,boasprticas,
parafazerbonsprojetosorientadosaobjetos.Contudo,nosoaplicveisatodososcenriose
nodevemserencaradoscomoumDogma70,nosodeaplicaocompulsria,nodevecausar
desconforto ou desespero criar cdigo que no sejam concordantes com esses princpios. A
aplicaoouno,dependedobomsenso,docontextoetambmdotempoedodinheiro:)
Nemtodasaslinguagenssuportamaimplementaodessesprincpios,inclusive,algumas
linguagens nem precisam deles, e outras linguagens implementam de maneira diferente, em
especialasqueincluemoparadigmadeprogramaofuncional.

Bibliografia
[MPW] MCLAUGHLIN, Brett; POLLICE, Gary; WEST, David. Anlise e Projeto Orientado ao
Objeto, da sria use a cabea. 1a ed. Editora: Alta Books, 2007.
[MARTIN] MARTIN, Robert. Cdigo Limpo: Habilidades Prticas do Agile Software. 1a ed.
Editora: Alta Books, 2009.
[M&M] MARTIN, Robert. MARTIN, Micah. Princpios, Padres e Prticas geis em C#. 1a
ed. Bookman, 2011.
[LARMAN] LARMAN, Craig. Utilizando UML e padres: uma introduo anlise e projeto
orientados a objetos e ao desenvolvimento iterativo. 3a ed. Bookman, 2007.

70

http://pt.wikipedia.org/wiki/Dogma

159

Captulo 5 Padres de Projeto Orientado a Objetos

Captulo5PadresdeProjeto
OrientadoaObjetos
Mauprojetado
Seestscommedodealteraralgoentoevidentequefoimau
projetado.
MartinFowler,emumatraduolivre

Na experincia de engenheiros e desenvolvedores no projeto de software orientado a


objetospercebeusequepartedosproblemasnoprojetodeobjetosserepetiam,quasedamesma
forma.Apercepodepadresnosproblemasmotivouaintroduodepadresdesolues,
eficientes e eficazes, reusveis, comprovadamente. Estes padres de solues no projeto
orientado a objetos so chamado de Design Patterns, traduzido como Padres de Projeto
(lembre,projetonosentidodeprojetar,planejar,nonosentidodotrabalho).
Nem toda soluo repetida pode ser chamada de Padro de Projeto, somente as
devidamentedocumentadasecomprovadas,eaindaassimsomuitas.Dedestaquepodemos
separarosseguintes:

GRASP: GeneralResponsibilityAssignment SoftwarePatterns71 (ouPrinciples),em


portugus:Padres(ouPrincpios)deSoftwareparaAtribuiodeResponsabilidades
Gerais.SomaisconhecidoscomoPrincpiosdoquecomoPadresetemopropsito
deidentificarheursticasparadarresponsabilidadesaosobjetosdeformacoerente
buscandoalcanarumprojetocomaltacoesoebaixoacoplamento.

GoFDesignPatterns:surgiudeumainiciativadedocumentarpadresusadosno
desenvolvimento de software orientado a objetos que deu origem ao livro Design
Patterns: Elements of Reusable ObjectOriented Software 72. Os 4 autores so
mencionadoscomo "Ganguedos4",emingls:GangofFour,porissooacrnimo
GoFeoconhecimentodospadrescomoGoFPatterns,ouPadresGoF.

Patterns of Enterprise Applications Architecture (EAA Patterns): so mais


conhecidoscomopadresdearquiteturaemboramuitosentendamcomopadresde

71

http://en.wikipedia.org/wiki/GRASP_(objectoriented_design)

72

http://en.wikipedia.org/wiki/Design_Patterns_(book)

160

Captulo 5 Padres de Projeto Orientado a Objetos

projeto.Alinhaquedivideoquearquiteturadoqueprojetomeioborrada.Estes
padres arquiteturais foram documentados por Martin Fowler e podem ser
consultadosonlinenestesite:http://martinfowler.com/eaaCatalog/

PatternsofEnterpriseApplicationIntegration(EAIPatterns):sopadres
arquiteturaisquetemopropsitodepermitiracomunicaoentresistemas
corporativosheterogneos,integrandodados,processoseferramentas.Estespadres
ficaramfamososcomapublicaodeGregorHohpe.Elespodemvisualizadosnestes
sites:http://www.enterpriseintegrationpatterns.comhttp://www.eaipatterns.com/

Core J2EE Patterns: o catlogo de padres oficial da Sun (hoje Oracle),


proprietria da plataforma e linguagem Java. Os padres so voltados para a
plataforma Java Enterprise (corporativo) e refletem um conjunto de boas prticas
paraaimplementaodeaplicaesdistribudas,AplicaesWebcorporativas,Web
ServiceseoutrosproblemasosquaispodemserresolvidoscomaplataformaJ2EE.
Eles so documentados no livro do Deepak Alure podem ser visualizados online
nestesite:http://www.corej2eepatterns.com

EstecaptulosededicaaosPadresGoF.Penso,nofuturo,emincluirospadresGRASP,masassimcomo
outrostantosconsideroGRASPmaiscomoprincpiosquecomopadreseseeuinserilosnofuturoserno
captulo4.Algunspadresarquiteturais,oriundosdoEAAeJ2EE,estodisponveisnoCaptulo2epadresde
integraofogemaocontextodestematerial.
conhecerpadresdeprojetoumacompetnciacorolria

Conhecer padres de projeto uma competncia essencial de desenvolvedores de


softwares de sistema e aplicativos, indispensvel para a criao de bibliotecas (toolkits) e
frameworks.

IntroduoaosDesignPatterns
Segundo o livro do GoF [GoF] umas das caractersticas que diferencia projetistas
experientesdenovatosqueosexperientesnoresolvemosproblemasdeprojeto "dozero",
elesutilizamsoluesquefuncionaramantes,nopassado,equandoencontramumaboasoluo
autilizamrepetidamente.Estassolues,reaplicveis,reutilizveis,soconsideradaspadres,
quenoexistemsemantesseremexaustivamenteaplicadosetersuaeficinciacomprovada.
projetistasexperientesnoresolvemosproblemasdozero73

possvelveraaplicaodepadresemvriasatividades,porexemplo,filmes.Veja
bem,quandoalgumdesejafazerumfilmedeaoondeummocinhosaipelacidadematando,
hdeterummotivo,quetal:suafilhafoisequestradaoumataramsuafamlia?Roteiristasno
precisamsairdozerotendoclichs,esteretipos,oupadres,comoesses.

73

partirdonadafrequentementemencionadonaliteraturahackercomofromscratch:
http://en.wiktionary.org/wiki/from_scratch

161

Captulo 5 Padres de Projeto Orientado a Objetos

Alm desolucionaro problema, ospadresdeprojeto trazem tambm algunsefeitos


positivos no desenvolvimento de software como facilidade de reutilizao e melhoria da
documentaoecomunicaoentreosenvolvidos.

DefinindoPadrodeProjeto
A definio padro, original, foi cunhada por Christopher Alexander74 (que no
trabalhavanareadeanliseedesenvolvimento 75)masqueenquantoArquiteto(daEngenharia
Civil)percebeupadresnosproblemasdeengenhariaelogodescreveupadresdesolues:
cadapadrodescreveumproblemanonossoambienteeocernedesuasoluo,detalformaque
vocpossausarestasoluomaisdeummilhodevezes,semnuncafazlodamesmamaneira

OsPadresdeProjetotemquatroelementosbsicos:

Nome:umnomepeloqualpodemosnosreferenciaraestepadroequefarpartedo
vocabulriodarea.Tupodescomunicarparaoscolegas: "useium Singleton para
guardar a configurao do servio de expedio" e eles devem ser capazes de
entenderoquefoifeito.Todopadrodeprojetotemumnome;

Problema:dizemquesituaodevemosaplicaropadro,essencialmenteoque
tentaremos resolver. Tipicamente o problema envolto em um contexto, como
exemplo, o mesmo problema em aplicativos com requisitos diferentes assim como
diferentes vises de domnio (negcio) pode trazer implicaes na forma como
implementaropadro.Todopadrodeprojetotentaresolverumproblemaemumdado
contexto.

Soluo:soosmdulos,classes,mtodos,interfaces,omodelofsiconecessriocom
seusrelacionamentos,responsabilidadesecolaboraes. Asoluoquasesempre
demonstradaemumnvelaltodeabstrao,eliminandoparticularidadesetrazendo
umavisogeral.Todopadrotemumaarranjodeobjetoscomaltonveldeabstrao
quecolaborampararesolveroproblema.

Consequncias:frutosdaaplicaodopadro.Serveparaavaliarosprsecontras
desuaaplicaoetalvezpensaremestratgiasalternativas. Todos padres quando
aplicadosdeixamconsequnciacomasquaistemosdelidar.

OspadresGoFsebasearamemlinguagensorientadasaobjetos,napocaemqueolivro
foi escrito, como Smalltalk e C++, mas so abstratos suficiente para funcionar em outras
linguagens,comoJava,C#,PHP(verso5+)masnogarantidoquesejamaplicveisemtodas
aslinguagens.

DescriodosPadresdeProjeto

74

http://pt.wikipedia.org/wiki/Christopher_Alexander

75

ChristopherescreveuolivroAPatternLanguage[http://www.amazon.com/dp/0195019199]acercade
padresencontradosnaconstruocvil
162

Captulo 5 Padres de Projeto Orientado a Objetos

NolivrodoGoFospadressodescritoscom:nome,inteno,motivao,aplicabilidade,
estrutura,participantes,colaboraes,consequncias,implementao,exemplodecdigo,usos
conhecidosepadresrelacionados.
Nestelivroadescrioserresumidapara:

Nome:onomedopadroserusadocomottulodotpico;

Tambm conhecido como: outros nomes pelos quais o padro conhecido na


comunidadededesenvolvedores;

Inteno:qualopropsitodopadro,oqueeletentaresolver;

Motivao:osbenefciosdeuslo,muitotilparacompararcomoutrassolues;

Implementao:umasituaoproblemaeocdigousadoparalidar,fazendousodo
padrodeprojeto,claro;

ParaumentendimentomaisdetalhadorecomendvelaleituradolivrodoGoF[GoF]
ou no mnimo o Use a Cabea Padres de Projeto, que bom e ao mesmo tempo bastante
didtico[UCPP].

PadresGoF
Antesdedetalharestespadresimportantesaberaclassificao,ostiposdepadres.Os
padresGoFestoagrupadosconformesuafinalidade:

Comportamentais:padresquelidamcominteraoedistribuiode
responsabilidadeentreclasseseobjetos;

Estruturais:padresquesepreocupamcomacomposiodeclasseseobjetos;

Criacionais:padresquesepreocupamcomoprocessodecriaodeobjetos;

Aotodoso23padreseemgeralelesserelacionam,porexemplo,opadroComposite
frequentemente aplicado em conjunto com o Iterator ou Visitor, ou ambos! A seguir uma
imagem,eminglsporenquanto[[traduzirimagem]],dasrelaesentreospadresGOF.

163

Captulo 5 Padres de Projeto Orientado a Objetos

RelacionamentosentreospadresGOF

PadresComportamentais
Os padres comportamentais servem para identificar traos comuns de comunicao
entreobjetoseabstrairestestraosparaflexibilizaracomunicao,encapsulandoalgoritmose
ocultandodetalhesdaimplementaonatrocademensagensentreobjetos.Emresumo,eles
lidamcomacomunicaoentreosobjetos.
padrescomportamentaislidamcomacomunicaoentreosobjetos

Nesta seo sero abordados os padres comportamentais GoF, com nfase nos mais
utilizados.

Observer

164

Captulo 5 Padres de Projeto Orientado a Objetos

OpadroObserver(observador)configuradoquandoumobjeto,chamadodesujeitoou
observvel, mantm uma lista de dependentes, chamados observadores, que so notificados
quandoaconteceumadeterminadamudanadeestado.

Tambmconhecidocomo

Publisher/Subscriber(publicador/assinante)

Observer/Observable(observador/observvel)

Event Source/Event Listener (fonte de eventos/ouvinte de eventos), como


conhecidonoJavaSwing

Inteno
Definirumarelaoumparamuitosentreobjetosdeformaapropagarumaatualizao
doobservadoparaseusdependenteseassimserematualizadosautomaticamente.

Motivao
Manteraconsistnciasincronizandoasatividadesentreobjetosrelacionadossemcriar
umforteacoplamentoentreambos.

Estrutura

DiagramadeClassesdoPadroObserver[[redesenhar]]

Um sujeito notifica um observador de suas alteraes de estado. So definidas duas


interfacesasquaissujeitoseobservadoresconcretosdevemimplementar.

Implementao
Osujeitoumobjetooqualrecebeumamudanadeestadoaqualquermomento,um
momento indeterminado. Os observadores tem o interesse em saber quando ocorreu esta
mudanadeestadoequemudanaocorreu.
Considereumsubsistemadeemailondenovosemailschegamesaem,gerenciadopor
umaclasse MailBox,equequeiramosimplementarumanotificaonabandejadosistemaou
165

Captulo 5 Padres de Projeto Orientado a Objetos

mesmoumlogdeemailsrecebidos/enviados.Comopodemosimplementaressanotificaoe
logsemincluirestasinformaesnaclasseMailBox?MesmosecriarmosasclassesMailNotifiere
MailLog,comofazemosqueaclasseMailBoxnoconhea(tenhareferncias)paraMailNotifiere
MailLog?
Podemospensar,porexemplo,emimplementarumtimeremMailNotifier,dedigamos10
segundos,ondeacadacicloeleperguntaa MailBoxsenovosemailschegaram.Esteomodelo
convencionaldetrocadeinformaes, modelo pull,ondeumobjeto puxa osdados deoutro
objeto.Emcertassituaes,comoessa,elebemmaisdifcileineficiente.Noseriamaisfcilse
oobjetoMailBoxavisasseaoMailNotifiereMailLogqueumnovoemailsaiuouchegou?Esteo
modeloassncronodetrocadeinformaes,modelopush,ondeumobjeto(sujeito,observado)
empurraosdadosparaoutroobjeto(observadores,assinantes).
Aseguirumaimplementaoparcialdoexemplo:
SubsistemadeEmaileNotificao:
class MailBox {
// instrues para recebimento e envio de e-mails
}
class MailNotifier {
// mostra notificaes na tela os ttulos das mensagens recebidas
}

Como MailNotifier saber que novos emails foram recebidos? Claro, sem ter uma
refernciaa MailBox ou MailBox a MailNotifier.Precisaremostrsmdulosquerepresentaroo
nossopadrodeprojeto:duasinterfaces,umaparaosujeitoeoutraparaosobservadoreseum
objetoquerepresenteoevento:
Mdulosnecessriosparaaplicaropadroobserver:
// servir de bolsa para carregar os ttulos dos e-mails
class Mails {
ArrayList<String> titulos = new ArrayList<String>();
public Mails(List<String> titulos) {
this .titulos.addAll(titulos);
}
public List<String> getTitulos() {
return Collections.unmodifiableList(titulos);
}
}
// contrato para os observadores (no Java chamamos de ouvintes)
interface MailListener {
void mailEvent(Mails mails);
}
// contrato para o sujeito, o observvel (no Java chamamos de origem)
interface MailSource {
void add(MailListener listener);
void remove(MailListener listener);
}

166

Captulo 5 Padres de Projeto Orientado a Objetos

Com essas interfaces abstramos o sujeito e observadores de emails. O objeto Mails


carregarosttulos,note,queremosimplementarsegundoomodelopush,ouseja,oobservador
noconheceroobjetoconcretoqueoriginouoevento.Aseguirocdigocompleto:
AplicandoopadroObserver:
class MailBox implements MailSource { // mailbox uma fonte de eventos
private List<MailListener> ouvintes = new ArrayList<MailListener>();
public void add(MailListener listener) {
if (!ouvintes.contains(listener)) ouvintes.add(listener);
}
public void remove(MailListener listener) {
ouvintes.remove(listener);
}
private void mailCheckLoop() {
// ...
// criamos o objeto de notificao
Mails mails = new Mails(titulos);
// e notificamos todos os observadores/ouvintes
for (MailListener o : ouvintes) o.mailEvent(mails);
}
}
class MailNotifier implements MailListener { // mailnotifier um ouvinte
// mtodo invocado quando o evento percebido
public void mailEvent(Mails mails) {
NotifyFrame frame = new NotifyFrame(mails);
frame.show();
}
}
// situao de uso:
// em algum ponto do programa acontecer a ligao
MailBox box = new MailBox();
box.run(); // digamos que mailbox seja um servio em segundo plano
MailNotifier notifier = new MailNotifier();
// possvel, afinal MailNotifier um MailListener
box.addListener(notifier);

Maisinformaessobreosemailspoderiamsertransportadasapenasadicionandonovos
atributosaclasseMails.Lembrandoquetambmseriapossvelapenasenviarumarefernciado
MailBoxedeixareleacessvelparaonotificadorconsultarainformaonecessria(modelopull).
Masestamoscomoprincpiodefazeroouvintedesconhecerafontedoevento.

MaisInformaes

167

Captulo 5 Padres de Projeto Orientado a Objetos

OpadroObserverusadofrequentemente,oentendimentoedomniodestepadro
altamenterecomendado.Algunslinksextrasestoaseguir:
ObserverexplicadopelaDoFactory:
http://www.dofactory.com/Patterns/PatternObserver.aspx

Observerexplicadopeloprof.JacquesSauve:
http://www.dsc.ufcg.edu.br/~jacques/cursos/map/html/arqu/observer.htm
ObserverexplicadoporBobTarr:
http://userpages.umbc.edu/~tarr/dp/lectures/Observer.pdf

Strategy(Estratgia)
AssimcomooObserveropadroStrategy,emportugusestratgia76,muitoutilizado,
sobretudo no desenvolvimento de frameworks e componentes. Strategy busca o reuso e a
extensodocomportamentoatravsdacomposioconformeosprincpios[[hiperligar]]Prefira
ComposioaHeranaeOpen/ClosePrinciple.

Inteno
Definirumafamliadealgoritmos,encapsulandocadaum,etornandoosintercambiveis.
OStrategypermitevariaroalgoritmoindependentementedosclientesqueousam[GoF].Em
outraspalavras,asinstruesvariveisdeumprocedimentosoencapsuladasemnovasclasses.

Motivao
Considereumclassequerepresentaumdocumentoondeocontedoorganizadocomo
ttulos,pargrafosetpicos,entreoutros.Digamosquetenhamosqueformatarestedocumento
comestilosvisuaisdiferentesbemcomopolticasdeespaamento.Destemodopodemosescolher
duas abordagens: manter o cdigo de formatao na classe representante do documento ou
separarocdigodeformatao,ouseja,criarumaclasseparaestecdigo.
Comaestratgiapodemosirmaislonge.Podemoscriardiferentescdigosdeformatao,
oumelhor,estratgiasdeformatao,selecionveisemtempodeexecuo.
AdicionarumanovaformataonoimplicariaemmudaraclassedeDocumento,jque
aformatao,oalgoritmodeformatao,independentedoDocumento.
Separar o comportamento varivel do comportamento comum o que motiva a
introduodopadroStrategy.

Tambmconhecidocomo

Policy(Poltica)

FunctionObject(http://en.wikipedia.org/wiki/Function_object)

Estrutura
76

Nopudeperderapiada:http://www.youtube.com/watch?v=KKvVcK8vEhg
168

Captulo 5 Padres de Projeto Orientado a Objetos

DiagramadeClassesdoPadroStrategy

Dado uma classe cliente, um Contexto, que tenha uma referncia uma estratgia
abstrata(interface),podertrocardeestratgiaatravsdeclassesconcretasqueimplementema
interface.

Implementao
Considereumaclassequerepresenteumemprstimo.Esteemprstimotemdiferentes
taxasdejurossegundoasuacategoria,porexemplo Emprestimo,Financiamento,Leasing.Aquesto
chave:comoalterarastaxaseadicionarnovascategoriassemterdealteraraclasseprincipal
Emprestimo?
Asoluoestemguardaroalgoritmousadoparaoclculodejurosemclassesexternas
(estratgias)segundoumainterfacecomum(contrato).
ClassesdosistemafinanceirosemStrategy:
class Emprestimo {
private static final double TAXA_ADM = 4.50;
private Categoria categoria;
private double

valor;

private double

parcelas;

public double valorFinal() {


switch(categoria) {
case EMPRESTIMO: return valor * Math.pow(1 + 0.09, parcelas);
case FINANCIAMENTO: return valor * Math.pow(1 + 0.06, parcelas);
case LEASING: return valor * Math.pow(1 + 0.03, parcelas)
+ TAXA_ADM * parcelas;
}
return 0.0;
}
}

E se o clculo de financiamento mudar? E se uma nova Categoria for necessria? A


intenoevitaralteraesnaclasse Emprestimo,masissopodeserdifcil,jqueelacumpre
muitasresponsabilidades.Alteraesimplicaronaadiodecategoriasenaintroduodemais
umcasenainstruoswitch.AsoluomaisviveltornarasCategoriasestratgias:
169

Captulo 5 Padres de Projeto Orientado a Objetos


AplicandoopadroStrategy:
public class Emprestimo {
// eis o primeiro passo: usar uma interface
private ICategoria categoria;
private double valor;
private double parcelas;
public double valorFinal() {
// o clculo do valor delegado para a categoria
return categoria.calculaValorFinal(valor, parcelas);
}
}
// aqui est o contrato da interface:
public interface ICategoria {
double calculaValorFinal(double valor, int parcelas);
}
// as expresses, incluindo as taxas, so encapsuladas como categorias
public class CategoriaEmprestimo implements ICategoria {
public double calculaValorFinal(double valor, int parcelas) {
return valor * Math.pow(1 + 0.09, parcelas);
}
}
public class CategoriaFinanciamento implements ICategoria {
public double calculaValorFinal(double valor, int parcelas) {
return valor * Math.pow(1 + 0.06, parcelas);
}
}
public class CategoriaLeasing implements ICategoria {
private static final double TAXA_ADM = 4.50;
public double calculaValorFinal(double valor, int parcelas) {
return valor * Math.pow(1 + 0.03, parcelas) + TAXA_ADM * parcelas;
}
}
// situao de uso:
Emprestimo e = new Emprestimo(3000, 13);
e.setCategoria(new CategoriaLeasing());
// calculado pela categoria Leasing
System.out.println(e.getValorFinal()); // imprime 4464,10
e.setCategoria(new CategoriaEmprestimo());
// calculado pela categoria Emprestimo
System.out.println(e.getValorFinal()); // imprime 6398,78

Comestaimplementaopodemosmudaroclculoemtempodeexecuobemcomo
introduzirnovosclculoscriandonovascategorias(queimplementemICategoria)semalterara
170

Captulo 5 Padres de Projeto Orientado a Objetos

classeEmprestimo. OpadroestratgiatambmvistonaAPIdoJava,porexemplo:omtodo
sortdaclasseCollections.

Maisinformaes
O padro Strategy outro padro muito utilizado, sendo que deve fazer parte da
"carteiradeconhecimentos"detodoprogramador/desenvolvedorOO.
Algumaslinguagenspermitemapassagemdefunesde callback,comoJavaScript77,e
suaestruturaeaplicaobemsemelhanteaopadroStrategy.Aseguiralgunsartigossobreo
assunto:
https://developer.mozilla.org/enUS/docs/Mozilla/jsctypes/jsctypes_reference/Callbacks
http://www.impressivewebs.com/callbackfunctionsjavascript/

NositedadevmediatemumbomartigosobreoStrategy:
http://www.devmedia.com.br/strategydesignpatterns/18839

TemplateMethod
OpadroTemplateMethod(mtodomodelo)usadoparadefinirumasriedepassos
deumalgoritmo,implementarumabaseinvarianteedeixarumoumaispassosvariveisparaas
subclasses definirem. Ele adere ao OCP mas, diferente do Strategy, prioriza herana
composio.AssimcomooStrategyeObservereleusadocomfrequnciaparaacriaode
frameworksecomponentesgeneralizados.

Inteno
Definiroesqueletodeumalgoritmoemumaoperao,delegandoalgunspassosparaas
subclasses.Deixarassubclasses(re)definirpartedoalgoritmosemmexeremtodasuaestrutura.

Motivao
ConsidereospassosnecessriosparaconfigurarumaformulrionoJava(JFrame)para
Login.Algunsatributosecomponentesdaestruturasosempreiguais:entrarcomousername,
entrarcomapassword,eclicarlogin.Digamosqueloginsejanossotemplatemethodquedever
executar uma sequncia de passos, alguns fixos e outros variveis, como verificar se o
username/passwordconferem,casosim,autorizarumaoperaoesair,casono,informarqueo
logininvlidoepermanecer.
Nestesentidopodemossepararapartefixadavarivel,apergunta:qualaparte
varivel?.Nesteexemplo,podemosassumirqueaconfernciavarivel,masosdemaispassos
sofixos.Tambmpodemosassumirqueaoperaoautorizadadeveserespecificada,massair
apsaautorizaoseriaessencial.Enfim, asoluopodeseraimplementaodeumclasse
LoginFrame,abstrata,ondeaclassefilha(concreta)definiriaalgunspassosabstratosde LoginFrame,
comodoConferir(Usuario, Senha)edoAutorizar().MesmoaformadenotificaodeLoginInvlido
poderiavircomoummtodopadromascomapossibilidadedesersobrescritohookInvalido().
JavaScriptfunctioncallbacksumrecursosmuitopoderoso:https://developer.mozilla.org/en
US/docs/Mozilla/jsctypes/jsctypes_reference/Callbacks
77

171

Captulo 5 Padres de Projeto Orientado a Objetos

Estrutura

DiagramadeClassesdoPadroTemplateMethod

Determinaroesqueletodeumalgoritmo(AbstractClass)edelegarcertospassosparaas
subclasses(ConcreteClass)definiremdeformaqueaestruturabasenosejaalterada.

Implementao
AseguirumexemplodopadroTemplateMethodaplicadoaumcomponenteSwingpara
login.
SuperclasseparaloginbaseadanoTemplateMethod:
public abstract class AbstractLoginForm extends JFrame {
private JLabel lbUsername = new JLabel("Usurio:");
private JLabel lbPassword = new JLabel("Senha:");
// so protegidos para permitir seu acesso pelas subclasses
protected JTextField tfUsername = new JTextField();
protected JPasswordField tfPassword = new JPasswordField();
// ...
private JButton btCancelar = new JButton("Cancelar");
private JButton btLogin = new JButton("Login");
public AbstractLoginForm() {
this .setLayout(new GridLayout(3, 2, 3, 3));
Container container = this .getContentPane();
container.add(lbUsername);
container.add(tfUsername);
container.add(lbPassword);
container.add(tfPassword);
container.add(btCancelar);
container.add(btLogin);
this .pack();
this .setDefaultCloseOperation(DISPOSE_ON_CLOSE);
this .setTitle("Login");
this .btCancelar.addActionListener(new ActionListener() {

172

Captulo 5 Padres de Projeto Orientado a Objetos

public void actionPerformed(ActionEvent e) {


dispose();
}
});
this .btLogin.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
login(); // aqui chama o template method
}
});
this .setVisible(true);
}
// TEMPLATE METHOD
private void login() {
// pega o usurio digitado
String usuario = tfUsername.getText();
// pega a senha
String senha = String.valueOf(tfPassword.getPassword());
// chama o mtodo abstrato para conferir
if (doConferir(usuario, senha)) {
// chama o mtodo abstrato quando o login vlido
doQuandoAutorizado();
dispose(); // fecha a janela
} else {
// chama o mtodo padro de aviso para login invlido
quandoNegadoHook();
}
}
public abstract boolean doConferir(String usuario, String senha);
public abstract void doQuandoAutorizado();
protected void quandoNegadoHook() {
JOptionPane.showMessageDialog(this , "Usurio ou senha invlidos");
this .tfUsername.setText(""); // limpa usurio
this .tfPassword.setText(""); // limpa senha
}
}

Oquefazumaclasseabstrata?Bem,nadaatquealgumaestenda.Adiferenaentre
umaclasseabstrataeumainterfacequetupodesfazerimplementaesemclassesabstratas,
ouseja,nemtodososmtodossoabstratos.Umainterfacecomoumaclasseabstratacom
todososmtodosabstratos, maslembre:noJavaspossvelestenderumaclasse(mesmo
abstrata)maspossvelimplementarvriasinterfaces.Useclassesabstratascomsabedoria.Este
exemplo acima justifica o uso de uma classe abstrata para implementar o padro Template
Method,nocasoomtodologin().Neleumasriadeetapassodefinidas,algumasfeitaspela
prpriaclasseabstrataeoutrasdelegadasparaasubclasse.Vamosimplementaestasubclasse:
SubclassequesubmeteoTemplateMethod:
public class MeuLoginForm extends AbstractLoginForm {

173

Captulo 5 Padres de Projeto Orientado a Objetos

// aqui implementamos a parte de validar o login, claro,


// poderia ser verificado junto a uma base de dados
@Override
public boolean doConferir(String usuario, String senha) {
return usuario.equals("zeh") && senha.equals("zezinho");
}
// e aqui entramos com as instrues quando o login for vlido
@Override
public void doQuandoAutorizado() {
new MainForm().setVisible(true );
}
}

AideiageraldoTemplateMethodnocomplicadaebemtilparaacriaodemuitas
classesbasequepodemserestendidasparapersonalizarocomportamento.Osdoismtodos
necessrio foram implementados. uma conveno nomear os mtodos obrigatrios com
doAlgumaCoisa,masaindaexisteummtodoquepode,ouno,serimplementado,eleopcional,
o quandoNegadoHook. Todos os mtodos opcionais so protected (podem ser sobrescritos) e so
nomeadoscom algumaCoisaHook,onde hook significagancho,ouseja,ummtodoqueprov
funcionalidadepadromasquepodesersobrescrito(anulado)parafazlodiferente.Digamos
queeunoqueiramaismostrarum JOptionPane,mascolorirofundodosInputsdevermelho
quandoologinforinvlido,entomosaobra:
AsubclassepodesobrescreverTemplateMethods:
public class MeuLoginForm extends AbstractLoginForm {
@Override
public boolean doConferir(String usuario, String senha) {
return usuario.equals("zeh") && senha.equals("zezinho");
}
@Override
public void doQuandoAutorizado() {
new MainForm().setVisible(true );
}
@Override
protected void quandoNegadoHook() {
tfUsername.setBackground(Color.red);
tfPassword.setBackground(Color.red);
}
}

Maisinformaes
Usei um exemplo simples mas penso que suficiente para esclarecer a ideia bsica.
ObviamenteocontextodoproblemapodeounoexigirumTemplateMethode,penso,que
vers bem a utilidade deste padro quando comear a encapsular lgica repetida de seus
aplicativos.

174

Captulo 5 Padres de Projeto Orientado a Objetos

OpadrodeProjetoTemplateMethodcombinabemcomopadrodeArquiteturaLayer
Superclass.
Na Wikipedia em ingls tem um bom exemplo de Template Method aplicado a uma
superclasse/frameworkdejogos:
http://en.wikibooks.org/wiki/Computer_Science_Design_Patterns/Template_method

Estaabordagemdosourcemakingtambmmuitoboa:
http://sourcemaking.com/design_patterns/template_method

EcomumaajudadoGooglefcilencontraralgoemportugus,comoesseartigoda
devmedia:http://www.devmedia.com.br/patternstemplatemethod/18953

Command
[[padrodeprojetocomando]]

State
[[padrodeprojetoestado]]

Visitor
[[padrodeprojetovisitante]]

ChainofResponsibility
[[padrodeprojetocorrentedaresponsabilidade]]

PadresEstruturais
Padresestruturaispreocupamseemorganizarosobjetoseclassesparadarflexibilidade
acomposioeformaodeestruturasmaiores.

Composite
[[texto]]

Decorator
[[texto]]

Faade
[[texto]]

Proxy
OpadroProxyusadoparaembrulharumobjetoemoutro,criandoumrepresentante
que pode interceptar as chamadas de mtodos ao objeto alvo. Isto d possibilidades de
175

Captulo 5 Padres de Projeto Orientado a Objetos

implementarfuncionalidadesdinmicasquepodemseradicionadasaumobjetosemalterarsua
interface.

Inteno
Providenciarumsubstitutoaoutroobjetoparacontrolaroacessoaele.

Motivao
[[]]

Tambmconhecidocomo

Surrogate(Substituto)

Implementao
[[]]

Estrutura
[[]]

Maisinformaes
[[]]

PadresCriacionais
Ospadrescriacionaissoaquelesquelidamcommecanismosdecriaodeobjetosde
formaapropriadaacadacontexto/problema.Demaneirageralospadresdecriaobaseiamse
emdoisconceitos:encapsulareesconderquaisclassesconcretassousadaspelosistemaou
esconderdosistemacomoestasclassessoinstanciadaseosobjetoscombinados.

Builder
OpadroBuilder,construidoremtraduolivre,forneceumaAPIparaconstruirobjetos
complexosemvezdeutilizaromtododeconstruopadro(usandoconstrutoresdaclasse).
particularmente til para instanciar objetos que precisam de muitos argumentos para serem
construdose/ouque,decertamaneira,aordemetipodosargumentosofuscamaleiturado
cdigofonte.

Inteno
Separaraconstruodeobjetoscomplexosdesuarepresentaodeformaqueomesmo
processodeconstruopossaserusadoparacriardiferentesrepresentaes.

Motivao

176

Captulo 5 Padres de Projeto Orientado a Objetos

Algumasclassesprecisamdeargumentosnumerososevariadosparasereminstanciadas,
precisandorealizarumasobrecargadoconstrutorparaatenderavariedadedeparmetros.Um
Builderpodefacilitaraleituradosparmetros,inicializandoasinstnciasdeformamaisclara.
Outrasituao,anecessidadedeinstanciarvriosobjetoscompoucasalteraesnos
parmetrosdeinicializao.UsandoumBuilderpossveldeterminarosparmetroscomunse
inicializarcadaparmetrovarivelnecessrioparainstanciarcadaobjeto.

Estrutura
[[]]

Implementao
[[]]

Maisinformaes
[[]]

FactoryMethod
Como o nome diz, o padro se baseia em utilizar mtodos para fabricar objetos, os
mtodos fbrica. Estes mtodos criam famlias de objetos interdependentes sem expor suas
classesconcretas.

Inteno
Definir uma interface para criar um objeto mas deixar as subclasses instancilos. O
padroFactoryMethodfazumaclassedelegaracriaodeobjetosasuassubclasses.

Motivao
Muitasvezesnecessriopadronizarumafamliadeobjetosesuasinterfacesmasdeixar
suaconstruoabertaeosaplicativosdefinirquandoseroinstanciados.

Estrutura
[[]]

Implementao
[[procurarumbomexemplo]]

Maisinformaes
[[]]

Singleton
O padro Singleton usado para restringir a criao de objetos, ou seja, regular a
instanciaodeclasses,nestecaso,paraumanicainstncia.
177

Captulo 5 Padres de Projeto Orientado a Objetos

Inteno
Permitirqueapenasumaesomenteumobjetodedeterminadaclassesejainstanciado.
Tambmpermitirqueesseobjetosejaacessvelglobalmente.

Motivao
Emcertassituaespodesernecessrioqueumobjetosejaacessvelemanipulvel,lidoe
gravado, em vrios pontos do aplicativo. Este arquivo geralmente contm informaes
compartilhveiscomoconfiguraes,porexemplo,credenciaisdeacessoaumbancodedados,
servio web, informaes de sesso, login ou outros dados em que sua vida na memria
acompanhaavidadoaplicativo.
Umasoluoparaesteproblemainstanciaroobjetologonapartidadoaplicativoe
passlocomoparmetroparatodososobjetosqueprecisamdele,noconstrutorgeralmente,
causandoumacorrentedepassagemdoobjeto.Umaoutrasoluocriarumaclasseemque
todos seus atributos e mtodos sejam estticos, o que restringe algumas caractersticas e
funcionalidades teis nas instncias, como polimorfismo, herana, alm da simplicidade no
acessodeatributosemtodosdeinstnciaemcomparaoaoesttico.
O padro Singleton traz a possibilidade de instanciar um nico objeto de uma certa
classe,ousubclassedesta,eexpeesteobjetoatravsdeummtodoesttico.umaabordagem
tilparacriarumobjetoglobalsemconstrulodeformatotalmenteesttica.

Estrutura

DiagramadeClassesdoPadroSingleton

Assegurarqueumaclassetemumaeapenasumainstnciadurantetodootempode
execuoequehumpontodeacessoglobalaestainstncia.

Implementao
Considereanecessidadedeimplementarumaclassequegerencieafiladeimpresso
(spooler). Um objeto desta classe, spooler, teria a fila de documentos para impresso e os
despachariaparaimpressora,permitiriacancelamentoouatalteraraordemdeprioridadena
fila.
O que no faria sentido ter mais de um spooler, pois como ficaria a gerencia dos
documentos?Secadaclientedospoolerchamarnew Spooler,cadaumteriaumafiladiferentede
documentos, o que no aceitvel para a funcionalidade, que deveria ter uma filha
compartilhada de documentos entre os clientes. Neste exemplo, neste contexto, faz sentido
limitaronmerodeinstnciasdospooler,parauma,apenas.Todoosistemateriaapenasum
spooleracessvelemanipulvelglobalmente.
178

Captulo 5 Padres de Projeto Orientado a Objetos

importante mencionar que existem vrias maneiras e tcnicas de implementar


Singleton.Nocdigoaseguirtuversumaimplementaosimples.
ImplementaodoSpoolerusandoopadroSingleton:
public class Spooler {
// faz a instanciao de um objeto Spooler, constante,
// s visvel para o prprio Spooler
private static final Spooler instancia = new Spooler();
private Queue<Documento> fila;
// o construtor privado nega a instanciao de um Spooler
// para as outras classes, em outras palavras apenas o
// prprio Spooler pode "se construir"
private Spooler() {
fila = new LinkedList<Documento>();
runPrintJob();
}
// mtodo que expe o acesso a instncia. Normalmente tem esse nome,
// mas no obrigatrio (ver Calendar, DateFormat, etc)
public static Spooler getInstancia() {
return instancia;
}
public void imprimeDocumento(Documento doc) {
fila.offer(doc);
}
private void runPrintJob() {
// thread de impresso
}
// ... restante irrelevante
}

Essa a implementao mais simples de um Singleton, as trs partes destacadas em


negritonocdigosoaspeasminmasnecessriasparaadefinio.Comessatcnicaapenas
umobjetoSpoolersercriadoetodosiroacessloporSpooler.getInstancia(),vejaaseguir:
AcessandooSingleton:
public class UmaClasseDoSistema {
// meio de acessar a instncia
private Spooler spooler = Spooler.getInstancia();
// assim no funciona, afinal o construtor privado
//

private Spooler spooler = new Spooler(); // <- errado

public void umMetodo() {


// como a instncia nica na prtica nem preciso guardar uma
// referncia para executar uma ao, por exemplo:
Spooler.getInstancia().imprimeDocumento(doc);

179

Captulo 5 Padres de Projeto Orientado a Objetos

// ... resto da implementao irrelevante

Maisinformaes
OpadroSingletonnemsemprevistocombonsolhos,algunsoconsideramumanti
padrocomoargumentodequeelefereprincpiosdeorientaoaobjetos.Enfim,assimmesmo
elemuitoutilizado,acompetnciacentralnecessriasaberquandoeledeveserusado,ou
seja,muitosapsconheclocomeamausloparatodososproblemas,cuidado!
Existe uma tcnica mais sofisticada de usar Singletons que a utilizao de Lazy
Initialization(inicializaotardia),quefazcomqueainstnciasejacriadaapenasnoprimeiro
usode getInstance().Contudoparaimplementarestatcnicadevesetornaromtodoseguro
paraacessoconcorrente(threadsafe)oquetrazumtrabalhoamais.Nesteartigo,muitobome
sucinto, explicada uma forma segura de usar Singletons inicializados tardiamente, leitura
sugerida:
http://www.oreillynet.com/onjava/blog/2007/01/singletons_and_lazy_loading.html

OpadroSingletontodifundidoquemesmoumartigoemportugusdawikipdiao
descreveeimplementaemvriaslinguagens:
http://pt.wikipedia.org/wiki/Singleton

AbstractFactory
[[texto]]

Prototype
[[texto]]

Padres:vilesoumocinhos?Umareflexo.
[[texto, prs, contras, etc: https://www.google.com.br/search?q=design+patterns+good+or+bad]]

Bibliografia
[F&F] FREEMAN, ELISABETH. FREEMAN, ERIC. Padres de Projeto, da Srie Use a
Cabea. Editora Alta Books, 2007.
[GoF] GAMMA, E.; JOHNSON, R.; VLISSIDES, J.; HELM, R. Padres de Projeto: Solues
reutilizveis de software orientado a objetos. 1.ed. Editora: Bookman, 2000.
[KERIEVSKY] KERIEVSKY, JOSHUA. Refatorao para Padres. 1.ed. Editora: Artmed,
2008.

180

Parte 3: Arquitetura e Projeto de Alto Nvel

PARTE3:ARQUITETURAEPROJETODE
ALTONVEL

181

Captulo 6 Introduo a Arquitetura de Software

Captulo6IntroduoaArquitetura
deSoftware
Oproblemaaescolha
Arquiteto: Como, sem dvida, voc est percebendo, a
anomalia sistmica, criando flutuaes at mesmo nas
equaesmaissimplesdisseoarquiteto.
Neo:Escolha.Oproblemaaescolha!
Cena do filme Matrix Reloaded emque Neo encontra o
ArquitetodaMatrix:http://youtu.be/dTK2LROhc2w

umaatitudeprofissionaldividirosoftwareempartesmenores,mdulos,parafacilitara
implementao e futura manuteno do software. Esses mdulos podem ser divididos em
componentesaindamenorestrazendovisesmaissuperficiais(altonvel)oumaisespecficas
(baixonvel)dedetalhesdaimplementao.
AescolhadeumaArquiteturaapenasumaetapanoprocessodedesenvolvimentode
software,eprojetaraArquiteturaumasubdisciplinadaEngenhariadeSoftware.Aetapade
Arquitetura pode ser realizada por um Engenheiro de Software, uma equipe experiente de
desenvolvedoresouporumprofissionalespecializadochamadoArquitetodeSoftware.
AprofissodeArquitetodeSoftwareaindanototalmentereconhecida(ouentendida),
talvez at por ser parte da Engenharia de Software, mas h iniciativas de especializao e
definiodecompetnciascomooOCEA78.Estecaptulotemaintenodedefinireesclarecera
atividade deArquitetura ecolocar algunsprincpios e padres bsicos dearquitetura usados
pelosDesenvolvedoresmaisexperientes,lderesdeprojetoe,claro,ArquitetosdeSoftware.

Oque,eoqueno,arquitetura?
[[melhorar as definies]] [[introduzir beautiful archicteture]]
Definir o significado de arquitetura realmente difcil, confuso e, at hoje, existem
opiniesdivergentes.AabordagemmaistcnicasegundooIEEE(lsei3e)1421200079:
78

OracleCertifiedEnterpriseArchitect: Arquiteto Corporativo Cerificado pela Oracle

79

IEEERecommendedPracticeforArchitecturalDescriptionforSoftwareIntensive
Systems
182

Captulo 6 Introduo a Arquitetura de Software

Arquitetura O conceito de mais alto nvel de um sistema em seu ambiente. A


arquitetura de um software (em dado momento) sua organizao ou estrutura de
componentes significantes interagindo atravs de interfaces, sendo estes componentes
compostosdesucessivoscomponentesmenoresesuasinterfaces
Particularmente acho a explicao de Martin Fowler [FOWLER #1 #2] mais
compreensvel.Eleargumentaqueosdesenvolvedoresenvolvidosemumprojetodesoftware
temumentendimentocompartilhadosobreoscomponentesexistentesecomoelesinteragem.
Frequentementeestesdesenvolvedoresdevemtomardecisesquesodifceisdeseremdesfeitas
porissodevemserdiscutidasnoinciodoprojeto,bemcedo,ouseja,qualquerescolhadifcilde
mudarumaescolhaarquitetural.
qualquerdecisoparaoprojetodosoftwarequesejadifcildeserdesfeitaumaescolha
arquitetural

GradyBooch,porexemplo,primeirodefineProjeto,nosentidodeProjetar,comosendo
cadadecisopontual,empartesbemespecficasdoSoftware,eentoArquiteturacomosendoas
decisessignificativas,ondesignificativomedidopelocustodamudana.
Jfalamosbemnoinciodocaptuloquepraxedividirosoftwareempartesmenores,
contudodecidircomoestaspartessecomunicamejuntastrazemumasoluovivel,uma
decisoarquitetural.Sparadramatizar,adiferenaentredecisesarquiteturaispodefazerum
Web Site atender de 500 requisies/minuto at 15000 requisies/minuto, e tambm pode
fazeraadiodenovasfuncionalidadeemumsoftwarejexistentedemorarumahoraouuma
semana. Cada deciso arquitetural implica diretamente nos requisitos nofuncionais como
performance,escalabilidadeemanutenibilidade,porexemplo.
Mesmo como desenvolvedor ou programador, tens de fazer escolhas a todo instante.
Algumassomaisespecficas,outrasmaisgerais.Porexemplo,escolherentreusarumtipo int
oudoubleparaarmazenarainformaodeidadealgobemespecficoe,relativamente,fcilde
mudarnofuturo.Poroutrolado,escolherusarumabibliotecapararesolvercertosproblemase
atmesmoalinguagemdeprogramao,obancodedadoseotipodeaplicao(web,desktop)
algobemgeral,impactaemtodoosistema,difcildemudarduranteoprojeto,sumloucodiria
aps 3meses decodificao: bem, Python no d um bom suporte a este requisito, vamos
mudarparaC#ouoclientenoprecisadeumainterfacewebelequeragoraumainterface
desktop.
No livro Use a Cabea Anlise e Projeto Orientado a Objetos eles dizem que A
arquiteturaasuaestruturadeprojetoedestacaaspartesmaisimportantesdasuaaplicaoe
osrelacionamentosentreelas.
importantesabersepararedistinguiroquecodificao,projetoearquitetura.

importantesabersepararoquecodificao,projetoearquitetura.Codificarrealizar
uma funcionalidade muito pequena, como um clculo de datas para estimar vencimentos.
Projeto,nonossoidioma,temsentidoambguo,podesernosentidodotrabalhoqueestsendo
realizado(oProjeto),ounosentidodeplanejar(oatodeProjetar)umpartedosistema.Note

183

Captulo 6 Introduo a Arquitetura de Software

quenestelivroquandofaloprojetoquasesempreserefereaoatodePlanejar,Projetar,sendoque
normalmenteusareiapalavradesignparanocausarconfuso.
ProjetaralgodemaisaltonvelqueCodificar.Porexemplo,decidirseasclassesque
lidamcomdatasdevemserempacotadasemumcomponenteseparadocomopropsitodeser
reusvel, uma atividade de planejamento, de projeto. Projetar demanda mais tempo, mais
raciocnioalongoprazo,resolveroproblemadehojeeodeamanh.Arquiteturaasomaea
convenodetudoqueprojetado,porexemplo,predeterminarpacotesespecficosepadresde
desmembramento(epersuadirosdesenvolvedoresaseguir)Arquitetura.
OArquitetodeveserumlder,eledeveguiarosDesenvolvedoremotivlosaaderirArquitetura
deRefernciaemvezdedesenvolveremsuasprpriasestruturas

Segundo o Processo Unificado 80, um modelo de processo para desenvolvimento de


software,oArquitetodefineumaArquiteturadeReferncia,que,basicamente,umpadroou
conjunto de padres de arquitetura predefinido, projetados e testados em determinados
contextos.

Objetivosdaarquitetura
Oobjetivoprincipaldaarquiteturatornarosistemasimplesdeentenderedeaplicar
correesnofuturo,ouseja,aarquiteturaintroduzregrasepadresaseguir,queatrasaum
poucoaprogramaonopresente,masfacilitaamanutenonofuturo.
Os objetivos especficos da arquitetura esto fortemente ligados aos requisitos no
funcionais,ouseja,aarquiteturaplanejadaeespecificadaparaqueosoftwareseja:

80

Manutenvel: fcil de corrigir e de introduzir novas funcionalidades. Alteraes


demorampoucotempoparaseremimplantadas.

Reusvel: seus componentes sejam reaproveitveis em outros sistemas, reduzindo


assimtempoecustonodesenvolvimentodenovasaplicaes.

Confivel:notenha falhas,ouquepelomenosqueasfalhasnoimpliquemem
perdadeinformaesimportantes.

Testvel:seja fcil de assegurar o corretofuncionamento e que os defeitossejam


rastreveisatravsdestestestes

Rpido:performancesatisfatriadopontodevistadeseususurios.

Seguro:nopermitaacessoindevidoeintroduoeexecuodecdigomalicioso.

Escalvel:sejafcilexpandiloparapermitirumacargamaiordefuncionalidadese
usurios,permanecendorpidodopontodevistadeseususurios

MaissobreoProcessoUnificadopodeserencontradonestewebsite:
http://www.wthreex.com/rup/portugues/index.htm

184

Captulo 6 Introduo a Arquitetura de Software

interessedoArquitetonomomentodadefinioatingiresteseoutrosrequisitosno
funcionais,toimportantesquantooslistadosanteriormente:

Acessvel:fcileintuitivodeoperar.Usuriosdemorampoucotempoparaaprender
auslo,almdeseremprodutivos,rpidos,nasuaoperao.

Concordante (compliance): o software adere s normas e leis vigentes. No h


violao de patentes ou de leis. O software est conforme as mtricas e leis de
segurana,privacidade,etc.

Interopervel: o software comunicase com outros softwares. Existe uma infra


estruturaquepermiteexportareimportarinformaesusandoprotocolosconhecidos
edifundidos.

Portvel:osoftwareexecutaemmaisdeumaplataformacomsatisfatoriedadee
toleranteaalteraesdehardware.Osoftwarepodeserinstaladoemdispositivos
mveis,sistemasoperacionaislivreseproprietrios.

ComosugestoconsiderelermaissobreosatributosqualitativosdossoftwaresnolivrodaMicrosoft[MS]
Captulo16:QualityAttributese/ouprocureinformaesextrasacercaderequisitosnofuncionaisna
ISO/IEC9126:http://pt.wikipedia.org/wiki/ISO/IEC_9126
OobjetivoprincipaldaArquiteturadeumsistemarealizarosrequisitosnofuncionais

AimportnciadaArquiteturaeDesign
Os clientes (ou usurios) percebem a qualidade externa do software, ou seja, eles
avaliamainterface,usabilidade,performanceeseosoftwareexecutaasatividadesnecessriase
teisparaseunegcio/problema.Osclientesnopercebemaqualidadeinternadosoftware,que
diz respeito a implementao, legibilidade do cdigo e a modularidade (a diviso em
componenteseacoernciaentreessescomponentes).
A qualidade interna de um software tambm vista na facilidade de incluir novas
funcionalidadesbemcomoalteraroutras.Aqualidadeinternafrutodeum design81coesoea
ausnciadessaqualidadeimplica,segundoRobertMartin,nosseguintessintomas:

Rigidez:Dizemosqueosoftwarergidoquandodifcilalterarumapartesemque
maisalteraessepropaguemnocdigoeemoutrosmdulos,gerandoumefeito
cascata.Noincomumqueotrabalhodeapenasumahoratorneseumdiainteiro
graasaumsoftwarergido.Arigideztambmatraiefeitoscolaterais,porexemplo,o
aumento do custo de alterao. Como difcil estimar a profundidade de uma
alteraoosGerentesdeProjeto(GPs)podemcomearanegaralgumasalteraes
noessenciais.Oquenoincioumadeficinciadedesignlogosetornaanomaliana
polticadegesto.

Fragilidade: A fragilidade est relacionada a rigidez. A propagao de uma


alteraonosoftwarepodefazloquebraremlugaresimpensveisequeinclusive

81

Lembrando, design significa Projeto no sentido de Projetar, Planejar.


185

Captulo 6 Introduo a Arquitetura de Software

podemternadahavercomolugarondeaalteraoinicialfoifeita.Esteumsintoma
muitocomumdesoftwaresconstrudossemplanejamento,ondeaequipedegestores
edesenvolvedoressempretememasalteraes,poisnotemconfiananosoftwaree
rezam para que ele no quebre. Softwares frgeis so muito difceis de manter e
particularmentejvivriosdessesseremreescritospoisnoconseguiammaisreceber
manuteno.

Imobilidade:comumtentarreaproveitarumafuncionalidadedeumsoftwareem
outro,oproblemaquealgunssoftwarestemseuscomponentestoacopladosque
impossvel levar uma funcionalidade para outro software sem levar outros
componentesquenadatemhaver.Seumsoftwaretemseuscomponentesfixos,que
nopodemserportadosparaoutrosoftware,entoelesofredeimobilidade.um
sintomatpicodefaltadeplanejamento,faltadedesign,faltadeprojetar.

Viscosidade:Quandoaequipesedeparacomumamudanaquepodeserfeitade
vriasmaneiras,ondealgumasdelaspreservamaarquiteturaeoutrasno,isto,
hacks82. Quando seguir o padro do projeto aparenta ser mais difcil de ser
implementado do que usando hacks ento dizemos que a viscosidade alta, em
outraspalavras,fcilfazerdamaneiraerradaedifcilfazerdamaneiracerta.

notvelaquantidadedesistemasimplementadoseimplantadosquetiverampoucaou
nenhumaatividadedearquiteturaedesign.Sepercebequandoumaequipedecidequemelhor
fazeralgummdulo(ouosistemainteiro)denovoemvezdealterlo.

ConsideraesparaArquitetura
Fazer a arquitetura consiste em escolher a linguagem, banco de dados, modelo de
interfaceeoscomponentesprincipaisnecessriosparaaconstruodaaplicao.Nofcil,
paradefinirumaarquiteturadeveselidarcomvriosdetalhes,entreeles:

Aplataformaescolhida:seaaplicaodesktop,web,embarcada,mvel,etc:no
possvelusaromesmomodeloemtodasestasplataformas,cadacasoumcaso;

Implantao:seaaplicaoserexecutadatotalmentelocal,totalmentenoservidor,
clientemagro,sobreumaintranetounainternet,ouummistodestesmodelos;

Tecnologia: que tipo de linguagens, frameworks, databases, sistemas operacionais,


etc,podemserusadoseaquecusto(financeiromesmo$$$);

AArquiteturaorienta,guiaosdesenvolvedoresdosistema,fornecendoumpadrodeestruturae
codificaoaserseguido

82

Soluo deselegante (a.k.a. gambiarra), mas que funciona:

http://en.wikipedia.org/wiki/Hack_(computer_science)#In_computer_science. Por vezes, conhecido como

Kluge: http://catb.org/jargon/html/K/kluge.html
186

Captulo 6 Introduo a Arquitetura de Software

AconstruodaarquiteturafortementebaseadanoprincpioSoC(aseguir),nacriao
decomponentesenousode frameworks.Aescolhadoscomponentesumgrandedesafioda
arquitetura,superadoapenaspeladecisodecomofazerestescomponentescomunicaremse.

SeparationofConcerns(SoC)
Oprincpiodeseparaodeinteresses(SoC)umaheursticaestruturalquevisaagrupar
partesdesoftwareconformeotemaouproblemaqueresolvem.Porexemplo,ousodeHTMLe
CSS:oprimeiro usadoparadefiniraestruturaeosegundoparadefiniraparncia,uma
aplicaodoprincpioSoC.
OSoCoprincpiomaisimportantenadefiniodeumaArquitetura

OSoCumprincpiobsicoaplicadoaarquitetura,queimplicaemdividiroaplicativo
emseesbemdefinidas.Tambmusadono design (OOD),nocasodeOOimplicaemcriar
classeseagruplasmediantesumcontextomaior,porexemplo:apresentaodedados,lgica
denegcioeacessoadados;econtextosmenores,porexemplo:sessodousurio,validao,
conversodedadosrelacionaisemdadosorientadosaobjetos,etc.

EstilosdeArquitetura
ExistemvriosestilosdeArquiteturaquedefinemumvocabulrioeumarefernciapara
ossoftwares.Estesestilospodemsercombinadoseadaptadosconformeoproblema.Exemplos:

83

Cliente/Servidor:quandooaplicativoestdivididoemdoisprocessos,namesma
mquinaouemmquinadiferentes,quesecomunicamatravsdeprotocolosbem
definidos,comooTCP/IP.Porexemplo,umaplicativoquepersisteosdadosemuma
basededadosMySQLCliente/Servidor,poisosoftwaresecomunicacomoMySQL,
queumsoftwareindependente.

Baseadaemcomponentes:divideoaplicativoemcomponentescominterfacesbem
definidasqueencapsulamumalgicaepodemsermovidosentreosprojetos.um
dosprincipaisrecursosparaevitaraimobilidade.

Arquiteturaemcamadas(Layered):divideosmdulosemseeslgicaschamadas
camadas.Cadacamadasecomunicacomacamadaabaixomasascamadasinferiores
desconhecemassuperiores.Exemplo:criarumacamadadeinterfacegrficaeumade
negcio, onde a interface acessa as regras de negcio mas a camada de negcio
desconheceoscomponentesdeinterface.

3Tier,nTier:separaascamadasemprocessosdiferentesnomesmocomputadorou
emcomputadoresdiferentes.usadocomoumatcnicadedistribuio,divisoda
cargaecompartilhamentodacamadadenegciocomvriasinterfaces.

SOA83:normalmenteumaplicativonTierqueimplementaacamadadenegcio
comoumServioWeb(WebService)queinteragecomvriasinterfaceseclientes

ServiceOrientedArchitecture(SOA):ArquiteturaOrientadaaServios
187

Captulo 6 Introduo a Arquitetura de Software

atravs de um protocolo comum como SOAP ou REST. til em ambientes


heterogneosemquecoexistemvriosaplicativosescritosemlinguagensdiferentes
masquedevemtrocarinformaes(Interop84).
Existemoutrosestilosecadaestilotemsuasestratgiasdeimplementaoemuitoafalar
arespeito,contudoesteumlivrointrodutrioenoserabordado.Minhasugestoaleitura
dolivroMicrosoftApplicationArchitectureGuide:
http://msdn.microsoft.com/enus/library/ff650706.aspx.gratuito,acrediteo_O

Entreosestilosarquiteturaismaisusados,trssotpicosemqualquertipodeaplicao,
autilizaodoestilo Cliente/Servidor,ComponenteseCamadas.Lembreque,emgeral,as
decisesarquiteturaissobaseadasnoprincpioSoCeenfatizamadiviso.

ArquiteturaCliente/Servidor
tpicoaplicativossereminstaladosemvrioscomputadoreseacessaremumabasede
dadosnica.Emoutraspalavras,osmesmodadospodemservistosportodosclientes(estaes
detrabalho).Ento,seoaplicativonolocal(rodasemumamquina),certamentetuirs
aplicarumarquiteturacliente/servidor,instalandooaplicativoclientenasestaesdetrabalhoe
umservidordebancodedadosrelacional85(SGBD)emumservidor.

ArquiteturaCliente/Servidor:softwarenasestaesebancodedadosnoservidor[[redesenhar]]

Acomunicaoentreclienteeservidornormalmenterealizadasobreprotocolosderede
bem estabelecidos, como TCP/IP. Por exemplo, os PDVs86 de um sistema de supermercado
podemacessarumSGBDPostgreSQLemumservidorcentral,quepodeinclusiveestaremoutra
cidade,desdequesejavisvelparaosclientesatravsdeumIPacessvel.
AarquiteturaCliente/Servidorpodeseestendermaisdoquesomenteentreaplicativoe
basededados,porexemplo,possvelfazerumclientescomainterfacegrficaqueacessa
84
85
86

http://en.wikipedia.org/wiki/Business_process_interoperability
TambmconhecidocomoDBMS:http://en.wikipedia.org/wiki/Database_management_system
PDVoacrnimodePontodeVenda:http://pt.wikipedia.org/wiki/Ponto_de_venda(Caixa,
popularmente)
188

Captulo 6 Introduo a Arquitetura de Software

outramquinaquecontmasclassesdenegcioeestaacessaoutramquinaquetemabasede
dados. o tpico funcionamento da Web, onde o navegador representa a interface, onde o
usurioclicaemumcomponentegrficoquedisparaumarequisioparaumservidorweb,que
dispara uma requisiopara um meiodeacessoaosdadosquedevolve para oservidorque
devolve para o usurio. Em outras palavras, a arquitetura Cliente/Servidor baseada em
Requisio/Respostacomonaimagemaseguir:

Cliente/Servidor:requisioerespostaemvriosnveis

Existemdetalhesaconsiderarquenoestonoescopodestelivromasquevaleapena
mencionar,comoaseguranadosdadosnotrfego,performanceeescalabilidade87,etc.

ArquiteturaBaseadaemComponentes
Independentedoproblema,dividirosoftwareempartesmenorestrazvriasvantagense
ajudaaatingirobjetivoscomoreusabilidadeemanutenibilidade.Normalmentecomponentesso
subprojetosdivididosempacotes(ounamespaces)quevisamresolverumproblemabemdefinido
equepodemser(deveriamser)reaproveitveis.
UmexemploumcomponentedeGeraodePDFquepodeserembutidoemqualquer
projetoquenecessitedisponibilizarrelatrioemPDF,sejaWebouDesktop.Aoinvsdecodificar
afuncionalidadedegerarPDFnaprpriaaplicaoseriadesejvelacriaodeumsubprojeto
que conta com classes e interfaces com mtodos documentados e fceis de aprender, e que
escondam(abstraiam)acomplexidadedageraodePDFs.
Aseguirsegueumcdigoquepartedopressupostodaexistnciadeumpacote util.pdfe
classesparafacilitarageraodePDF:
UsandoumcomponenteparagerarPDF:
import util.pdf;
...
PDF relatorio = new PDF();
relatorio.setCabecalho("Relatorio de vendas " + new Date().toString());
relatorio.setConteudo(vendas.toTableString());
relatorio.setRodape("Empresa X");
relatorio.isNumeraPagina(true);
if (!imprime) relatorio.salva("c://relatorios//" + vendas.getIdentificacaoUnica());
else relatorio.imprimeNaImpressoraPadrao();

InternamenteaclassePDF fazusodevriasoutrasclasseseAPIsparaI/O,impressoe
codificaodePDF,contudoistoficaescondidodoprogramador(queumusuriodaAPI).
87

Habilidadedeatenderumademandacrescente,estarpreparadoparacrescer:
http://pt.wikipedia.org/wiki/Escalabilidade
189

Captulo 6 Introduo a Arquitetura de Software

Aseleodefuncionalidadequepodem(oudevem)serencapsuladasemcomponentes
umpassoimportante.Aprticamaiscomumbuscarnaespecificao(nosrequisitos)partes
arquiteturalmenteimportantes.
Aspartesconsideradasessenciaisemumsistemasoarquiteturalmenteimportante

ArquiteturaemCamadas
Fundamental Theorem of Software Engineering88
Ns podemos resolver qualquer problema atravs da introduo de um nvel extra de
indireo
Andrew Koenig89, cientista da computao famoso pelo livro C Traps and Pitfalls90
Separarosoftwareemcamadas,digamos,oestadodaartedoprincpioSoCaplicadoa
arquiteturadesoftware.Consiste em separar ocdigoportemas(interesses) bemdefinidos,
buscandonomisturalos.Porexemplo,enquantointeressesdistintos,ocdigoparaainterface
comousurio(UI91)elgicadaaplicao(tambmchamadonegciooudomnio)soseparados
emcamadas.
Como exemplo, imagine uma tela quecontenha um formulrio e um boto chamado
"salvar".Ocliquenobotodisparaumevento,ummtodo,quedeveriasalvarosdadosdo
formulrio,masaoinvsdissoelecolheosdadosdoformulrioeencaminhaparaumaclasse
responsvelporsalvaroregistro,estaclassevalidaosdadoseaplicaalgicaenvolvidaparaa
persistnciadosdados.
SegundoFowler[FOWLER#1]existembenefciosimportantesaodividirosoftwareem
camadascomo:

Poder programar uma camada sem se preocupar com as outras: os


programadoresdeinterfacecomousurionoprecisamsepreocuparcomoosdados
seropersistidos,elesapenasdesenhamaIUechamamomtododeterminadopara
salvarasinformaesnoimportandocomoeleassalva.

Substituir camadas por implementaes alternativas: pode ser possvel, por


exemplo,alternaracamadadepersistnciaparasalvarosdadosemmemria(RAM),
emumabasededadosrelacionaloumesmoemarquivosXMLsemprecisarmudaras
camadasdeapresentaoenegcio.

Reusar camadas colocando camadas mais altas: por exemplo, possvel


reaproveitartodaumacamadadenegcionamigraodeumaaplicaodeDesktop
paraWeb,redesenhandoapenasacamadadeapresentao.

Obviamente,possveldividirosoftwareemmuitascamadas,masnecessriosaberque
h um aspecto negativo nisto. Embora dividir em camadas torneo cdigo dosoftwaremais
adaptativoeaparentementeorganizadoelaintroduzmaisindireo.Indireooresultadoda
88

http://en.wikipedia.org/wiki/Fundamental_theorem_of_software_engineering

89

MaissobreAndrewKoenig:http://en.wikipedia.org/wiki/Andrew_Koenig_(programmer)
CTrapsandPitfallsliteraturaobrigatriaparaosprogramadoresC/C++:http://www.amazon.com/CTraps
PitfallsAndrewKoenig/dp/0201179288
UserInterface,emportugusInterfacecomoUsurio(ver:InteraoHomemComputadorIHC)

90

91

190

Captulo 6 Introduo a Arquitetura de Software

delegao,ouseja,ummdulo(classe,componenteoucamada)delegaachamadaparaoutro
mdulo.Aquantidadedemdulosintroduzidapelaindireopodetornarosoftwaredifcilde
gerenciarededarmanuteno.Tambmpodeintroduziranecessidadedealteraesemcascata
quando,porexemplo,temqueseintroduzirumcampo,eatprejudicarodesempenhojque
umachamadaamaissignificamaisumaclassenamemriaemaisummtodonapilha.
Amaioriadossistemasusamapenasduascamadasenosmaiscomplexospodemexistir3ou4,
camadasdemaisdificultamoentendimentodosistemainteiroeafetamaperformance.

Tipicamente,desenvolvedoresamadoresincluempoucaounenhumaindireo,oque
pssimo,poisdeixaosistemargido,frgileimvel(ver[[linkar]]AImportnciadaArquitetura
eDesign);desenvolvedoresprofissionaistendemaadicionarindireodemais,tornandodifcila
visualizao do projeto inteiro; desenvolvedores experientes conseguem balancear um nvel
adequadodeindireo.Asoluomais tpica a threelayerarchitecture,arquiteturadetrs
camadas,comoaque estaseguireque sugeridapeloMicrosoft ApplicationArchitecture
Guide:

TrscamadassegundooMS.NETApplicationArchitectureGuide:apresentao,negcioedados

Astrscamadastradicionais
costumeiro,emaplicativosWebeDesktop,utilizartrscamadasbembsicas,cadauma
comresponsabilidadesbemdefinidas,asaber:

Apresentao(PresentationLayer):tambmchamadade camadadeinterfacedo
usuriooucamadadevisualizao.Temopropsitode:

Exibirinformaes;

Tratarassolicitaeseeventos:cliquesembotes,links,pressionamentode
tecla;

Exibircontrolesdeformulrioparaentradadedados;

191

Captulo 6 Introduo a Arquitetura de Software

Domnio(DomainLayer):acamadaqueencapsulaasregras,algicadodomnio,
ou,comomuitoschamam,regrasdenegcio(BusinessLayer).Temopropsitode:

Fazervalidaes;

Encapsularalgicadoaplicativo;

Executartarefaseatividadespesadas;

Persistncia(PersistenceLayer):tambmchamadadefontededados(DataSource
Layer)ouacessoadados(DataAccessLayer).Temopropsitode:

FazeracomunicaocomSGBDeserviosexternos(WS92);

Gerenciarconexes;

Gerenciartransaes;

Estascamadaspodemrodaremummesmosoftware(processo)oucadaumaemum
mquinadiferente.Seesteforocaso,nousamosotermoLayeresimTier,ondeLayeruma
camada lgica e Tier uma camada fsica. Alm das camadas tpico incluir outros mdulos
utilitriosdeusogeral.Aseguirestumaimagemquerepresentaaarquiteturamaisutilizada
emsistemascorporativosdepropsitogeral:

Trscamadastradicionais:apresentao,lgicadodomnioeacessoadados.

Regrabsicadadivisoemcamadas
Aodividirumsoftwareemcamadastustensqueseguirumaregrabembsica:
ascamadassuperioresacessamosserviosdisponibilizadospelascamadasinferiores,masas
camadasinferioresdesconhecemascamadassuperiores

Separtirmosdanoodetrscamadasclssicas:apresentao,negcioepersistncia;
entenda que a apresentao acessa a camada de negcio e pode acessar a camada de

92

WSoacrnimodeWebService,eportugusServioWeb:http://pt.wikipedia.org/wiki/Web_service
192

Captulo 6 Introduo a Arquitetura de Software

persistncia;acamadadenegcioacessaacamadadepersistncia;acamadadepersistncia
acessaasbasesdedadoses.
Obs.:atenoaocasodacamadadeapresentao,elaacessaacamadadenegcioepodeounoacessara
camadadepersistncia,umadecisoarquiteturaltornaracamadasintermedirias,comoadenegcio,
opacasoutransparentes.
tornarcamadasintermediriasopacasoutransparentesvlidocomodecisoarquitetural

Contudo, a uma exceo a esta regra, embora que, de certa forma, a regra no seja
quebradacomestaexceo.Ascamadasinferiorespodemacessarascamadassuperioresdesde
quesejaatravsdeabstraes,sendoqueacamadainferiornoconheceosdetalhesdacamada
superior. Considere que a camada de domnio pode chamar um mtodo da camada de
apresentao, chamado showErrorMessage(String). Este mtodo pode ser modelado como uma
interface,implementadapelacamadadeapresentaoquepodeexibiramensagemdeerroem
umJOptionPane,seforDesktop,ouemumdiv,seforWeb,noimportaparaodomnio.

Tecnologias
Enquanto Arquiteto, ou desenvolvedor lder (ou solitrio, hehe), necessrio tomar
vrias decises quanto ao que sera usado para desenvolver o software, que plataforma, que
linguagem, que banco de dados, que IDE, etc. A seguir vou falar brevemente de algumas
plataformas,apenasparafazerumquadrogeral.

BaseadasnaplataformaJava
AplataformaJava,noconfundircomalinguagemJava,temseunichonacomputao
corporativa,especialmenteemserviosquerodamnaWeb,conhecidocomoJavaEE93.
JavatambmestnosDesktops,comosframeworksSwing94eJavaFX95,contudonotem
entradanessenichocomooDelphieoVisualBasic.Aprincipalvantagem,eachoquea nica
quepodemotivaralgumadesenvolvedoraplicativosDesktopcomJavaaportabilidade,ou
seja,osoftwarerodasobreWindows,LinuxeMac.Sparacitarexemplos,osistemadoscorreios
edareceitafederalsoconstrudosemJavaSwing.
Javatambmestdisponvelparaacomputaomvel,celularesePDAs,comoJava
ME,hojecaindoemdesuso,eoAndroid96,queemborafornecidopeloGoogletemsuaAPIeKit
deDesenvolvimentoemJava.Emoutraspalavras,quempretendedesenvolverparasmartphones
comoSistemaOperacionalAndroidusaroJava.
Javaconsolidadoebemvistoporempresasdemdioegrandeporte,poroutrolado
podeserdesperdciodeesforo(edinheiro)usaroJavaparafazerpequenossoftwaresouweb
sites.EmpresasgrandestemrequisitoscomplexosqueaplataformaJavaEEatendebemcomo
Escalabilidade,Segurana,Performance,etc.

93
94
95
96

JavaEnterpriseEdition:http://www.oracle.com/technetwork/java/javaee/overview/index.html
http://docs.oracle.com/javase/tutorial/uiswing/
http://www.oracle.com/technetwork/java/javafx/overview/index.html
http://www.android.com/http://developer.android.com/sdk/index.html
193

Captulo 6 Introduo a Arquitetura de Software

ExistemdoisIDEsbemconsolidadosparaJava,o Eclipse97 eo NetBeans98.(semcitar


outrasnomenosimportantescomoOracleJdevelopereJetBrainsIntelliJ).Ambostemmuita
entradaeequiparamseemfuncionalidades.AcomunidademaisWebetambmAndroidprefere
oEclipse,enquantooNetBeansabraaoDesktop.
importante ressaltar que o desenvolvimento na plataforma Java no se limita a
linguagem Java. Java como plataforma e como linguagem so coisas bem diferentes. A
plataformaJavacompostapeloSDKepelamquinavirtual(JVM)queaceitavriaslinguagens
almdalinguagemJavacomo:

Jython:linguagemPythonquecompilaparaaJVM(http://www.jython.org/);

JRuby:linguagemRubyquecompilaerodasobreaJVM.bemaplicadautilizada
para a implantao de aplicaes Web baseadas no framework Rails
(http://jruby.org/);

Clojure:umavariantedalinguagemLISP,baseadanoparadigmadeprogramao
funcional, est se tornando uma alternativa popular, em outras palavras, h uma
tendncia a redescoberta do paradigma funcional com aplicaes prticas
(http://clojure.org/);

Groovy:linguagemdinmicaconstrudaparasercompatvelcomJavapormcom
umasintaxemaisminimalista,intuitivaeamigvel.Cresceanualmenteembasede
usurios(http://groovy.codehaus.org/).

Scala: uma linguagem mista de funcional e orientada objetos, multiparadigma,


robusta e confivel que ganhou visibilidade especialmente quando o Twitter foi
reescritousandoa(anteseraescritoemRuby)(http://www.scalalang.org/);

ExistemoutrasvriaslinguagensparaaplataformaJava,podespesquisaravontade.Se
fossedarumadicadeumalinguagemproeminenteparaofuturochutariaaCeylon,criadapelo
GavinKing(criadordoHibernate):http://ceylonlang.org/

Baseadasnaplataforma.NET
Aplataforma .NET (pronunciasedotnet: http://www.microsoft.com/net)fornecidapela
MicrosoftetemtendnciaaserapreferidaparacomporsoluesbaseadasemWindows.
.NET atende Desktop, Web e Mobile, sendo respectivamente destinado a executar no
Windows,IISeWindowsPhone.
.NETindependentedelinguagemmashatendncianaturalausaralinguagemC# 99
(pronunciaseCsharp)quefoi desenvolvida juntocomaplataformaparasubstituiroVisual
Basic, muito embora exista o VB.NET 100 que uma implementao de Visual Basic para a
plataforma.NET.C#fortementeorientadaaobjetos,muitosemelhantealinguagemJavacom
muitosrecursosdoObjectPascal(oulinguagemDelphisepreferir).
97

http://www.eclipse.org/

98

http://netbeans.org/
MaissobreC#aqui:http://msdn.microsoft.com/ptbr/vstudio/hh388566.aspx
VisualBasic.NEThttp://msdn.microsoft.com/ptbr/library/cc580665.aspx

99
100

194

Captulo 6 Introduo a Arquitetura de Software

.NET bem sucedido em Desktops (Windows) e concorre com Java em aplicaes


corporativas para Web. No concorre com o PHP no desenvolvimento de sites e pequenas
aplicaes.
UmadasprincipaisvantagensdaplataformaadistribuiodoKitdeDesenvolvimento
integradoaoIDE,o Visual Studio101.OVisualStudioumaIDEprtica,permitedesenharas
telas com rapidez e cria boa parte do cdigo a partir de templates, sendo indicada para o
desenvolvimentorpido(RAD).
AssimcomoaplataformaJavaaplataforma.NETaceitaoutraslinguagens,almdoC#e
VB.NET, como Iron Python, Iron Ruby e F#, esta ltima uma linguagem funcional
disponibilizadapelaMicrosoft.
DevidoaonomefortedaMicrosoftatrsdaplataformaelabemaceitaporempresasde
(quase)todoporte(comexceodaquelasquenopodempagaraslicenas,hehehe).
Embora o Visual Studio seja pago existem verses gratuitas intituladas Express que
podemseracessadasaqui:
http://www.visualstudio.com/products/visualstudioexpressvs

BaseadasnoPHP
PHPalinguagem,ouplataforma,maisbemsucedidanaInternet.Existemmilhesde
sitesescritosemPHPehospedadossobreservidoresLinuxcomoApacheeMySQL atuando
comoServidorWebeBasedeDadosrespectivamente.
OPHPj passou porvriasreviseseacada nova versomuitosconceitostemsido
introduzidos.AtoPHP4alinguagemeraaltamenteorientadaaprocedimentoseapartirdo
PHP5muitotemseintroduzidodeorientaoaobjetos.Entretantonopartedaculturada
linguagem,einclusivedosprogramadoresdePHP,programarorientadoaobjetos.
QualquerprojetonainternetdepequenoatmdioportesebeneficiabemdoPHP,afinal
PHPverstiletemmuitamodeobradisponvel,enfim,alinguagemfcildeaprender.
Contudo PHP tem muitos truques, inferncias e surpresas que so desconhecidas dos
iniciantes e mais familiares aos programadores experientes. A linguagem extremamente
permissiva, permitindo ao programador omitirse de lidar com situaes que em outras
linguagens teria de aplicar um raciocnio para resolver. Neste sentido, deixar a linguagem
trabalharsozinha podeserumatonegligente.Domeupontodevista,essadesobrigaodo
programadoracabaporexigirmaisexperinciadomesmo,emoutraspalavras,devesesermuito
bomprogramadorparatrabalharemPHP(omesmovaleparaJavaScriptporexemplo).
Mesmo aplicativos Desktop podem ser construdos em PHP, com o uso da biblioteca
grficaGTK,mascomaentradadosaplicativosWebnaintranetdasempresasmuitossoftwares
degesto,RHeoutrosestosendoimplantadosnasempresasemsuasredesinternaseescritos
em PHP. Contudo, importante que fique claro que grandes corporaes consumidoras de
softwarerelutamemaceitarPHPcomoplataformaparaseusaplicativos,partepelocarter"fita
adesiva" dalinguagemedosprogramadores(noseofenda),etambmporteremcontratos
fechadosondeexistemrestriesatecnologiasquepodemserimplantadas.Omesmoacontece,
101

AmbientedeDesenvolvimentoMicrosoftVisualStudio:http://www.microsoft.com/visualstudio
195

Captulo 6 Introduo a Arquitetura de Software

porexemplo,naescolhadeumsistemagerenciadordebasesdedados,ondecorporaesoptam
porsistemasproprietriosepagoscomooOracleouMicrosoftSQLServeremdetrimentoao
MySQLouPostgreSQL,quesogratuitos.

FrameworksnotveisparadesenvolvimentoWeb
Frameworkssoteisparareduzirotempodedesenvolvimentoetambm,entreoutros
benefcios,formalizarumpadrodeestruturaparaocdigo.Existem frameworksparaatender
diferenteslinguagenseplataformas,easeguirvouapenasdarumapassadanosmaisnotveis.

Java

Swing:usadoparadesenvolveraplicativosDesktop

JavaFX:usadoparaaplicativosWebricoseDesktop

Spring:usadoparaodesenvolvimentodeaplicativosWebcorporativos

GoogleWebToolkit(GWT):permitedesenvolveraplicativosWebdeclarandocdigo
Java

Struts:frameworkMVCparaaplicativosWeb

PlayFramework:frameworkparadesenvolvimentowebrpidocomJava.

JavaServerFaces(JSF):frameworkMVCoficialdaOracle

Hibernate:frameworkparaabstrairapersistnciaepermitiracessarbasesdedados
relacionaissemousodeSQL

JUnit:ferramentaparatestesdecdigo

WebForms:usadoparadesenvolveraplicativosDesktop

Silverlight:usadoparaaplicativosWebricoseDesktop

ASP.NETMVC:frameworkMVCparaaplicativosWebbaseadosemASP.NET

Entity Framework: framework daMicrosoft paraabstrairapersistnciaepermitir


acessarbasesdedadosrelacionaissemousodoSQL,semelhanteaoHibernate

NHibernate:oHibernatepara.NET

NUnit:ferramentaparatestesdecdigo(port102doJunit)

.NET

PHP

102

Carregar,levarumafuncionalidadeourecursoparaoutraplataforma,ver:
http://en.wikipedia.org/wiki/Porting
196

Captulo 6 Introduo a Arquitetura de Software

Zend103Framework:frameworkparaaplicaesWebquebuscaestruturarefacilitar
odesenvolvimentocomPHP

CakePHP:frameworkMVCeobjetorelacionalsemelhanteaoRails

Yii:frameworkMVC

CodeIgniter:outroframeworkMVC

Maisaqui:http://www.phpframeworks.com/

Paraobterumalistadeframeworksacesseestelink,bemcompleto:
http://en.wikipedia.org/wiki/Comparison_of_web_application_frameworks

Opesemergentes
AlmdeJava,.NETePHP,muitasoutrasplataformasestodisponveisesousadascom
relativosucesso.Comoopesemergentesdparadestacaralgumaslinguagenseframeworks,
ondeosmaisnotveisestoaseguir:

RubyonRails:RoRcomochamadoousodalinguagemRubycomoframework
WebRails.ApsolanamentodoRailsalinguagempassouadesempenharumpapel
importante no desenvolvimento de aplicativos Web usando tcnicas de
desenvolvimentogil.umadassoluesmaisproeminentesebemsucedidasparao
desenvolvimentoWebaopontodevriosoutros frameworks paraoutraslinguagens
seremcriadoscombasenoRails.

Python, web2py e Django: a linguagem Python j tem sua entrada na Web


inicialmentecomoframeworkweb2pyemaistardecomoDjango,queRailslike.A
comunidadePythonbemativa,alinguagemmuitobemdocumentada,elegante,
flexvelepoderosa.

Groovy,GrailseSpringSource:GroovyumalinguagemquerodasobreaJVMe
tem como principal apoiadora a Spring Source, que uma empresa que fomenta
tecnologia para aplicaes corporativas. O Groovy tem o framework Grails (que
Railslike),temoamparodaplataformaJavaeosuporteaocorporativoprestadopela
SpringSource,oquefazdeleumaboaopoparaempresasmaisexigentes.

AslinguagensRuby,PythoneGroovy,permitemtrabalhartambmcomframeworksDesktopparacriaode
aplicaeslocais,comoGTKeQT,nocasodeRubyePython,eSwingnocasodoGroovy

SolutionStacks
AsSolutionStacks,comoonomediz,soPilhas(detecnologias)usadasjuntascomouma
Soluo,consisteemutilizartecnologias,linguagenseplataformasquefuncionamemharmonia
ou quetem alguma afinidade, tornandose uma configurao pronta. Para tentaresclarecer
melhorvamosaumexemplo,oLAMP.
103

AZendTechnologiesaprincipalmantenedoradaplataformaPHP
197

Captulo 6 Introduo a Arquitetura de Software

LAMP
o acrnimodeLinux,Apache,MySQLePHP, quesorespectivamente umSistema
Operacional,umServidorWeb,umSGBDeumalinguagem.MuitasaplicaesnaWebusam
LAMP,ainstalaodeumservidorLAMP,incluindocomofazeraspartesfuncionarem,muito
bemdocumentado,tornandoseumasoluocomum(oureceitadebolo,sepreferiresassim).

WISAouWINS
ApilhadesoluesbaseadaemtecnologiasMicrosoftconhecidacomoWISA,acrnimo
deWindows,IIS,SQLServereASP.NETetambmporWINS,oacrnimodeWindows,IIS 104,
.NET e MS SQL Server. Consiste no Sistema Operacional, Servidor Web, Plataforma de
AplicaeseSGBD.AssimcomooLAMPoWISA bemdocumentadoetemforteentradano
mercadocorporativo"prMicrosoft".
Obs.:ExistemoutrasSolutionStacks(masnemtodastemumacrnimobacana:)comoodaOracle:
http://www.oracle.com/technetwork/serverstorage/solaris10/documentation/integratedstacktesting
168417.pdf

MaissobreArquitetura
ArquiteturadeSoftwareumadisciplinanova,aindanoentendidacompletamentee
confundidacomEngenhariadeSoftwareeDesenvolvimento.MuitoargumentamqueoArquiteto
deSoftwareumDesenvolvedor evoludo,outrosafirma que diferente, quenobasta ter
apenasforteconhecimentodecdigomastambmdepessoas,enfim,adiscussovailonge.
Minha sugesto que localizem mais informaes em ferramentas de busca sobre a
profissoArquitetodeSoftware.ConsidereavisodoProcessoUnificado(UP)eaentrevista
comoGuilhermeSilveira,ambosaseguir:
Papel:ArquitetodeSoftware
http://www.wthreex.com/rup/process/workers/wk_archt.htm

QualorealpapeldoArquitetodeSoftware?
http://www.infoq.com/br/news/2010/09/realpapelarquiteto

OlivrodisponibilizadopelaMicrosofttambmumtimopontodepartida,servindo
como um Cookbook105 para vrios cenrios e problemas. Ele est mencionado a seguir na
bibliografiadocaptulo.

Bibliografia
[FOWLERBOOK]FOWLER,Martin.PadresdeArquiteturadeAplicaesCorporativas.
1a.ed.Editora:Bookman,2006.

104
105

InternetInformationServices(IIS)oServidorWebdaMicrosoft,concorrentedoApache
LivrodeReceitas
198

Captulo 6 Introduo a Arquitetura de Software

[FOWLERPAPER]FOWLER,Martin.Whoneedsanarchitect?.Disponvelemhttp://in
gmbh.de/uploads/media/whoNeedsArchitect.pdf.Acessoem23dedezembrode2011.
[MARTINx2]MARTIN,RobertC.Princpios,PadresePrticasgeisemC#.1a.ed.Editora
Bookman/Artmed,2011.
[MAAG]MicrosoftPatterns&PracticesTeam.MicrosoftApplicationArchitectureGuide.
Disponvelemhttp://msdn.microsoft.com/enus/library/ff650706.aspx.Acessoem23dedezembro
de2011.
[DEEPAK]ALUR,DEEPAK;CRUPI,JOHN;MALKS,DAN.CoreJ2EEPatterns.2a.ed.Editora:
Campus,2004.

199

Captulo 7 Modularizao

Captulo7Modularizao
Estecaptulodedicadoaumacaractersticaimportantssimanoprojetodesoftware:
reuso.Bonsdesenvolvedoresprojetamparaoreuso,ouseja,buscamcriarsoftwaresemmdulos
reaproveitveisentrediferentesprojetos.Mdulosquesejamfacilmenteencaixveisetenham
um baixa curva de aprendizado, ou seja, que encoraja os novos programadores e
desenvolvedoresautilizlos.
Mdulos, pedaos de software, tem uma propriedade essencial, so disponibilizados
atravsde uma API, e tambm tem propriedades especiaisque os fazem serem classificados
como:Toolkit's(CaixasdeFerramentas),BibliotecasdeClasses,ComponentesouFrameworks.
Estasnuancesseroabordadasnostpicosaseguir.

API's
API o acrnimo de Application Programming Interface, em portugus Interface de
ProgramaodeAplicaes(ouAplicativos).Consistenaespecificaoepadresestabelecidos
por softwares para permitir sua utilizao, incluindo procedimentos, funes, estruturas de
dadoseclasses.Apalavrachaveaquiinterface.
OsprogramadoresutilizamasAPI'sdeoutrosprogramasparaconstruirnovosprogramas
enovasAPI's.Quandoasinstrueslidamcomdadoseinformaesmaisabstratas,chamamos
de API de alto nvel (de abstrao), por exemplo, um mtodo para salvar um texto em um
arquivopodeterdoisargumentosassim:
String texto = "Um texto";
String arquivo = "c:/docs/texto.txt";
File.save(texto, arquivo);

Neste exemplo h um mtodo esttico save que recebe dois argumentos: o texto e o
arquivo, ambos strings. uma API de alto nvel j que abstrai detalhes subjacentes, desta
maneira,umaAPIatmesmomenosflexvel.UmaAPIdebaixonvellidacomdadosmais
puros,brutos.Porexemplo,omtodoparasalvarpoderiareceberumarraydebytes,fazendo
comquenosapenastextospossamsersalvosmasqualquertipodedadoemqualquermeio,
porexemplo,usandoumOutputStream:
200

Captulo 7 Modularizao

byte[] bytes = "Um texto".getBytes();


FileOutputStream saida = new FileOutputStream("c:/docs/texto.txt");
File.save(bytes, saida);

QuandosefalaemlinguagensorientadasaobjetosaAPIgeralmente implementada
comclasseseinterfacesquedisponibilizammtodosparamanipularalgumtipoderecurso.Toda
aestruturapblicadisponvelentendidacomosendoaAPI.
Porexemplo,considereumaclasse Calc,ondesofeitasasquatrooperaesbsicascom
nmerosinteiros:
ClasseCalceasquatrooperaesbsicas:
public class Calc {
public static int soma(int a, int b)

return a + b;

public static int divide(int a, int b)

return a / b;

public static int subtrai(int a, int b)

return a - b;

public static int multiplica(int a, int b) {

return a * b; }

OimportanteasaberqueaimplementaonoimportaquandosefalaemAPI's,a
importnciaestnasinterfaces,ouseja,nosnomeseassinaturasdasclasses,atributosemtodos
pblicos.QuandousamosaclasseCalcnsavemosassim:
ClasseCalcsendousada:
int r1 = Calc.soma(4, 2);
int r2 = Calc.subtrai(4, 2);
int r3 = Calc.divide(4, 2);
int r4 = Calc.multiplica(4, 2);

conhecidoqueCalctemummtodoestticosomaquerecebedoisargumentosinteiros
edevolveuminteiro.Isto aAPI,ouseja,ainterfacede Calc.Ainterfacedeumaclasse
formada por todos os membro (campos e mtodos) disponibilizados externamente, ou seja,
aquelesquenosoprivados.AinterfacedeCalcpodeserdescritaassim:
APIdeCalc:
// l-se: o mtodo soma recebe dois argumentos inteiros e retorna um inteiro
Calc.soma(int, int):int
Calc.subtrai(int, int):int
Calc.divide(int, int):int
Calc.multiplica(int, int):int

TodasaslinguagensdisponibilizamumaAPI,paracitarumexemplo,considereStringsno
Java:
APIdejava.lang.String:
String palavra = "aspecto";

201

Captulo 7 Modularizao

// mtodo "caractere em ..."


System.out.println(palavra.charAt(3)); // imprime "e"
// assinatura, isto , API de charAt:
String.charAt(int):char

A classe java.lang.String do Java disponibiliza vrios mtodos, cada qual com seus
argumentoseretornos,caracterizandoaAPIString.

APInaslinguagens
As linguagens de programao alm de disponibilizarem construes sintticas e
semnticas para a implementao de algoritmos tambm trazem um conjunto de classes,
interfacesemtodosparalidarcomsituaeseproblemascomunscomo:manipulararquivos,
comunicarse em rede, lidar com bancos de dados e at construir interfaces grficas, entre
outros.
Estesconjuntosdeclasses,funeseestruturasdedadossochamadosporvriosnomes,
conformeaplataformaelinguagem,porexemplo:

Java:chamadodeJavaAPI106;

Python:chamadodeStandardLibrary107(BibliotecaPadro);

C/C++:chamadodeSTL,acrnimodeStandardTemplateLibrary 108(Biblioteca
PadrodeGabaritos(segundoWikipedia109));

C#:erachamadode BCL,acrnimode BaseClassLibrary (BibliotecadeClasses


Base),erecentementede.NETFrameworkClassLibrary110;

Ruby:chamado,assimcomonoPython,deStandardLibrary(ouSTL);

Para citar um exemplo mais concreto, a linguagem Java disponibiliza uma srie de
pacotes,cadaqualcomumcontexto,paralidarcomproblemastriviaiscomopodeservistona
figuraaseguir:

106

http://docs.oracle.com/javase/7/docs/api/

107

http://docs.python.org/2/library/
http://www.cplusplus.com/reference/
http://pt.wikipedia.org/wiki/Standard_Template_Library
http://msdn.microsoft.com/ptbr/library/gg145045(v=VS.110).aspx

108
109
110

202

Captulo 7 Modularizao

JavaAPI:conjuntodepacoteseclassesdisponibilizadosjuntocomalinguagemJava

ParacadatipodesituaoumaAPIdisponibilizada,contextualizadaemumpacote,por
exemplo,oMath.UsandooMathpossvelexecutarvriasfunesmatemticas:

JavaMathAPI:oscamposemtodossoaAPIdeMath

[[melhoraraexplicaodeumaAPIouintroduzir'definindoAPI']]

DocumentaodeAPI's
AsAPIso,geralmente,bemdocumentadas.Comoexemplo,considereadocumentao
da API do Google Maps: https://developers.google.com/maps/?hl=ptbr. O Google fornece a
documentaonecessriaparadesenvolvedoresWebadicionaremoMapsnosseussites.Outros
exemplos de documentao de API's so a do jQuery http://api.jquery.com/, CakePHP
http://api.cakephp.org/,Pythonhttp://docs.python.org/library/,entreoutros.

203

Captulo 7 Modularizao

NocasodeprogramascriadoscomJavansfazemosissousandooJavadocquejfoi
discutidoanteriormentenotpico[[linkar]]NoComente,Documente!

ImplementandoAPI's
Enquanto desenvolvedores quando criamos classes, interfaces e dados que sero
reutilizados temos que raciocinar sobre a API da nossa soluo. Por exemplo, digamos que
disponibilizaremosumconjuntodeclassesparagerarPDFs,quaissoosnomesdestasclasses,
assinaturasdosmtodoseemquesequnciasoutilizadasparaqueumPDFsejagerado?Isto
planejaraAPI.
Vamosaumexemploprtico.Considereanecessidadedoclculocomdatas,entreas
funcionalidadesdigamosquequeiramossaberadiferenadediasedemesesentreduasdatas.
Se tu j sum programador com um pouco decaminhada j deve perceber que tem vrias
maneirasdefazerisso.ParaesteexemplovouoptarpelacriaodeumaclassedeIntervalode
Tempo(IntervaloTempo),queguardardoisinstantes,incioefim,efarosclculossobreestes
instantes.Nesteexemplo,vouimplementarumaAPIparalidarcomIntervalo:
APIparaIntervalo:
class IntervaloTempo {
private Date inicio;
private Date fim;
public IntervaloTempo(Date inicio, Date fim) {
this .inicio = inicio;
this .fim = fim;
}
public long getDias() {
long decorrido = fim.getTime() - inicio.getTime();
return (int) (decorrido / (24 * 60 * 60 * 1000));
}
}
// situao de uso:
DateFormat df = DateFormat.getDateInstance();
IntervaloTempo intervalo = new IntervaloTempo(df.parse("12/10/2012"),
df.parse("15/10/2012"));
System.out.println(intervalo.getDias()); // imprime 3

AAPIdoIntervaloTempoconstitudapelacriaodoobjetopassandoincioefimelogo
apschamandoosmtodosquecalculam ointervalo.No exemplofoi usado dias,mas nada
impedequenovosmtodossejamadicionadospermitindofazerasseguintechamadas:
Situaodeuso,umlaboratrioparaacriaodeAPI:
// situao de uso:
DateFormat df = DateFormat.getDateInstance();
IntervaloTempo intervalo = new IntervaloTempo(df.parse("12/10/2012"),

204

Captulo 7 Modularizao

df.parse("15/10/2012"));
System.out.println(intervalo.getDias());
System.out.println(intervalo.getMeses());
System.out.println(intervalo.getHoras());
System.out.println(intervalo.getSegundos());

AmelhormaneiradeplanejarumaAPIconsiderarsuassituaesdeuso,ouseja,como
osobjetosserocriadosecomoosmtodosserochamados.estalgicaqueimporta.Como
vistonocdigoanterior,podemosimplementarotempoemmeses,horasesegundos,dpara
perceberpelachamadadomtodoaassinaturadomtodoaAPI.
SeaAPIaestruturaeassinaturadasclasses,objetosemtodos,umacoisaquetemque
ficar clara que modificaes no cdigo podem ou no modificar a API. Por exemplo,
poderamosmudaraformacomooclculodediasrealizado:
AlteraesnocdigonemsempreimplicamemalteraesnaAPI:
class IntervaloTempo {
private static final long UM_DIA_EM_MILLIS = 24 * 60 * 60 * 1000;
...
public long getDias() {
long decorrido = fim.getTime() - inicio.getTime();
return (int) (decorrido / UM_DIA_EM_MILLIS);
}
...
// sem alteraes na situao de uso:
DateFormat df = DateFormat.getDateInstance();
IntervaloTempo intervalo = new IntervaloTempo(df.parse("12/10/2012"),
df.parse("15/10/2012"));
System.out.println(intervalo.getDias()); // imprime 3

Sealteraesnocdigonoimplicamemalteraesnasituaodeuso,entoaAPIno
foialterada,ouseja,osnomes,asassinaturas,forammantidas.Aalteraodomtodo getDias
para getDiasDecorridos, por exemplo, estaria impondo alteraes API, bem como se
decidssemosalterarotipoderetornodelongparadouble.
Penseduasvezesantesdealterarnomedeclasseseassinaturasdemtodos,poisimplicaem
mudanadeAPIepossvelquebradeclientes,ouseja,outrasclassesquedependemdaAPI

Existeumarestriomuitoimportanteemsairalterandoosnomesdosmtodospblicos.
Elesjpodemestarsendousadosporoutrasclasses,assimsendo,alterlospoderiafazeroutras
classesquebrarem,umtipodequebraconhecidapelamudanadaAPI,isto,alteraesem
dadospblicosdasclasses,quecomoasclassessecomunicamcomasoutras.
TodososPrincpiosdeProjetosoimportantesparaimplementaodeAPI,umdelestem
bastantenfase:

PrincpiodoMenorPrivilgio:tudoprivadoatquesejanecessriotornarpblico.
LembrequeaAPIformadapelosmembrosnoprivadosdaclasse,ouseja,tornar
205

Captulo 7 Modularizao

ummembronoprivado,sejapblicoouprotectedporexemplo,disponibilizado
comoAPI;

ProjetandoAPI's
Projetar API's no diferente de projetar linguagens de programao. Muito pode se
aprender com a histria destes programadores, minha sugesto de leitura a Filosofia do
Ruby,umaentrevistacomYukihiroMatsumoto,traduzidaporFbioAkitaedisponvelaqui:
http://www.akitaonrails.com/articles/2006/10/09/entrevistacomyukihiromatsumotopartei

Pequenosprincpiospodemajudaracriarlinguagensdequalidade,estesprincpiossoos
mesmosusadosparaprojetarAPI's,eestolistadosabaixo:

Umalinguagemdeveserprevisvel:deveseraexpressodeideiashumanasefcil
parahumanosentenderem,mesmoquesejaexecutadaporcomputadores;

Uma linguagem deve ser consistente: coisas semelhante devem parecer


semelhantes,coisasdiferentesdevemparecerdiferentes.Istopodeajudaraspessoas
quejaprenderamumapartedalinguagemaaentendermaisfacilmenteorestante.

Uma linguagem deve ser concisa: novas linguagens so criadas para reduzir o
cdigoredundante, se elasexigem maiscdigo do queantespara fazer a mesma
coisa,entonoestonocaminhocerto.

Umalinguagemdeveserconfivel:elasdevemsercorretasenocausarsurpresas,
elasdevemresolvermaisproblemasdoquecriar.

Uma linguagem deve ser depurvel: quando algo d errado as pessoas podem
quererconsertarounomnimosaberondeerraram,aslinguagensdevemfornecer
estahabilidade.

VoltandoaoexemplodaAPIparaIntervalodeTempo.Assimcomodevolveosdias
necessrio tambm devolver o tempo em meses. Para ser previsvel e consistente podemos
implementarnomesmosentidoquefoiimplementadooclculodedias:
APIPreditivaeConsistente:
class IntervaloTempo {
private static final long UM_DIA_EM_MILLIS = 24 * 60 * 60 * 1000;
// ...
public long getDias() {
long decorrido = fim.getTime() - inicio.getTime();
return (int) (decorrido / UM_DIA_EM_MILLIS);
}
public long getMeses() {
// clculo de meses
}
// ...
// sem alteraes na situao de uso:
DateFormat df = DateFormat.getDateInstance();

206

Captulo 7 Modularizao

IntervaloTempo intervalo = new IntervaloTempo(df.parse("12/01/2010"), df.parse("15/10/2012"));


// se para contar os dias usamos getDias, para contar os meses seria?
System.out.println(intervalo.getDias());
// getMeses! isto ser previsvel e consistente
System.out.println(intervalo.getMeses());
// assim seria inconsistente e imprevisvel, visto que cada mtodo tem um padro
System.out.println(intervalo.calculaMeses());
System.out.println(intervalo.contaAnos());

ManteraAPIclaraecoerenteimportanteparaterumamelhorqualidade,eparatornar
debugvel importante fornecer informaes teis, por exemplo, o toString pode ajudar a
consultaroobjetodeIntervalo:
TornandoDebugvel(depurvel):
class IntervaloTempo {
private static final long DIA = 24 * 60 * 60 * 1000;
private Date inicio;
private Date fim;
public IntervaloTempo(Date inicio, Date fim) {
this .inicio = inicio;
this .fim = fim;
}
// ...
@Override
public String toString() {
DateFormat df = DateFormat.getDateTimeInstance();
return "entre " + df.format(inicio) + " e " + df.format(fim);
}
// ...
// situao de uso:
DateFormat df = DateFormat.getDateInstance();
IntervaloTempo intervalo = new IntervaloTempo(df.parse("12/10/2010"), df.parse("15/10/2012"));
// qual o estado do intervalo neste instante:
System.out.println(intervalo);
// imprime: 12/10/2012 00:00:00 <->15/10/2012 00:00:00

AsAPI'sdevemserconfiveis.Confiabilidadeserfuncionalemcondiesnormaisde
operaoassimcomoemcondiesexcepcionais.Acreditoquesejaaoatributoqualitativomais
difcildealcanarnaconstruodeAPI's,assimcomosistemasinteiros.Considereoclculode
meses,serqueimplementadodestamaneiraeleconfivel:
Confivelouno:
class IntervaloTempo {

207

Captulo 7 Modularizao

private static final long DIA = 24 * 60 * 60 * 1000;


private static final long MES = 24 * 60 * 60 * 1000 * 30;
private Date inicio;
private Date fim;
public IntervaloTempo(Date inicio, Date fim) {
this .inicio = inicio;
this .fim = fim;
}
public int getMeses() {
long inicioMilis = inicio.getTime();
long fimMilis = fim.getTime();
long decorridoMilis = fimMilis - inicioMilis;
return (int) (decorridoMilis / MES);
}
// ...

OnicojeitodetestaraconfiabilidadesubmeteraAPIasituaesdeusotantonormais
quantoexcepcionais.EstaAPIpodeforneceronmerocorretonamaioriadavezes,maspode
falharemalgunscasos,porexemplo:
FalhasnaAPIdeIntervalo:
DateFormat df = DateFormat.getDateInstance();
IntervaloTempo intervalo1 = new IntervaloTempo(df.parse("12/10/2012"), df.parse("15/11/2012"));
// responde 1, est correto
System.out.println(intervalo1.getMeses());
IntervaloTempo intervalo2 = new IntervaloTempo(df.parse("01/02/2012"), df.parse("01/03/2012"));
// responde 0, est INCORRETO
System.out.println(intervalo2.getMeses());

Considere a leitura dos seguintes tpicos que podem te ajudar a desenhar API's de
qualidade:ProgramandoePrincpiosdeProjeto.

Tratamentodasentradaseexcees
[[]]

Toolkits
Todobomdesenvolvedorquerresolverseusproblemasatuais,efuturos.Certasatividades
na programao podem ficar bem massantes se forem realizadas de forma repetitiva, por
exemplo,sequnciasdecdigousadopararesolverumproblemapontual,comonoexemplodo
clculo de intervalo. Desenvolver envolve modelar e implementar a lgica que soluciona o
problema,mastambmenvolveemcriarcondiespararesolverproblemascomuns.

208

Captulo 7 Modularizao

[[introduziraabordagemdolivroGoFsobretoolkits]
fortemente recomendado que tu cries programas que te ajudem a programar,
programas que criam programas. Isto pode ser alcanado empacotando classes, interfaces e
funes em uma biblioteca(uma BibliotecadeClasses) quepodeserembutidaem qualquer
projetonovo.EsteoconceitodeumaCaixadeFerramentas,ouToolkit.

Motivao
Toolkitspodemsercriadoscomduasmotivaesbemclaras:

Estenderalinguagem:significasuprirumadeficinciadalinguagem,atentativade
incluirmdulosquetuachasquejdeveriamvirnalinguagem,masnovem.Por
exemplo,sabidonasrodasdeprogramadoresqueaAPIdedatadoJava,incluindo
DateeCalendar,soumpnosaco,muitoruins.Paratentardarumasoluomais
adequada ao clculo de tempo, seja data ou hora, Brian S O'Neill e Stephen
ColebournecriaramoJodaTime111,queumabibliotecadecenteparalidarcomdatae
hora,muitobemaceitapelacomunidadededesenvolvedores.

Atacar um problema particular: ou seja, procurar desenvolver solues para


problemaspontuais,maisespecficos,masigualmenteimportantes,porexemplo,a
biblioteca de validao de epubs ePubChecker112, que disponibiliza as classes
necessriasparavalidardocumentosdistribudosnoformatodeepub.

Toolkit!=Framework
bemcomumconfundirtoolkitcomframeworkeviceeversa.Aprincipaldiferenaque
frameworks geralmente definem estruturas, ou seja, classes abstratas, interfaces e outras
construes, que implementam parte da funcionalidade, a parte comum, e delegam a parte
varivelparaosprogramadoresimplementarem,estendendoclasseseimplementandointerfaces,
isto um framework. Toolkits no so parciais, eles implementam a funcionalidade
inteiramenteenonecessitamdeextensoouimplementao,nohcontrato.
Frameworkincompleto,toolkitcompleto,isto.

UtilizandoToolkits
possvelencontrarvriostoolkitsdistribudossobsoftwarelivreemgrandesrepositrios
de projetos como o Google Code, GitHub e CodePlex 113, que so conhecidos por hospedar
respectivamenteprojetosJava,PHP/RubyeMicrosoft/.NET(noquenohospedemprojetos
paraoutrasplataformas).
Falando de Java, e quando se tenta estender a linguagem com toolkits, os mais
conhecidossoospresentesnosprojeto commons (comum)daApacheFoundation,disponvel
aqui: http://commons.apache.org/. O commonslang, por exemplo, traz funcionalidades no

111
112
113

OJodaTimepodeservistonapginaoficial:http://jodatime.sourceforge.net/
OePubCheckerumprojetohospedadonoGoogleCode:http://code.google.com/p/epubcheck/
RepositriosdeProjetos:http://code.google.comhttp://github.comhttp://codeplex.com
209

Captulo 7 Modularizao

presentes na API do Java como capitalizar palavras, fazer clculos com nmeros racionais e
implementarmaisfacilmenteequals,hashCodeetoString.
Para fornecer um exemplo prtico, considere a utilizao de algumas funcionalidades
comStringsnopresentesnalinguagemJava,maspresentesnotoolkitcommonslangdaApache.
OprimeiropassoparausarotoolkitiratositedaApacheCommonsLangefazerodownload,
conformeilustraoaseguir:

SitedoProjetoCommonsdafundaoApache:fontedodownloadedocumentao

Baixeaversomaisapropriada,nocaso,Binariesaopoemquebaixamosapenasa
biblioteca,eemSourcebaixamosocdigofonte.FiqueatentoaversomnimadoJava,por
exemplo, o commonslang 3.1 exige pelo menos Java 5 (Java 1.5). Como o arquivo vem
compactado,necessriodescompactloparaobterabiblioteca,o.jar.Apsdescompactaro
commonslangtuversosseguintesarquivos:

Arquivosdocommonslang:estopresentesabiblioteca,javadoc,cdigofonteetestes,nestaordem.

Na prtica, precisamos apenas do binrio, neste exemplo o arquivo commonslang3


3.1.jar. O javadoc e sources so teis para incluir no IDE e habilitar a documentao ao
autocompletarevercdigofonteaoclicar,masnosoobrigatrios,emproduonotemvalor
algum.
NoJava,programas, toolkits, frameworks,sempresodistribudoscomobibliotecasna
forma de Arquivo Java, em ingls Java ARchive, o que d origem a extenso .jar. Para
utilizarumtoolkitnecessriobaixloeincluiroarquivo(ouosarquivos).jarnoclasspath,ou
210

Captulo 7 Modularizao

usandooNetBeansouEclipse,necessrioincluiro.jaremPropriedades>Bibliotecas.Aseguir
umaimagemquemostraainclusodocommonslang33.1.jarnoprojeto:

Adiodoarquivo.jarnoNetBeans

Apsestaoperaoparausara toolkit bastaimportaropacoteeutilizarasclasses.Por


exemplo,ocommonslangvemcomumutilitrioparaStringsquepermitefazervriasoperaes,
entre elas verificar se uma String numrica atravs de StringUtils.isNumeric. As classes do
commonslang estodisponveisnopacoteorg.apache.commons.lang3,eumasituaodeuso
podeservistanailustraoaseguir:

ImportaoeusodotoolkitApacheCommonsLang

Pelalinhadecomandotambmnomuitocomplicadoutilizarumabiblioteca(sejaela
um toolkit ouum framework),apenasexigindoqueseespecifiqueolocaldoarquivo.jarno
momento da compilao. Por exemplo, considere que o cdigo fonte est em um diretrio
qualquereo commonslang33.1.jarestemumdiretrio lib dentrododiretriodocdigo
fonte.Sejaocdigoaseguir:
CdigodetestedoApacheCommonsLang:
import org.apache.commons.lang3.*;
public class Teste {
public static void main(String[] args) throws Exception {

211

Captulo 7 Modularizao

String n = "455";
if (StringUtils.isNumeric(n)) {
System.out.println("n numrico");
} else {
System.out.println("n no numrico");
}
}
}

Para compilar e executar o programa anterior necessrio executar as seguintes


instrues:
javac -cp .:lib/commons-lang3-3.1.jar Teste.java
java -cp .:lib/commons-lang3-3.1.jar Teste

Note a necessidade de especificar o jar do commonslang no caminho de classes


(classpath), tanto para compilar como para executar. Se houvessem mais jar's teriam de ser
especificados,umaumseparadospordoispontosouincluindoum asterisco(assim: -cp
.:lib/*).Outrodetalheimportantequequandooprogramaforinstaladonecessrioter,junto
com o mesmo, os jar's quais ele depende. A falta de uma biblioteca causa um erro
NoClassDefFoundErrorsemelhanteaeste:
java Teste
Exception in thread "main" java.lang.NoClassDefFoundError:
org/apache/commons/lang3/StringUtils
at Teste.main(Teste.java:6)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.lang3.StringUtils
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
... 1 more

Resumindo,introduzirbibliotecasumaatividadecomumedeveserumacompetncia
essencialdequalquerprogramador,afinal,semprequepossvelinteressantenoficartentando
reinventararoda,sabendoquandousarumabibliotecaexistentequeresolvaseuproblema.
Noreinventearoda,semprequepossveluseumabibliotecaqueresolveoseuproblema

Tambmimportantesaberescolherabibliotecacerta,algumaspodemserinstveise
outrasatconterinstruesindevidas.
cuidado,algumasbibliotecaspodemserinstveisoumaliciosasepodemintroduzirfalhasnoseu
aplicativo,sempreusebibliotecasdefontesconfiveis

DesenvolvendoToolkits

212

Captulo 7 Modularizao

Programadoresexperientespercebem,comotempo,quecertasfuncionalidadespodem
serreaproveitveis.Asoluousadaporprogramadoresamadores,copiarecolarcdigodeum
programa para outro, e a soluo usada por programadores experientes criar um projeto
separado,comtodososcdigoscomuns,quetercomoresultadoumabiblioteca(arquivojarno
Java,dllno.NET,umapastacomclassesnoPHP,etc).Abibliotecageradaincludanosprojetos
emandamento,aproveitandoasclasses,mtodoseoutrasestruturascomuns.
[[]]

ComponentesdeSoftware
[[]]

Frameworks
OsFrameworkssempreobjetivamumasituaoparticular,umproblemarecorrenteaser
resolvido.Paraestabelecerasoluoumframeworkdefineumaestruturabsica,comum,parao
problema,porissoonome(framework==arcabouo==armao).Contudo,oframeworkno
resolveporsisoproblema,eleapenasseocupadaparterepetitivadoproblema,apartefixa,j
a parte dinmica, varivel, esta tem de ser implementada pelo desenvolvedor. Em outras
palavras,umframeworkincompleto.
[[introduziraabordagemdolivroGoFsobreframeworks]]
aessnciadeumframeworkdefiniraspartescomunsedeixarganchosparaaspartes
variveis.Istoalcanadocomoauxliodeclassesabstratas,interfaces,etc,fazendocomqueos
utilizadoresdo framework implementemmtodoseforneaminformaes,emoutraspalavras,
preenchamalacuna.

Problemasquepodemserresolvidosporframeworks
[[]]

Tcnicasparaimplementao
[[]]

Opapeldametaprogramao
[[]]

LinguagensEspecficasdoDomnio
[[]]

Bibliografia
213

Captulo 7 Modularizao

[CLEANCODE]MARTIN,ROBERT.CdigoLimpo:HabilidadesPrticasdoAgileSoftware.1a.
ed.Editora:AltaBooks,2009.
[GoF]GAMMA,E.;JOHNSON,R.;VLISSIDES,J.;HELM,R.PadresdeProjeto:Solues
reutilizveisdesoftwareorientadoaobjetos.1.ed.Editora:Bookman,2000.
[JAVAEFETIVO]BLOCH,JOSHUA.JavaEfetivo.2a.ed.Editora:AltaBooks,2008.

214

Captulo 8 Padres de Arquitetura

Captulo8PadresdeArquitetura
Sobreoconhecimento
Seoconhecimentotrazproblemas,noaignornciaqueos
resolve
IsaacAsimov114

Os padres de arquitetura so organizados conforme as camadas tradicionais


mencionadas. Existem padres de arquitetura para organizar e estruturar as camadas de:
apresentao,domnioepersistncia.Nestetpicovouabordarapenasalgunspoucospadres
tradicionaisdearquiteturaparaorganizaralgicadedomnioepersistncia.Padresparaa
camada de apresentao no sero abordados, mas todos os padres so documentados por
Martin Fowler neste livro [FOWLER ARCHPAT], ento, se queres aprender bem mais sobre
arquitetura,leiao.

PadresdeArquiteturaparaLgicadoDomnio
Doispadressotipicamenteusadosparaorganizaralgicadodomnio:Transaction
ScripteDomainModel.Cadaumtemvantagensedesvantagensversaseguir.

TransactionScript
O padro Roteiro Transacional (Transaction Script TS) uma abordagem
procedimentalemmeioaocdigoorientadoaobjetos,entretantotemseuespaoeseuvalor
paraorganizarcamadasmaissimplesdedomnio.suficienteparaamaioriadasaplicaes
geraisequandono,outropadroaplicado:omodelodedomnio.
NoTSseparamosalgicaemclassesdenegcioquetemmtodosanlogosaatividade
que devem executar. Por exemplo, para um sistema de gesto devemos calcular o total de
receitasemumms.ParaistopodemoscriarumaclasseLancamentoServiceouLancamentoBusinesse
neladisponibilizaromtodoobterTotalReceitas,verocdigoediagramadeclasseaseguir:
Classedeservioemtodocomoroteirodatransao,implementaotpicadeTS:
class LancamentoService {

114

http://pt.wikipedia.org/wiki/Isaac_Asimov

215

Captulo 8 Padres de Arquitetura

double obterTotalReceitas(int mes) {


// cdigo que calcula o total de receitas do ms informado
}
// todos a lgica envolvendo lanamentos seria inserida nesta classe

CamadasdeDomnioqueusamTSsoreconhecidaspelousodeclassesdeservioounegcio

Alguns frameworks so fortemente baseados neste padro de arquitetura como o


EnterpriseJavaBeans115 (EJB),queusadoparaorganizaralgicadedomnioemclassesde
negciodistribudas.
TSopadrodearquiteturamaisfcildeentendereimplementar,masnoomaisfcilde
manteralongoaprazo

DomainModel
SegundoFowler,nopiorcaso,dealgicasermuitocomplexa,aabordagemtotalmente
orientada a objetos pode ser a melhor opo de implementao. como funciona o padro
ModelodeDomnio.NoModelodeDomnioparamodelarumnegciocomplexocriamosuma
famliadeclassesaoinvsdeumaclassedeserviocomonoTS.Porexemplo,paracalcularo
totaldereceitasteramosaclasse Receitas, Mes, Despesas, Lancamento,etc.Vejaodiagramade
classesaseguir:
[[redesenhar este diagrama no Gliffy]]

115

http://pt.wikipedia.org/wiki/Enterprise_JavaBeans

216

Captulo 8 Padres de Arquitetura

DiagramadeclassesdeumalgicaorganizadanopadroarquiteturalDomainModel

O padro Domain Model amplamente discutido no livro DomainDriven Design116


(Projeto117GuiadopeloDomnio)deEricEvans 118.Noomaisfcildeimplementar,tampouco
omaissimplesdeentender,masmaisfcildemanteralongoprazo,sendoassimrecomendado
paraimplementarsistemasquetemregrasdenegciomuitovariveis.

PadresdeArquiteturaparaPersistncia
Tambmexistemmuitospadresparapersistncia,masnestetpicopretendoabordar
doispadrestpicos:DataAccessObjecteActiveRecord.Oprimeirointegrantedospadres
JavaEE[COREJ2EE]eosegundodolivrodoFowler[EAAP].

DataAccessObject
OpadroDAO(objetodeacessoadados),segundoDeepakAlur 119(no,nooTupac
Shakur) [COREJ2EE] usado para encapsular o acesso e a manipulao de dados em uma
camadaseparadaecoesa.ODAOgerenciaaconexoerealizaacomunicaocomoservio
persistente, como um SGBD. Tipicamente, DAOs encapsulam os mtodos CRUD: Create
(criar/insert),Read(ler/select),Update(atualizar)eDelete(excluir).Aseguirumcdigode
exemploquerepresentaumDAO:
DAOsimplesparaoperaesCRUDdelanamentos:
public class LancamentoDAO {
void salva(Lancamento lancamento) {
// cdigo necessrio para executar um INSERT
}
void atualiza(Lancamento lancamento) {
// cdigo necessrio para executar um UPDATE
}

116

117
118
119

OLivroDDDmuitopopularentreosprojetistasearquitetosdesoftware:
http://www.amazon.com/dp/0321125215
ProjetonosentidodeProjetar,noProjetocomoTrabalho,fiqueatentosempre
EricEvansumrespeitadoEngenheirodeSoftwarequetrabalhaemgrandesempreendimentos
http://www.linkedin.com/in/deepakalur
217

Captulo 8 Padres de Arquitetura

void exclui(Integer idLancamento) {


// cdigo necessrio para executar um DELETE
}
Lancamento encontraPorId(Integer idLancamento) {
// cdigo necessrio para executar um SELECT
}
List<Lancamento> encontraPorMes(Mes mes) {
// cdigo necessrio para executar um SELECT WHERE
}

PresteatenonofatodeoDAOnoarmazenarestado,ouseja,elenorepresentao
modelodedomnio.Porexemplo,paraocasodaaplicaolidarcomprodutos,teremosduas
classes,aclasseProduto querepresentaomodelodedomnioeaclasseProdutoDAOquefaza
gravaoeleituradeprodutosapartirdeumafontededados.Ocdigoaseguirmostrao
processodepersistnciadeumproduto:
PersistnciausandoDAO:
Produto produto = new Produto(2333452133, "Cx.Som Edifier Max 2.1", 22.30);
ProdutoDAO dao = new ProdutoDAO();
dao.salva(produto);

UsandoDAOsapersistnciasemprerealizadacomclassesdemodelo,querepresentam
entidades,eclassesdeacessoadados,quefazemacomunicaocomumafontededadoscomo
umSGBD.OpadroDAOomaisfcildeentendereimplementar.Tambmsimplesmixlo
comoutrospadres,comooActiveRecord,quevistoaseguir.

ActiveRecord
OpadroActiveRecord(RegistroAtivo)fazcomqueoobjetodedomniotenhaalgica
denegcioetambmosmtodosparaleregravaremmeiopersistente(basesdedados).A
implementaorelativamentesimples,porexemplo,umaclasseCidadeteriaalmdemtodos
acessores(gettersesetters)osmtodossalva,atualiza,exclui,etc,vejadiagramadeclassea
seguir:

ActiveRecord:aclasseexpeosatributoseosmtodosparaacessoaomeiopersistente

O padro Active Record uma boa escolha para projetos que no tem lgica muito
complexaedomniomuitoextenso.Nestepadro,cadaclasserepresentaumatabeladabasede
dadosecadainstnciaumregistro.Classeeinstnciatemoscomandos(SQL)parafazeras
218

Captulo 8 Padres de Arquitetura

operaes,criandoumacoplamentoentreomodelodedomnioeastabelasdabasededados.A
classecidadeseriaumtantoparecidacomocdigoaseguir:
ClasseCidadecomopadrodearquiteturaActiveRecord:
class Cidade {
// a classe tem os atributos expostos por GETs e SETs,
// ou seja, um JavaBean
private int codigo;
private String nome;
private String estado;
public int getCodigo() { return codigo; }
public void setCodigo(int codigo) { this.codigo = codigo; }
public String getNome() { return nome; }
public void setNome(String nome) { this.nome = nome; }
public String getEstado() { return estado; }
public void setEstado(String estado) { this.estado = estado; }
public void salva() { // os mtodos de persistncia pertencem ao objeto
PreparedStatement cmd = null ;
try {
cmd = DB.prepareStatement("INSERT INTO cidades VALUES (?, ?, ?)");
cmd.setInt(1, this.codigo)
cmd.setString(2, this.nome);
cmd.setString(3, this.estado);
cmd.executeUpdate();
} catch (Exception e) {
throw new PersistenceException(e);
} finally {
DB.close(cmd);
}
}
public static Cidade buscaPorCodigo(int codigo) {
PreparedStatement cmd = null ;
try {
cmd = DB.prepareStatement("SELECT * FROM cidades WHERE codigo = ?");
cmd.setInt(1, this.codigo)
return relacionalParaObjeto(cmd.executeQuery());
} catch (Exception e) {
throw new PersistenceException(e);
} finally {
DB.close(cmd);
}
}

219

Captulo 8 Padres de Arquitetura

importanteressaltarqueopadrodearquiteturaActiveRecordrepresentaomodelode
domnioepersistnciacomamesmaclasse.Setivssemosdemodelarprodutos,teramosuma
classe Produto queseria,aomesmotempo,adetentoradosatributoscomocdigo,descrio,
etc,etambmosmtodosdepersistnciasalva,l,exclui,etc,vejaexemploaseguir:
PersistnciausandoActiveRecord:
Produto produto = new Produto(2333452133, "Cx. Som Edifier Max 2.1", 22.30);
produto.salva();
// ou:
new Produto(445664, "Mouse Logitech 3 botes", 57.64).salva();

O padro Active Record tambm pode ser usado junto com o padro Repository120
(repositrio),emuitocomumemabordagensDomainModel.Eletambm,digamos,a"bola
davez"emframeworksdedesenvolvimentogilparaweb,comdestaqueparaoRails121(para
Ruby)eCake(paraPHP).

Agora,todosjuntos!
Partindo do princpio de que usaremos trs camadas como ficaria a sequencia de
chamadasentreelas?Aseguirumdiagramadesequenciaqueilustraumbuscadelanamentos
pormseexibioparaousurioemumatabela:

Diagramadesequencia:representaapilhadechamadasdesdeaUIatoSGBD

A prtica de implementara delegao uma competncia essencial do programador.


Cadamdulo,classe,fazumapartedotrabalhoelidasomentecomaquiloquepertinenteaseu
nvel,oquechamadodeOrtogonalidade122.
120
121

122

http://martinfowler.com/eaaCatalog/repository.html
Ruby on Rails um framework MVC popular para Ruby que inspirou outros como Cake, Django, etc
http://www.artima.com/intv/dry3.html

220

Captulo 8 Padres de Arquitetura

Aorganizao,oagrupamentodevriosmdulos(classes)comopropsitodedefinirpartes
distintasnosistema,umatarefaarquiteturalenotrivial.Exigeumacertaexperincia.Como
sugestoconsiderelerolivrodoFowler[EAAP]e,sepretendesespecializarteemJava,leiao
livrodoTupac,opa,Deepak[COREJ2EE]:).

221

Captulo 9 Projeto e Padres de Persistncia

Captulo9ProjetoePadresde
Persistncia
Leidoinstrumento123
Setudooquetutensummartelo,entotudolheparecer
comoumprego
AbrahamMaslow's

Amaioriadosaplicativosquecriamoslidamcominformaescompostasdeestruturasde
dadoscomumaestruturabemdefinida,eessasinformaestemdeestardisponveisapso
aplicativo ser fechado ou mesmo visvel para vrias instncias do mesmo aplicativo sendo
executado localmente ou remotamente atravs de uma rede local ou internet, enfim h a
necessidadedeguardaressasestruturasdedadosemummeionovoltil,enolidarcomeles
semmemria.
Estecaptulotratadecomoimplementarpersistncia,emoutraspalavras,ummeiode
manterasinformaesacessveisusandoummeionovoltilequesobrevivamesmoapso
encerramentodoaplicativo.Naseesqueestoporvirabordareipersistnciacomoconceitoe
logoapstcnicasdeimplementaousandoSistemasGerenciadoresdeBasesdeDados,comoo
MySQL.

Persistncia
Todoprogramatemumestado,umasituaoatualdasvariveiseestruturasusadaspara
guardar as informaes durante a execuo. Diferentes linguagens em diferentes paradigmas
fazemistodeformadiferentesmaneiras,comojeradeseimaginar.Emlinguagensorientadasa
objetostradicionalconduzirerepresentaresteestadoatravsde,claro,objetos,quetemsua
estruturadefinidaatravsdeclasses,interfaces,enumeradoseoutrostipos.Comoestudodecaso
considereaestruturaaseguir:
EstruturasdeDadoscomClasses:
public class Livro {
String titulo;
123

http://en.wikipedia.org/wiki/Law_of_the_instrument

222

Captulo 9 Projeto e Padres de Persistncia

String isbn;
int ano;
Editora editora;
}
public class Editora {
String nome;
String cidadeEstado;
}

CadaregistrodeLivrorepresentadocomoumainstnciadaclasse Livro,quepossuium
relacionamentocomEditora,tambmrepresentadacomumaclasse.
Neste estudo de caso o cadastro de editoras e livros pode se dar por um aplicativo
desktop, usando alguns formulrios do Swing (JFrame) eento instanciando os objetos para
armazenarestesdados.
[[inserir figura formulrio JFrame Livro]]
Contudo ao pedir para salvar as informaes, os livros e editoras por exemplo,
necessrioconduzir,copiarestasinstnciasparaummeiopermanente,persistente.Naverdade
existemvriasmaneirasdefazeristo,comousandoarquivos.Nestecasooobjeto serializado
(convertido) em um formato armazenvel, podendo ser binrio (ver ObjectOutputStream124),
CSV (CommaSeparated Values125) ou outros formatos consolidados na indstria de software
comoXML126ouJSON.
Seporumladoarmazenarasuarededeobjetosemarquivotemsuasvantagens,em
especiala primeira eu diria que a simplicidade, poroutro lado as desvantagens aparecem
quandooaplicativomaiscomplexo.Considerequeomesmoarquivolido(egravado)por
maisdeumprograma,bem,dacomeamosprimeirosproblemasdesincronizao,emoutras
palavras,osaplicativosconcorrero127 na gravaodasinformaesepoderhaverperdade
dadosouduplicaes.
Comessascondiespodesedizerqueoarmazenamentoemarquivoviveleadequado
paraaplicativos standalone (umprocessoapenaslegravaoarquivo).Masoqueutilizarem
outras condies? Isto , lidar com o acesso concorrente s mesmas informaes no s
localmente quanto remotamente? So muitos detalhes com se preocupar, mas felizmente
sistemasassimjforamimplementadosesochamadosdeSistemasGerenciadoresdeBases(ou
Banco)deDados(SGBD).OaplicativopodeusaroSGBDparatornaraestruturapersistente.

SGBD:algunsdetalhesaconsiderar
OsSGBDspermitemquevriosprocessosacessemosmesmosdados,ficandoporconta
deleocontroledaconcorrnciadeacessoeintegridadedasinformaes.Acomunicaoentreo
SGBD e os aplicativos feita atravs de um protocolo comum (ambos devem conhecer o
124

http://docs.oracle.com/javase/6/docs/api/java/io/ObjectOutputStream.html

125

ValoresSeparadosporVrgula(oupontoevrgulasvezes)

126

http://www.oracle.com/technetwork/articles/javase/index140168.html

127

Umdosmaioresproblemasnodesenvolvimentodeaplicativoscorporativosagestoecontroleda
simultaneidadedoacesso
223

Captulo 9 Projeto e Padres de Persistncia

protocolo), assim o mesmo SGBD pode servir, ao mesmo tempo, a programas escritos em
diversaslinguagensesendoexecutadosnomesmocomputadorouremotamenteatravsdarede.
OsSGBDstemcaractersticasqueosfazemteismasquetambmdeveseravaliadasparafazer
uma boa arquitetura que no venha a trazer mais problemas do que resolver. Estas
caractersticasemgeralseroexplicadasaseguir.

Driver
ParaosaplicativosconectaremsenoSGBDnecessrioumDriver,quenadamaisdo
queumabibliotecacontendooprotocolodecomunicaodoobanco.Notequeexistemdiversos
fornecedoresdeSGBDs,comoMySQL(Oracle),PostgreSQL(Berkeley),SQLServer(Microsoft),
Firebird,DB2(IBM)eOracle(daOracle,claro),sparacitaralgunsexemplos 128.Emoutras
palavras, semeu aplicativo em Java e o banco que queroconectarme MySQL ento eu
preciso do Driver do MySQL para Java. No se desespere, nada que uma googlada no
resolva129.

Conexes
OJava,queusamoscomoexemploemtodoestelivro,seconectacomosSGBDsatravs
desockets,isto,umaconexoTCP/IPrealizadaemlocalhost(seobancoestiverlocalmente)ou
paraumipnarede.CabedizerqueumaconexoTCP/IPutilizaumaportanoPClocaleuma
portanoPCremoto.OsSGBDscostumamescutaremumaportabemdefinida,porexemplo,o
MySQLusaaporta3306,oPostgreSQL5432eoSQLServer1433.TodoSGBDapsrecebera
requisio de conexo encaminha o restante do trmite para outra porta (aleatria).
importantemencionaralgunsdetalhesimportantes:

128
129

Onmerodeportasfinita,65536paradizeraverdade,massesubtraironmero
deportasreservadasestenmerocaiumpouco.Euseiqueaindabastante,mass
para lembrar que as conexes so finitas e este o motivo das conexes serem
fechadas(pelomenosquandooaplicativofechado).

Cadaconexofazcomqueumnovoprocesso(outhread)sejacriadonoSGBD
para lidar as requisies/respostas. Isto quer dizer que cada conexo causa
consumoderecursos,isto,processamentoememria.

AlgunsSGBDstemumlimitedeconexesestabelecido,seporexemploforem100
conexes,at100aplicativospodemestarconectadosaoBancoaomesmotempoe,
se um centsimo primeiro tentar conectar, lhe ser negado. Este um detalhe
importante para decidir se seu aplicativo abrir uma conexo e fechar s no
encerramento,ouabrirefecharparacadaformulrioaberto,oucadarequisioou
cadaao(pressionardeumbotooulink,porexemplo"salvar").

[[achoqueesqueciumdetalhe:/]]

ListadeSGBDR'shttp://en.wikipedia.org/wiki/List_of_relational_database_management_systems
https://www.google.com.br/search?q=java+mysql+driver
224

Captulo 9 Projeto e Padres de Persistncia

Sparaconstar,algunsSGBDcomunicamsecomaplicativosatravsdeoutrasformasao
invsdeSockets,comoNamedPipes130ouSharedMemory131,estaltimaausadaporpadro
peloSQLServereaplicativosescritosem.NET,emboramaisrpida(maisdoquesocketsdevido
aooverheaddoTCP/IP)sfuncionaseaplicativoebancoestiveremnomesmocomputadores,ou
seja,tenhamamemriacompartilhada(maisclaroagora?).

Fornecedor
UmadecisoarquiteturalaseleodofornecedordoSGBD.Digodecisoarquitetural
porqueapsiniciarcomumcertoSGBDmuitodifciltrocloduranteoprojeto.
Primeiro,emboraamaioriadosSGBDsejamrelacionais 132 baseadosemSQL,elesno
implementamoSQLestritamente,oquecausapequenasnuancesnasintaxe,diferentesnomese
quantidadedefunesdisponveis,entreoutrosdetalhesquepodemfazerseucdigoescrito
paraumcertoSGBDRnofuncionarparaoutroSGBDR.
Segundo,aescolhadeumSGBDinfluenciaadistribuioenegociaodoseuaplicativo.
Existemopesproprietrias,pagas,gratuitas(comcondies),livresedecdigoaberto,regidos
pordiferentestiposdelicenas.Porexemplo,aimagemaseguirumscreenshotdapginade
vendasdaOracle,umdasmaispopularesempresasfornecedorasdeSGBDR:

https://shop.oracle.com/pls/ostore/f?
p=dstore:2:1019931098971740::NO:RIR,RP,2:PROD_HIER_ID:4509958287721805720011em2demaiode2012

AOracleumabemsucedidaempresadetecnologiacomvriasfrentes,nosbasesde
dados,hoje,maiode2012,aOracleaproprietriadaplataformaJava,oSGBDRMySQLe
130

http://pt.wikipedia.org/wiki/Pipe_nomeado

131

http://en.wikipedia.org/wiki/Shared_memory

132

OtermocorretoseriaSGBDR,SistemaGerenciadordeBasesdeDadosRelacionais(RDBMS):
http://pt.wikipedia.org/wiki/Banco_de_dados_relacional
225

Captulo 9 Projeto e Padres de Persistncia

umaparceiradagiganteSAP,comreceitaanualde35bilhesdedlaresemaisde100mil
funcionrios,ouseja,ddinheiro.PessoalmentejtrabalheicombasesOracleepossodizerque
agradvel;FerramentascomooSQLDevelopereoJDevelopersomuitoeficientesedevemser
levadasemconsiderao.Entretantoomaioratrativoparaasempresasosuporteegarantia
queaOracleoferece.AssimcomoaOracleexistemoutrosfornecedoresnotveiscomomesmo
regimedelicenciamento,entreosprincipais:

SQL Server: fornecido pela Microsoft especialmente desenvolvido para ser


executadoemservidoreseclustersbaseadosnaplataformaMicrosoftWindowsServer
(masclaroquetujsabias:).Algumasempresasoptampelahomogeneidadede
tecnologiaparaminimizartrabalhosdeadaptaoeerrosdeconfiguraoeassim
optam,comoexemplo,porumaestrutura100%Microsoft.[[falardesolutionstack]]

DB2:fornecidopelaIBM,temumabaserazovelefieldeempresasqueoutilizam.
TemumaintegraoplanejadacomosmainframesesistemasdaIBM,claro,comoo
z/OS, OS/400 e outros sistemas da IBM objetivando especialmente o mercado
corporativo,governamentalefinanceiro(ex.:$bancos$).

Umaobservaoimportante,emboratodostenhamumcustorazovel(poucoparauma
empresa,muitoparauma startup133)todos(Oracle,MSSQLServereIBMDB2)oferecemuma
versogratuita,commenosrecursosclaro,mastotalmentefuncionalquepodemserincludose
distribudoscomseuaplicativodadaumalicena(quedeveserlida).Listaaseguir:
http://www.oracle.com/technetwork/products/expressedition/overview/index.html
http://www.microsoft.com/express/sql/
http://www01.ibm.com/software/data/db2/express/

Livremente,existemoutrosSGBDRsbemvalenteseamplamenteutilizados.Destacamse
nestegrupooMySQLeoPostgreSQL.
OMySQLoSGBDRmaisusadomundialmenteeconhecido,informalmente,comoo
"bancodaweb".AmaioriadosWebSitesdinmicosdepequenoemdioportenaWebtem
uma base MySQL atrs. Entretanto, h um ponto a se avaliar no uso do MySQL como seu
SGBDR,aversocomunitria, opensource,licenciadopor GPL134,queumalicena "viral",
digamosqueela"contamina"seuaplicativo,oquesignificaqueseuaplicativotambmdever
terumalicenacompatvelcomoGPLeteucdigoterqueseraberto.Paratodosquecriam
seus WebSitescom PHP e MySQL, sem problemas, afinal ocdigoPHP est l, ele no
compilado,eamaiorianotemmuitoaesconder(eningumquervercdigofeioeruim),por
outroladoasuapoliticadelicenciamentoefaltadesuporteparaaversocomunitrianoto
bemvistapelomercadocorporativo,paraesteclientefinaltemoMySQLEnterprise.
OPostgreSQLtemaumentadoemadoo,naWeb,Desktopenocorporativo,aprioripor
sualicenaBSD,que,diferentedoGPL,permiteoseuusocomaplicativoscomqualquertipode
licenciamento:abertos,proprietrios,etc.OPostgreSQLtambmtemummecanismo,dialetoe
arquiteturabemsemelhanteaoOracleesefazuma timaopoparaocorporativoqueno
desejapagarporsuporteegarantia.Maslembrese,SGBDRsopensourcenotemmanutenoe
mantimentogarantido,aseguirumtrechoextradodalicenadoPostgreSQL:

133

http://exame.abril.com.br/pme/dicasdeespecialista/noticias/oqueeumastartup

134

http://www.gnu.org/licenses/oldlicenses/gpl2.0.html

226

Captulo 9 Projeto e Padres de Persistncia

"THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE


UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE,
SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS"
*Apertando a tecla SAP: O software fornecido neste distribudo como est, e a
Universidade da Califrnia no tem obrigao de prover manuteno, suporte, atualizaes,
melhorias ou modificaes. Tambm diz na licena que no h responsabilidade por danos e
perdasdecorrentesdousodosoftware(oPostgreSQL),emoutraspalavras,sehumdefeitono
SGBDReperdestetuabaseinteiraecomelamilharesdereais,oproblemanodeles.
Acho que tu me entendes quanto quero dizer que nem toda licena cabe a qualquer
empresa,certo?

JavaDataBaseConnectivity(JDBC)
A linguagem Java tem toda uma API comum que serve de interface para acessar e
manipular dados relacionais em SGBDs. O ecossistema de classes e interfaces do JDBC est
disponvelatravsdedoispacotes:java.sql(JDBCbsico)ejavax.sql(JDBCestendido).Algumas
interfacesnotveisequesousadascomfrequnciaso:

java.sql.DriverManager:usadoparafazerumaconexocomoSGBD;

java.sql.Connection:representaumaconexocomoSGBD,criaosStatements,d
acessoaosmetadadosdobanco.Deveterseumtodocloseinvocadoparaencerrara
conexo;

java.sql.Statement: representa um comando a ser submetido ao SGBD. Caso seja


necessrioinserirparmetrostemosdeconcatenlosnaStringdocomandoeporeste
motivoseuusodesencorajado(devidoaoSQLInjection135porexemplo);

java.sql.PreparedStatement: representa um comando que pode ser preparado e


parametrizado antes de ser submetido ao SGBD. O uso de PreparedStatement
desejvelaoinvsdoStatement;

java.sql.CallableStatement:representaumafunodoSGBDquepodeserinvocada.
EstasfunesdoSGBD,tambmconhecidascomoPROCs(StoredProcedures);

java.sql.ResultSet:representaumiteradorderesultadosadvindosdoSGBDapsa
execuodeumaconsulta(select)usandoumStatement.

S para constar, em outras linguagens, submeter consultas ao banco no muito


diferente, como exemplo considere o .NET da Microsoft com SqlConnection, SqlDataReader,
SqlCommandeoutrasclassesanlogas,ver:
http://msdn.microsoft.com/ptbr/library/system.data.sqlclient.aspx

Estabelecendoumaconexo
135

SQLInjectionumavulnerabilidadefrequenteemWebSiteseAplicativos
http://pt.wikipedia.org/wiki/Injeo_de_SQL
227

Captulo 9 Projeto e Padres de Persistncia

Emqualquerlinguagemoacessobasededadosseguealgumaspremissasbsicaseuma
sequnciasemelhantedeinstrues:
Premissas:
1. TerumabasededadosemumSGBDR,eumusuriocomcredenciaisdeacessoaessa
base;
2. TeroDriver(cdigocomoprotocolodecomunicaocomoSGBDR)disponvel,ativado
eincludo;
Instrues:
1. ParaoJava,registraroDriver.Essepassopode(deve)serfeitoumanicavez;
2. ConectarseaoSGBDR(usandoascredenciais);
3. SubmetercomandosaoSGBDRusandoaconexo;
4. Lidar com as respostas dos comandos (nmero deregistros adicionados, alterados ou
excludos,oumesmoosregistrosqueretornaramdeumaconsulta);
5. Fecharaconexo(essepassoimportante!);
AseguirumcdigodeexemploquedemonstraesseprocessonalinguagemPHP:
InserindoumregistronoSGBDMySQLusandoalinguagemPHP:
// considere que o mysql est instalado na mquina local e temos as credenciais,
// ento estabelecemos uma conexo
$con = mysql_connect("localhost","admin","senhasecreta");
// considere que tenhamos uma base de dados chamada "agenda", ento a selecionamos
mysql_select_db("agenda", $con);
// considere que tenhamos uma tabela chamada contatos com os campos nome e telefone,
// ento inserimos um registro
$ok = mysql_query("INSERT INTO contatos (nome, telefone) VALUES ('$contato->nome', '$contato>telefone')");
// a insero retorna true ou false caso seja bem ou mau sucedido
// tudo feito, fechamos a conexo
mysql_close($con);
https://gist.github.com/marciojrtorres/6198449

Estesmesmospassossoexecutadosdeformamuitosemelhanteemoutraslinguagens
com,excetoasintaxe,poucasalteraes,sendobemprevisvel.Porexemplo,noJavatemosum
arranjosemelhante,ocdigoaseguirmostracomoinserirumregistronoJava:
InserindoumregistronoSGBDMySQLusandoalinguagemJava:
// sabendo que o SGBD MySQL registramos o Driver:
Class.forName("com.mysql.jdbc.Driver");
// com as credenciais e considerando um banco de dados agenda estabelecmos a conexo

228

Captulo 9 Projeto e Padres de Persistncia

Connection conexao =
DriverManager.getConnection("jdbc:mysql://localhost:3306/agenda", "usuario", "senha");
// usando a conexo estabelecida criamos um comando
Statement comando = conexao.createStatement();
// com o comando executamos uma instruo que retorna o nmero de registros afetados
int linhasInseridas = comando.execute("INSERT INTO contatos VALUES ('" + contato.getNome()
+ "', '" + contato.getTelefone() + "')");
// tudo feito, fechamos a conexo
conexao.close();
https://github.com/marciojrtorres/livroaps/tree/master/javadbaccess

Esteexemplofoibemsimplificado,porexemplo,nonecessrioregistraroDrivertodas
asvezes,entointeressantedeclarloemumInicializadorEsttico136.Outraprticacomum
moveroestabelecimentodaconexoparaoutraclasse,umbuilderdeconexes,comopropsito
deencapsularoprocessoenoespalharascredenciaispelocdigo.
Nouseestaimplementaoparaumprojetosrio,elemuitosimples

A seguir vem um tpico de como estabelecer uma conexo de uma maneira mais
eficiente.

Padrodeimplementaoparaestabelecerconexescomobanco
Aimplementaoanteriordeconexoserveattulodesimplesexemplo,delongenoa
implementao adequada para um projeto srio. Ela tem imperfeies e problemas a nvel
projeto,ouseja,aimplementaofunciona,noumproblemadeprograma,umproblemade
projeto.Osproblemasestolistadosaseguir:

136

ODriversempreregistrado:oDriverdeveserregistradoapenasumavez.NoJava
issopodeserfeitocomuminicializadoresttico.

Ascredenciaisdaconexoestoembutidasnocdigo:importanteabstrairos
detalhes, incluindo as credenciais, da conexo. importante mover a abertura de
conexoparaoutraclasse,umaclassequegerenciarasconexes.

Ocomandodeveserfechado:ocomandotambmdeveserfechadoparaliberar
recursos(memria).

A conexo deve ser fechada incondicionalmente: o problema que se houver


algumerronainstruoSQL,umaexceoacontecereainstruoclose()noser
executada.Omododeresolverissocolocarasinstruesemumbloco try(tente)e
fechar a conexo e comando em um bloco finally (que executado
incondicionalmentesehouverumerroouno).Aconexosempredeveserfechada.

InicializadoresEstticos,aprendaausar:

http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html

229

Captulo 9 Projeto e Padres de Persistncia

Ogerenciamentodaconexoservistonoprximotpico,noentanto,paraapresentar
umasoluoadequadaaosproblemas1,3e4pelomenos,ocdigoaseguirsuficiente:
AdequandoaimplementaodeAcessoaoBancodeDados:
// chamaremos ela de ContatoDB
public class ContatoDB {
// este bloco inicializa a classe apenas uma vez, ento aqui fica o Driver
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException driverNaoEncontrado) {
// caso o Driver no seja encontrado o aplicativo encerrado
throw new ExceptionInInitializerError("O driver do banco est indisponvel");
// encerrar o aplicativo prudente, no h como inserir o Driver do banco
// com o aplicativo em execuo (Runtime) (ver o tpico Fail Fast)
}
}
//

mtodo usado para inserir um Contato

public void salva(Contato c) {


// importante, conexo e comando so declarados antes do try
Connection conexao = null ;
Statement comando = null ;
// aqui comea a tentativa, qualquer comando dentro do try pode ou no
// lanar uma exceo
try {
conexao = DriverManager
.getConnection("jdbc:mysql://localhost:3306/cobaia", "root", "root");
comando = conexao.createStatement();
comando.execute("INSERT INTO CONTATOS VALUES ('" + c.getNome()
+ "', '" + c.getSobrenome()
+ "', '" + c.getTelefone() + "')");
// o catch para o caso de uma exceo acontecer
} catch (SQLException erroSql) {
// neste caso, deixamos estourar, erros no devem ser omitidos
throw new RuntimeException("Houve um erro SQL", erroSql);
// o bloco finally executado sempre, seja ou no lanada uma exceo
} finally {
// as instrues abaixo so necessrias para fechar o comando
if (comando != null ) {
try { // tenta fechar o comando, isto , se j no estiver fechado
if (!comando.isClosed()) comando.close();
} catch (SQLException erroSQL) {
throw new RuntimeException("Erro SQL", erroSQL);
}
}

230

Captulo 9 Projeto e Padres de Persistncia

// as instrues abaixo so necessrias para fechar a conexo


if (conexao != null ) {
try { // tenta fechar o comando, isto , se j no estiver fechado
if (!conexao.isClosed()) conexao.close();
} catch (SQLException erroSQL) {
throw new RuntimeException("Erro SQL", erroSQL);
}
}
}
}
}
https://github.com/marciojrtorres/livroaps/tree/master/javadbaccess

Aclasseficoubemlonga,retirandooscomentrioselabemmenor,mashobenefcio
dareutilizao,considerequesejaincludoummtodosalva(Compromisso),muitasinstruesso
asmesmas,naverdade,smudaaStringSQL,oqueabreumespaoparaabstraodetodoo
processodecriaodaconexo,comandoefechamentodosmesmos.
Ocdigovistodemonstraasequnciaidealdeinstrues,liberandorecursos,protegendo
deexcees,masaindanomodularosuficiente.Outrasquestestambmficamemaberto,
questesarquiteturais,algumasdelasso:

Abrir e fechar a conexo todas as vezes ou abrir uma conexo e deixla sempre
abertadurantetodaavidadoaplicativo?

Paraabstrairoestabelecimentoeencerramentodaconexo,seriamelhorcriaruma
superclasseeestendlaouumaclasseauxiliareusla?

Asexceespoderiamsersuprimidasaoinvsderelanadas?

Seconseguesimaginarmaisquestesacercadaimplementaoentoestsnocaminho
certo.

Gerenciamentodaconexo
Umadecisoarquitetural,quefardiferenanaescalabilidadedoaplicativo,selecionar
umaestratgiaparaabrirefecharasconexes.Conexessofinitas,ouseja,existeumlimitede
conexessuportadaspeloSGBD,logoapenasumacertaquantidadedeaplicativospodemacessar
oSGBDsimultaneamente.
Estadecisomuitoafetadapelocontextodoaplicativo,porexemplo,seeledesktopou
web.Emcadaumdelesexistemopesdiferentesdedefinirotempodevidadeumaconexo.
Indiferente, seo propsitoprincipal evitara quebra doaplicativo, seja porfalta de
conexesouinterfernciasnestas,aopomaissimpleseseguraabrirefecharaconexoa
cadainteraocomoSGBD.Colocandoemumexemplo,considerequetenhamosdeinserirum
registro no SGBD, ns abrimos a conexo para executar o comando insert e logo depois a
fechamos.

231

Captulo 9 Projeto e Padres de Persistncia

ParaevitarproblemasdeindisponibilidadedoSGBDexperimentefecharaconexoomaisrpido
possvel
Conexessofinitas,ouseja,umdadoSGBDpodelidarcomnconexessimultneas,emesmoque
possalidarcom1milho,cadaconexoconsomerecursosdoservidor(CPU,Memria)

DeixaraconexoabertaomenortempopossvelajudaaliberaroSGBDparaatender
outrosaplicativos,ouseja,osaplicativosnocairoporindisponibilidadedoSGBD.Aseguirum
exemplodeabre,executaefecha:
Abre,executaefecha!
// ... em uma classe de acesso a dados um mtodo salva:
public void salva(String nome, String telefone) {
String sql = "INSERT INTO CONTATOS VALUES ('" + nome + "', '" + telefone + "')";
Connection conexao = null ;
try {
// abre conexo:
conexao = DriverManager.getConnection("jdbc:mysql://localhost:3306", "user", "senha");
// executa instruo:
conexao.createStatement().execute(sql);
} catch (SQLException erroSql) {
throw new RuntimeException(erroSql);
} finally {
if (conexao != null) {
// fecha conexo:
try { if (!conexao.isClosed()) conexao.close(); }
catch (SQLException erroSQL) { throw new RuntimeException(erroSQL); }
}
}
}

Nestaestratgiaaintenomanteraconexoabertaomenortempopossvel,sendoque
norecomendadofazeroutrasatividadesouexecutaroutroscomandosquenoprecisamda
conexoestabelecida.Emoutraspalavras,seaconexonomaisnecessria,fechea.
Estcomdvidadecomovaigerenciaraconexo?Ento,abre,executaefecha!

Abrir e fechar a conexo a cada instruo a escolha mais prudente para evitar a
indisponibilidadedoSGBD, masporoutrolado notcnicacomamelhorperformance.
Existeumcusto,derecursosetempo,paraabrireparafecharumaconexo.NegociaesTCP/IP
temdeserfeitas,pacotesviajamnarede,oSistemaOperacionaldisponibilizaumSocket,ou
seja,somuitos "atores" envolvidosnoprocesso.Otempodeexecuodiferentepara,por
exemplo, executar 100 instrues abrindo e fechando a conexo para cada um, ou abrir a
conexo paraexecutaras100instruesesento fechar. Ou seja,asinstruesaseguir,
teriamtemposdiferentesdeexecuo:
[[inseririnstruescommesmaconexoouconexoporinstruo]]

232

Captulo 9 Projeto e Padres de Persistncia

FazendoInsert's,Update'seDelete's
[[]]

FazendoQueriesemanipulandoResultSets
Primeiro,sobreapalavraQuery137,elasignificaoatodeperguntar,maisliteralmente,ou
consultar,maisclaramente,obancodedados.Emqualquerlinguagemfazerconsultasaobanco
envolve tipicamente:conectar,submetera query,lidarcomosresultados,liberarosrecursos
alocados e desconectar. O tipo e forma como os resultados da query so devolvidos bem
variado, por exemplo, em Java devolvido um objeto ResultSet, que itervel, em PHP o
resultadopodeserlidocomoumarrayassociativo.

ProtegendocontraSQLInjection
[[]]

MapeamentoObjeto/Relacional
[[]]

PadresdeArquiteturaparaPersistncia
[[]]

DAO,ActiveRecord,DataMapper
[[]]

CarregamentodeAssociaes
[[]]

Controledeconcorrncia
Ascoisasandammuitobemquandoseuaplicativostandalone,ouseja,eleacessauma
basededadosexclusivaparaele,sejaumarquivo(ex.:CSV),umSGBDlocal(ex.:SQLite,Access
MDB, Microsoft SQL Server Compact) ou mesmo um SGBD no modo servidor, mas que
utilizadoapenaspeloaplicativolocalmenteemlocalhost.Osproblemascomeamnomomento
emqueestesdadossocompartilhados,lidosegravados,pormaisdeumainstnciadeseu
aplicativo,atravsdaredeporexemplo,oumesmocompartilhadocomoutrosaplicativosque
137

NoBrasilpercebesequeopessoalpronunciaQuerycomoqurienquantoapronnciaoriginalquiri(como
renroladodoingls),dvidas?Vejaaqui:http://translate.google.com/#en/pt/query
233

Captulo 9 Projeto e Padres de Persistncia

tambmteminteressenestesdados.Nestecontextodizemosqueosaplicativosacessamosdados
deformaconcorrente,ouseja,existemsituaesemquemaisdeumaplicativoestacessandoa
mesma informaoeat tentando atualizla. Vriassituaes conflitantes podem acontecer,
paracitarumexemplo,podemosestareditandoumregistroqueoutrousurioexcluiueteruma
surpresaaotentarsalvar.

Ausente,a.k.a.LastWins
[[]]

Pessimista
[[]]

Otimista
[[]]

Bibliografia
[JDBC]ORACLE.JDBCDatabaseAccess.
http://docs.oracle.com/javase/tutorial/jdbc/index.html.Acessoem20deDezembrode2011.

[EAAP]FOWLER,Martin.PadresdeArquiteturadeAplicaesCorporativas.1a.ed.Editora:
Bookman,2006.
[COREJ2EE]ALUR,Deepak;CRUPI,John;MALKS,Dan.CoreJ2EEPatterns.2a.ed.Editora:
Campus,2004.

234

Parte 4: Controle da Qualidade

PARTE4:CONTROLEDAQUALIDADE

235

Captulo 10 Garantia da Qualidade de Software

Captulo10GarantiadaQualidade
deSoftware
[[]]

236

Captulo 11 Instrumentao e Depurao

Captulo11Instrumentaoe
Depurao
[[]]

237

Captulo 12 Teste de Software

Captulo12TestedeSoftware
Erros,DefeitoseFalhas
Heisenbugs
[[]]

Testes
TiposdeTeste
EstratgiasdeTeste
Testesestticos:PMD,Findbugs.
Testesunitrios:JUnit
Lidandocomdependncias:Fakes,StubseMocks?

CoberturadeTestes
StatementCoverage
[[]]

BranchCoverage
[[]]

DecisionCoverage
[[]]
238

Captulo 12 Teste de Software

ProgramandocomTestes
[[]]

ProgramaoAssertiva
[[pg144livroProgramadorPragmtico]]

DesenvolvimentoGuiadoporTestes(TDD)
[[]]

Bibliografia
[TDD]BECK,Kent.TDDDesenvolvimentoGuiadoporTestes.1a.ed.Editora:Bookman,2010.

239

Eplogo

Eplogo
[[]]

240

Apndice: [[]]

Apndice:[[]]

241

S-ar putea să vă placă și