Upload
elliando-dias
View
1.140
Download
1
Embed Size (px)
DESCRIPTION
Citation preview
Cristina T. CerdeiralPeter P. Lupo
Treinamento TABA
PrincipaisPrincipais FrameworksFrameworks eeDocumentaDocumentaççãoão
Apache Log4jApache Log4j
Tópicos• Logging• Antes do Log4j• Exemplo de API de Logging• Log4j• Eventos de Log• Logger• Level• Exemplo• Appenders & Layouts• Appenders Disponíveis• Layouts Disponíveis• PatterLayout• Configuração
• BasicConfigurator• PropertyConfigurator• DOMConfigurator• Performance• Hierarquia de Loggers
LoggingLogging
• “Diário de bordo”� Histórico de execução
• Depuração� Vantagens
� Instruções persistentes
� Sessões persistentes
� Multithreading
� Procedimentos recursivos
Antes do Log4jAntes do Log4j
publicpublic staticstatic voidvoid mainmain (String[](String[] argsargs) {) {SystemSystem.out..out.printlnprintln((““Vai executar oVai executar o mainmain:: argsargs == ”” ++ argsargs););//...//...
}}
privateprivate staticstatic finalfinal booleanboolean DEBUG =DEBUG = truetrue;;
publicpublic staticstatic voidvoid mainmain (String[](String[] argsargs) {) {ifif (DEBUG) {(DEBUG) {
SystemSystem.out..out.printlnprintln((““Vai executar oVai executar o mainmain:: argsargs == ”” ++ argsargs););//...//...
}}}}
Exemplo de API deExemplo de API de LoggingLogging
publicpublic classclass LogLog {{protectedprotected staticstatic javajava..ioio..PrintStreamPrintStream streamstream;;protectedprotected staticstatic booleanboolean enabledenabled == truetrue;;
publicpublic staticstatic voidvoid printprint ((ObjectObject o) {o) {ifif ((enabledenabled))
streamstream..printlnprintln(o.(o.toStringtoString());());}}
}}
publicpublic staticstatic voidvoid mainmain (String[](String[] argsargs) {) {LogLog..printprint((““Vai executar oVai executar o mainmain:: argsargs == ”” ++ argsargs););
}}
Log4jLog4j
• Projeto da Apache
� http://logging.apache.org/log4j/
• API de Logging� Categorias de logging
� Níveis (prioridades)
� Formatação dos eventos de logging
� Saídas para os eventos de logging
� Informações de Contexto
� Configurável
Eventos deEventos de LogLog
• Horário• Prioridade• Categoria• Mensagem• Arquivo fonte• Número da linha• Nome da thread• ...
LoggerLogger
• Gerador de eventos de logging� org.apache.log4j.Logger
• Categorias de logging• Criando um Logger
LoggerLogger loglog == LoggerLogger..getLoggergetLogger((““categoriacategoria””););LoggerLogger loglog == LoggerLogger..getLoggergetLogger((AClassAClass..classclass););
LevelLevel
• Prioridade de Logging� Constantes definidas em org.apache.log4j.Level
� DEBUG < INFO < WARN < ERROR < FATAL
• Emitindo mensagens
loglog.debug(.debug(““mensagemmensagem””););loglog..infoinfo((““mensagemmensagem””););loglog..warnwarn((““mensagemmensagem””););loglog..errorerror((““mensagemmensagem””););loglog.fatal(.fatal(““mensagemmensagem””););
LevelLevel
• Uma requisição de log é dita habilitada se seu level for maiorou igual ao level do seu logger
• Caso contrário, a requisição é dita desabilitada
ExemploExemplo
LoggerLogger loggerlogger == Logger.getLogger("com.fooLogger.getLogger("com.foo");");
logger.setLevel(Level.INFOlogger.setLevel(Level.INFO););
////EssaEssa requisirequisiççãoão éé habilitadahabilitada,, porqueporque WARN >= INFO.WARN >= INFO.logger.warn("Lowlogger.warn("Low fuel level.");fuel level.");
////EssaEssa requisirequisiççãoão éé desabilitadadesabilitada,, porqueporque DEBUG < INFO.DEBUG < INFO.logger.debug("Startinglogger.debug("Starting search for nearest gas station.");search for nearest gas station.");
AppendersAppenders && LayoutsLayouts
• Saída para eventos de logging� Interface org.apache.log4j.Appender
• Formatação de eventos de logging� Interface org.apache.lo4j.Layout
AppendersAppenders DisponDisponííveisveis
Servidor acessível via telnetorg.apache.log4j.net.TelnetAppender
UNIX syslog daemonorg.apache.log4j.net.SyslogAppender
NT Event Logorg.apache.log4j.nt.NTEventLogAppender
E-mailorg.apache.log4j.net.SMTPAppender
Arquivo (após um certo tamanho,faz backup do antigo e começaum novo)
org.apache.log4j.RollingFileAppender
Arquivoorg.apache.log4j.FileAppender
Console (System.out ouSystem.err)
org.apache.log4j.ConsoleAppender
SaídaAppender
LayoutsLayouts DisponDisponííveisveis
XMLorg.apache.log4j.xml.XMLLayout
HTMLorg.apache.log4j.HTMLLayout
Depende da string de formataçãoorg.apache.log4j.PatternLayout
“176 [thread] INFO categoria –mensagem”
org.apache.log4j.TTCCLayout
“DEBUG – mensagem”org.apache.log4j.SimpleLayout
FormatoLayout
PatternLayoutPatternLayout
• As seguintes opções estão disponíveis:� c: Categoria do evento de log� C: Nome da classe que fez a rwuisição de log� d: Data do evento de log. Deve ser seguido de um formater de data
entre chaves. Por exemplo, %d{HH:mm:ss,SSS} ou %d{dd MMMyyyy HH:mm:ss,SSS}. Se nenhum formater for fornecido, o formatoda ISO8601 será utilizado
� F: Nome do arquivo da requisição do evento de log� l: Localização da classe que invocou a requisição que gerou o evento de
log� L: Número da linha da qual a requisição do evento de log foi disparada� n: Separador de linha dependente de plataforma� M: Nome do método no qual o evento de log foi lançado� p: Prioridade do evento de log� t: Nome da thread que gerou o evento de log� m: Mensagem de log
ConfiguraConfiguraççãoão
• Programática
loglog..addAppenderaddAppender((appenderappender););loglog..setLevelsetLevel((levellevel););
• Configurator� Básico (BasicConfigurator)� Arquivo de Properties (PropertyConfigurator)� Arquivo XML (DOMConfigurator)
• Automática� log4j.xml� log4j.properties
BasicConfiguratorBasicConfigurator
• BasicConfigurator� org.apache.log4j.BasicConfigurator
publicpublic classclass MyAppMyApp {{staticstatic LoggerLogger loggerlogger == LoggerLogger..getLoggergetLogger((MyAppMyApp..classclass););publicpublic staticstatic voidvoid mainmain(String[](String[] argsargs) {) {
BasicConfiguratorBasicConfigurator.configure();.configure();loggerlogger..infoinfo("("EnteringEntering applicationapplication.");.");
BarBar barbar = new Bar();= new Bar();bar.bar.doItdoIt();();loggerlogger..infoinfo("("ExitingExiting applicationapplication.");.");}}
}}
0 [main] INFO MyApp - Entering application.51 [main] INFO MyApp - Exiting application.
PropertyConfiguratorPropertyConfigurator
• PropertyConfigurator� org.apache.log4j.PropertyConfigurator
• Arquivo de Configuração
log4j.log4j.appenderappender..nomeDoAppendernomeDoAppender=classe.do.=classe.do.appenderappenderlog4j.log4j.appenderappender..nomeDoAppendernomeDoAppender..properiedadeproperiedade=valor=valor......log4j.log4j.appenderappender..nomeDoAppendernomeDoAppender.layout=classe.do.layout.layout=classe.do.layoutlog4j.log4j.appenderappender..nomeDoAppendernomeDoAppender.layout..layout.properiedadeproperiedade=valor=valor......log4j.log4j.appenderappender..nomeDaCategorianomeDaCategoria=n=níível,vel, nomeDoAppendernomeDoAppender, ..., ...
PropertyConfiguratorPropertyConfigurator
publicpublic classclass MyAppMyApp {{
staticstatic LoggerLogger loggerlogger == LoggerLogger..getLoggergetLogger((MyAppMyApp..classclass..getNamegetName());());
publicpublic staticstatic voidvoid mainmain(String[](String[] argsargs) {) {//// BasicConfiguratorBasicConfigurator substitusubstituíído pordo por PropertyConfiguratorPropertyConfigurator..PropertyConfiguratorPropertyConfigurator.configure(.configure(argsargs[0]);[0]);loggerlogger..infoinfo("("EnteringEntering applicationapplication.");.");BarBar barbar = new Bar();= new Bar();bar.bar.doItdoIt();();loggerlogger..infoinfo("("ExitingExiting applicationapplication.");.");
}}}}
PropertyConfiguratorPropertyConfigurator
log4j.log4j.rootLoggerrootLogger=DEBUG, A1=DEBUG, A1log4j.log4j.appenderappender.A1=org.apache.log4j..A1=org.apache.log4j.ConsoleAppenderConsoleAppenderlog4j.log4j.appenderappender.A1.layout=org.apache.log4j..A1.layout=org.apache.log4j.PatternLayoutPatternLayoutlog4j.log4j.appenderappender.A1.layout..A1.layout.ConversionPatternConversionPattern=%d [%t] %=%d [%t] %--5p %c5p %c --
%m%n%m%nlog4j.log4j.logger.comlogger.com..foofoo=WARN=WARN
2000-09-07 14:07:41,508 [main] INFO MyApp - Entering application.2000-09-07 14:07:41,529 [main] INFO MyApp - Exiting application.
DOMConfiguratorDOMConfigurator
• DOMConfigurator� org.apache.log4j.xml.DOMConfigurator
• Arquivo de Configuração
<<configurationconfiguration>><<appenderappender namename==““nomeDoAppendernomeDoAppender”” classclass==““classe.do.classe.do.appenderappender””>> <param<paramnamename==““propriedadepropriedade”” valuevalue==““valorvalor”” />/>
<layout<layout classclass==““classe.do.layoutclasse.do.layout””>><param<param namename==““propriedadepropriedade”” valuevalue==““valorvalor”” />/>
</layout></layout></</appenderappender>><<categorycategory>>
<<prioritypriority namename==““nníívelvel”” />/><<appenderappender--refref refref==““nomedoAppendernomedoAppender”” />/>
</</categorycategory>></</configurationconfiguration>>
DOMConfiguratorDOMConfigurator
<?xml version="1.0" encoding="UTF<?xml version="1.0" encoding="UTF--8" ?>8" ?><!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"><!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"><log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">j/"><<appenderappender name="name="appenderappender""
class="org.apache.log4j.FileAppender">class="org.apache.log4j.FileAppender"><<paramparam name="File" value="name="File" value="IndentifyIndentify--Log.txtLog.txt"/>"/><<paramparam name="Append" value="false"/>name="Append" value="false"/><layout class="org.apache.log4j.PatternLayout"><layout class="org.apache.log4j.PatternLayout"><<paramparam name="name="ConversionPatternConversionPattern" value="%d [%t] %p" value="%d [%t] %p -- %%m%nm%n"/>"/>
</layout></layout></</appenderappender>><root><root><priority value ="debug"/><priority value ="debug"/><<appenderappender--ref ref="ref ref="appenderappender"/>"/>
</root></root></log4j:configuration></log4j:configuration>
PerformancePerformance
• Evitando o custo da construção da mensagem:
loglog..isDebugEnabledisDebugEnabled();();
loglog..isInfoEnabledisInfoEnabled();();
......
loglog..isFatalEnabledisFatalEnabled();();
• Quando a requisição está habilitada, duplica o esforço
Hierarquia deHierarquia de LoggersLoggers
• Membros separados por “.”• br.ufrj.cos.lens.Processo
� Logger br� Logger br.ufrj� Logger br.ufrj.cos� Logger br.ufrj.cos.lens� Logger br.ufrj.cos.lens.Processo
Hierarquia deHierarquia de LoggersLoggers
• Herança de nível entre loggers� Se um logger não tem um nível explicitamente atribuído, é assumido o
nível explicitamente atribuído ao logger ancestral mais próximo
• Herança de appenders entre loggers� Um evento de logging é emitido para todos os appenders registrados no
logger, e para todos appenders registrados nos loggers ancestrais
JUnitJUnit
Tópicos• Tipos de Testes• O que é JUnit?• Para que serve?• Como usar o JUnit?• JUnit 4• Exemplo• Asserções• Fixtures• Exceções Esperadas• Outras Anotações• Teste Siutações de Falha• Limitações do JUnit• Como escrever bons testes?• Como descobrir testes?• Testes como documentação
Tipos de TestesTipos de Testes
• Testes de Unidade� Testam unidades de lógica. Em linguagens orientadas a objetos,
unidades geralmente representam métodos, mas podem tambémrepresentar um objeto ou ainda um estado de um método
� Ignoram condições ou dependências externas. Testes de unidade usamdados suficientes para testar apenas a lógica da unidade em questão
• Testes de Integração� Testam como uma coleção de unidades interage entre si ou com o
ambiente onde executam
• Testes Funcionais (caixa-preta)� Testam casos de uso de uma aplicação. Validam a interface do usuário,
operações requisitadas, etc.
O queO que éé JUnitJUnit??
• Um framework que facilita o desenvolvimento e execução detestes de unidade em código Java� Uma API para construir os testes: junit.framework.*� Aplicações para executar testes: TestRunner
Para que serve?Para que serve?
• “Padrão” para testes de unidade em Java� Desenvolvido por Kent Beck e Erich Gamma� Design muito simples
• Testar é uma boa prática, mas é chato. JUnit torna as coisasmais agradáveis, facilitando:� A criação e execução automática dos testes� A apresentação dos resultados
• JUnit pode verificar se cada unidade de código funciona daforma esperada� Permite agrupar e rodar vários testes ao mesmo tempo� Na falha, mostra a causa em cada teste
• Serve de base para extensões
Como usar oComo usar o JUnitJUnit??
• Há várias formas de usar o JUnit. Depende da metodologia detestes que está sendo usada� Código existente: precisa-se escrever testes para classes que já foram
implementadas� Desenvolvimento guiado por testes (TDD): código novo só é escrito se
houver um teste sem funcionar• Onde obter o JUnit?
� www.junit.org• Como instalar?
� Incluir o arquivo junit.jar no classpath para compilar e rodar osprogramas de teste
• Extensões do JUnit� Permitem usá-lo para testes funcionais e de integração
JUnitJUnit 44
• A versão 4 do JUnit acabou de ser lançada (abril de 2006)• Ela usa as ferramentas disponíveis na versão 5 do Java para
fazer com que desenvolver os testes seja ainda mais fácil
• Vamos apresentar o JUnit 4• É usado com adaptadores em aplicativos antigos• Em breve poderemos abandonar os adaptadores
ExemploExemplo
AsserAsserççõesões
• Asserções são métodos de junit.framework.Assert� Afirmam que certas condições são verdadeiras� Causam AssertionFailedError se falharem
• Principais asserções
assertEqualsassertEquals((objetoEsperadoobjetoEsperado,, objetoRecebidoobjetoRecebido))assertTrueassertTrue((valorBooleanovalorBooleano))assertNotNullassertNotNull(objeto)(objeto)assertSameassertSame((objetoUmobjetoUm,, objetoDoisobjetoDois))failfail()()
FixturesFixtures
• São dados reutilizados por vários testes• Devem conter apenas dados suficientes• O JUnit 4 provê duas novas anotações para os métodos de set
up e tear down:� @Before: Método anotado com @Before executa antes de todo teste� @After: Método anotado com @After executa depois de cada teste
• Podemos ter quantos @Before e @After quantos foremnecessários
• É possível herdar dos métodos @Before e @After. O JUnitexecuta os métodos @Before da superclasse antes dos dasubclasse
FixturesFixtures
FixturesFixtures
• One-time set up e tear down� JUnit4 provê as anotações @BeforeClass and @AfterClass para one-
time set up e tear down� Estas anotações rodam o código do set up uma vez antes de todos os
testes e do tear down uma vez depois de todos os testes
FixturesFixtures
ExceExceçções Esperadasões Esperadas
• É tão importante testar o cenário de falha do seu código quantoo de sucesso
• O JUnit 4 facilita o teste quando uma exceção é esperada. Aanotação @Test recebe a exceção que deve ser lançada pelométodo de teste como parâmetro
ExceExceçções Esperadasões Esperadas
Outras AnotaOutras Anotaççõesões
• Ignorando um teste� A anotação @Ignore faz com que o teste não seja rodado e seja
relatado que não foi rodado� Pode-se passar uma String como parâmetro para a anotação @Ignore
que explique porque o teste foi ignorado.
• Determinando o tempo limite de um teste� Você pode passar um tempo limite como parâmetro para a anotação test
para especificar um período em limissegundos� Se o teste levar mais que esse tempo, ele falha
Teste SituaTeste Situaçções de Falhaões de Falha
• É tão importante o cenário de falha do seu código quanto o desucesso
• Método fail() provoca uma falha� Use para verificar se exceções ocorrem quando se espera que elas
ocorram
@@TestTest publicpublic voidvoid entityNotFoundExceptionentityNotFoundException() {() {resetEntityTableresetEntityTable();();trytry {{
ParameterEntityTagParameterEntityTag tagtag == parserparser..resolveEntityresolveEntity((““bogusbogus””););failfail((““Devia ter causado a exceDevia ter causado a exceççãoão EntityNotFoundExceptionEntityNotFoundException!!””););
} catch (} catch (EntityNotFoundExceptionEntityNotFoundException e) {e) {}}
}}
LimitaLimitaçções doões do JUnitJUnit
• Acesso aos dados de métodos sob teste� Métodos private e variáveis locais não podem ser testados com JUnit� Dados devem ser pelo menos friendly (package-private)
Como escrever bons testes?Como escrever bons testes?
• JUnit facilita bastante a criação e execução de testes,mas elaborar bons testes exige mais� O que testar? Com saber se testes estão completos?
• Teste tudo o que pode falhar� Métodos triviais (get/set) não precisam ser testados� E se houver uma rotina de validação no método set?
• É melhor ter testes a mais que testes a menos� Escreva testes curtos (quebre testes maiores)� Use assertNotNull() (reduz drasticamente erro de NullPointerException
difíceis de encontrar)� Reescreva e altere o design de seu código para que fique mais fácil de
testar: promove design melhor!
Como descobrir testes?Como descobrir testes?
• Listas de tarefas (to-do-list)� Comece implementando os testes mais simples e deixe os testes
“realistas” para o final� Requisitos, use-cases, diagramas UML: reescreva s requerimentos em
termos de testes� Quebre requisitos complexos em pedaços menores
• Bugs revelam testes� Achou um bug? Não conserte sem antes escrever um teste que o pegue
(se você não o fizer, ele volta!)• Descoberta de testes é atividade de análise e design
� Sugerem nomes e estrutura de classes da solução� Permitem que se decida sobre detalhes de implementação após a
elaboração do teste
Testes como documentaTestes como documentaççãoão
• Testes são documentação executável� Execute-os periodicamente para mantê-los atualizados� Use nomes significativos� Mantenha-os simples!
• As asserções do JUnit possuem um argumento para descrever o que estásendo testado� Quando presente é o primeiro argumento� A mensagem passada será mostrada em caso de falha� Use, sempre que possível
assertEqualsassertEquals((““ArrayArray deve coincidir!deve coincidir!””, esperado,, esperado, testArraytestArray););assertNotNullassertNotNull((““obj deve serobj deve ser nullnull!!””, obj);, obj);assertTrueassertTrue((““xyzxyz() deve retornar() deve retornar truetrue!!””, a., a.xyzxyz());());
DocumentaDocumentaççãoão
Tópicos• Comentários e Documentação• Tags do JavaDoc• Tipos de Documentação• Tags Comuns• Tags de Classes• Tags de Variáveis• Tags de Métodos
ComentComentáários e Documentarios e Documentaççãoão
• É possível gerar documentação automaticamente em Java pelouso de Comentários de Documentação
• O Java possui uma ferramenta para gerar a documentação aaprtir dos comentários inseridos no código fonte chamadaJavaDoc
• O JavaDoc extrai os comentários /** ... */, especiais dedocumentação embutidos no código, gerando um arquivo noformato html convencional
• O JavaDoc processa apenas comentários de documentaçãopara membros de classe declaradas como public ou protected
• Comentários em membros do tipo private ou friendly serãoignorados a menos que se explicite sua inlcusão
ComentComentáários e Documentarios e Documentaççãoão
• Há duas maneiras de se trabalhar com o JavaDoc:� Embutindo-se código HTML� Usando tags de documentação
• Embutindo HTML� O JavaDoc permite o uso de comandos HTML diretamente nos
comentários de documentação� É permitido o uso de qualquer comando de formatação, tal como <tt> e
<b>, mas não se pode fazer uso de comandos estruturais, tais como<h2> e <hr>; pois o JavaDoc já insere seus próprios comandosestruturais
ComentComentáários e Documentarios e Documentaççãoão
/**/**** ÉÉ posspossíível <b> atvel <b> atéé </b> gerar uma lista</b> gerar uma lista* <* <olol>>* <li> item um* <li> item um* <li> item dois* <li> item dois* <li> item três* <li> item três* </* </olol>>*/*/
• Os asteriscos iniciais das linhas são opcionais e ignorados peloJavaDoc
TagsTags dodo JavaDocJavaDoc
• Tags são comandos que permitem formatação adicional dadocumentação e são sempre iniciados por @:� @author� {@code}� {@docRoot}� @deprecated� @exception� {@inheritDoc}� {@link}� {@linkplain}� {@literal}� @param
� @return� @see� @serial� @serialData� @serialField� @since� @throws� {@value}� @version
Tipos de DocumentaTipos de Documentaççãoão
• Há três tipos principais de documentação: o de classes, o devariáveis e o de métodos
• Devido a diferenças entre esses tipos, algumas tags sãoexclusivas para cada um deles
TagsTags ComunsComuns
• Apenas as seguintes tags são utilizadas para qualquer tipo:� @see� @since� @deprecated� {@link}� {@linkplain}� {@docroot}
TagsTags de Classesde Classes
• As tags abaixo podem ser utilizadas para documentação declasses e interfaces:� @see� @since� @deprecated� @serial� @author� @version� {@link}� {@linkplain}� {@docRoot}
TagsTags de Classesde Classes
/**/*** A class representing a window on the screen.* A class representing a window on the screen.* For example:* For example:* <pre>* <pre>* Window win = new* Window win = new Window(parentWindow(parent););** win.showwin.show();();* </pre>* </pre>*** @author* @author SamiSami ShaioShaio* @version %I%, %G%* @version %I%, %G%* @see* @see java.awt.BaseWindowjava.awt.BaseWindow* @see* @see java.awt.Buttonjava.awt.Button*/*/
class Window extendsclass Window extends BaseWindowBaseWindow {{......
}}
TagsTags de Varide Variááveisveis
• As tags abaixo podem ser utilizadas para documentação devariáveis:� @see� @since� @deprecated� @serial� @serialField� {@link}� {@linkplain}� {@docRoot}� {@value}
TagsTags de Varide Variááveisveis
/**/*** The X* The X--coordinate of the component.coordinate of the component.*** @see #* @see #getLocationgetLocation()()*/*/
intint x = 1263732;x = 1263732;
TagsTags de Mde Méétodostodos
• As tags abaixo podem ser utilizadas para documentação demétodos e construtores:� @see� @since� @deprecated� @param� @return – não pode aparecer em construtores� @throws� @exception� @serialData -� {@link}� {@linkplain}� {@inheritDoc}� {@docRoot}
TagsTags de Mde Méétodostodos
/**/*** Returns the character at the specified index. An index* Returns the character at the specified index. An index* ranges from <code>0</code> to <code>length()* ranges from <code>0</code> to <code>length() -- 1</code>.1</code>.*** @* @paramparam index the index of the desired character.index the index of the desired character.* @return the desired character.* @return the desired character.* @exception* @exception StringIndexOutOfRangeExceptionStringIndexOutOfRangeException* if the index is not in the range <code>0</co* if the index is not in the range <code>0</code>de>* to <code>length()* to <code>length()--1</code>.1</code>.* @see* @see java.lang.Character#charValuejava.lang.Character#charValue()()*/*/public charpublic char charAt(intcharAt(int index) {index) {
......}}
FimFim
Parabéns!! Chegamos ao fim daapresentação de Frameworks eDocumentação!!
Agora sabemos criar aplicações queutilizam esses frameworks para torná-las mais robustas!
Próximos passos:Padrões de Projeto!