Análise e Projeto de Software Orientados a Objeto

Lista de Exercícios

Lugares onde tem exercícios interessantes

O Processo de Desenvolvimento de Software

  1. Qual é o objetivo principal de um Processo de Desenvolvimento de Software?
  2. Qual é diferença entre desenvolver um software com e sem um processo adequado?
  3. Nas suas palavras, defina o que significa Software de Qualidade.
  4. Descreva brevemente as grandes etapas necessárias ao desenvolvimento de software de qualidade.
  5. Comente o que se entende pela frase seguinte: "Os requisitos devem falar dos problemas e não das soluções".
  6. Comente o que se entende pela frase seguinte: "Os requisitos existem para reduzir o espaço de solução".
  7. Os produtos de informática de hoje frequentemente exibem funcionalidades que claramente sairam da cabeça da equipe de desenvolvimento. Isso é ruim? É bom? Comente.
  8. Usando UML, qual é o resultado de cada etapa do processo de desenvolvimento?
  9. O que deve fazer parte dos requisitos além dos requisitos funcionais?
  10. Escreva um parágrafo típico que poderia fazer parte de um documento de requisitos com respeito a cada um dos itens seguintes:
  1. Quem deve aprovar um documento de requisitos?
  2. Argumente a favor ou contra a afirmação de que "Todo documento gerado no processo de desenvolvimento deve ter um dono único".
  3. Quais são os objetivos principais do design de alto nível (arquitetural)?
  4. Por que um produto deve ter um único projetista principal?
  5. Por que o design de alto nível se preocupar tanto com as interfaces entre componentes?
  6. Justifique a atividade de design de baixo nível.
  7. O documento de design de baixo nível é preparado por quantas pessoas?
  8. Descreva como UML descreve a atividade de design de baixo nível.
  9. O que é code review? Qual é sua importância?
  10. Quais são os tipos de atividades de teste de software? Descreva cada atividade em uma ou duas frases.
  11. Por que existem tantos tipos de testes?
  12. O que se perde quando testes não são automatizados?
  13. O que é scaffolding?
  14. O que um plano de testes de unidade deve conter?
  15. Como a função main pode ser utilizada em Java para os propósitos de testes?
  16. Que fase de testes pretende testar as interfaces entre módulos?
  17. Dê um exemplo de uma "função" típica que seria testada num teste de função.
  18. O que um plano de teste de função deve tipicamente conter?
  19. Explique a importância de manter um histórico dos erros descobertos durante os testes numa base de dados.
  20. Quais tipos de testes podem ser considerados black box e quais podem ser considerados white box?
  21. Qual é o motivo principal que explica a utilização de testes de componentes?
  22. O que um plano de teste de componente deve conter?
  23. Como identificar um "componente" na atividade de teste de componentes?
  24. O que é um Total System Environment? Por que testar nessas condições?
  25. Quem deve executar cada tipo de teste?
  26. Qual é a diferença entre testes de sistema e testes de regressão?
  27. Descreve o que é um teste alfa e como ele deve ser feito.
  28. Quem deve ser responsável pela condução de um teste alfa?
  29. O que um teste alfa deve testar?
  30. Descreve o que é um teste beta e como ele deve ser feito.
  31. Quem deve ser responsável pela condução de um teste beta?
  32. O que um teste beta deve testar?
  33. O que diferencia um teste alfa de um teste beta?
  34. O que são as Publicações de um produto?
  35. O que é um Plano de Publicações?

Introdução à Linguagem de Programação Java

Os exercícios abaixo foram retirados dos capítulos 1 a 4 do livro Data Structures and Problems Solving Using Java, Weiss, Addison-Wesley, 1998.

Capítulo 1: Primitive Java

  1. Que extensões são usadas para arquivos contendo código fonte e codigo compilado em Java?
  2. Descreva os três tipos de comentários utlizados em programa Java.
  3. Quais são os oito tipos primitivos em Java?
  4. Qual é a diferença entre os operadores * e *=?
  5. Explique a diferença entre os operadores de incrementação pré-fixados e pós-fixados.
  6. Descreva os três tipos de laços em Java.
  7. Descreva todos os usos do comando break. O que é um comando break com rótulo?
  8. O que é feito pelo comando continue?
  9. O que é sobrecarga de métodos?
  10. Descreva a chamada por valor.
  11. Suponha que b tenha valor 5 e c tenha valor 8. Qual é o valor de a, b e c após cada linha no seguinte fragmento de programa:

a = b++ + c++;
a = b++ + ++c;
a = ++b + c++;
a = ++b + ++c;

  1. Qual é o resultado de true && false || true?
  2. No seguinte fragmento de programa, forneça um exemplo para o qual o laço for não seja equivalente ao laço while:

for( init; test; update ) {

statements

}


init;

while( test ) {

statements

update;

}

  1. Quais são as possíveis saídas do seguinte programa?

public class WhatIsX {

public static void f( int x ) { /* body unknown */

public static void main( String [] args ) {

int x = 0;

f( x );

System.out.println( x );

}

}

  1. Escreva um comando while que seja equivalente ao seguinte fragmento for. Por que isso seria útil?

for( ; ; )

statement

  1. Escreva um programa para gerar as tabuadas de adição e multiplicação para números de um único dígito (as tabuadas que alunos do primeiro grau estão acostumados a ver).
  2. Escreva dois métodos estáticos. O prmeiro deve retornar o máximo entre três inteiros e o segundo deve retornar o máximo entre quatro inteiros.
  3. Escreva um método estático que receba um ano como parâmetro e retorne true se o ano for bissexto e false caso contrário.
  4. Escreva um programa para determinar todos os pares de inteiros positivos, (a, b), tais que a < b < 100 e (a^2 + b^2 + 1)/(ab) seja inteiro.
  5. Escreva um método que imprima a representação do seu parâmetro inteiro como número Romano. Assim, se o parâmetro for 1998, a saída é MCMLXLVIII.
  6. Suponha que você queira imprimir números entre colchetes formatados como segue: [1][2][3], e assim por diante. Escreva um método que receba dois marâmetros: howMany e lineLength. O método deve imprimir números de 1 até howMany no formato já mencionado, mas não deve imprimir mais do que lineLength caracteres numa mesma linha. Ele não deveria iniciar um [ se o ] correspondente não couber na linha.
  7. No problema seguinte usando aritmética decimal, cada uma das dez letras diferentes recebe o valor de um dígito. Escreva um programa que descubra todas as possíveis soluções (uma daas quais está mostrada).
MARK A=1 W=2 N=3 R=4 E=5 9147
+ALLEN L=6 K=7 I=8 M=9 S=0 +16653
-----   -----
WEISS   25800

Capítulo 2: References

  1. Liste as diferenças principais entre tipos de referência e tipos primitivos.
  2. Liste cinco operações que podem ser aplicadas a um tipo de referência.
  3. Descreva como exceções funcionam em Java.
  4. Liste as operações básicas que podem ser aplicadas a strings.
  5. Se x e y têm valores 5 e 7, respectivamente, qual é sa saída do seguinte fragmento:

System.out.println( x + ' ' + y );

System.out.println( x + " " + y );

  1. Um checksum é um inteiro de 32 bits que é obtido pela soma dos caracteres Unicode contidos num arquivo (permitimos um overflow silencioso, embora um overflow silencioso seja improvável se todos os caracteres forem ASCII). Dois arquivos idênticos possuem o mesmo checksum. Escreva um programa para calcular o checksum de um arquivo cujo nome é dado como argumento da linha de comando.
  2. Escreva um método que retorne true se String str1 for um prefixo de String str2. Não use qualquer uma das rotinas especiais de pesquisa em strings com exceção de charAt.
  3. Escreva um programa que imprima na saída o número de caracteres, palavras e linhas nos arquivos cujos nomes são dados como argumentos da linha de comando.
  4. Implemente um programa de cópia de arquivos de texto. Inclua um teste para ter certeza de que os arquivos fonte e destino seja diferentes. Você terá que ler um livro de referência java para aprender como fazer saída para arquivos.

Capítulo 3: Objects and Classes

  1. O que significa esconder informação? O que é encapsulação? COmo Java dá suporte a estes conceitos?
  2. Explique as seções públicas e privadas da classe.
  3. Descreva o papel do construtor.
  4. Qual é o resultado quando uma classe não provê um construtor?
  5. O que significa acesso package friendly?
  6. Como a saída é feita para uma classe ClassName?
  7. Dê as duas formas de diretivas de importação que permitem que longPause seja usado sem ter que mencionar o nome do package Supporting.
  8. Por que classes não podem ser declaradas como privadas?
  9. Um cadeado de segredo tem as seguintes propriedades básicas: o segredo (uma sequência de 3 números) está escondido; o cadeado pode ser aberto ao fornecer o segredo; e o segredo pode ser alterado, mas apenas por alguém que saiba o segredo atual. Projete uma classe com método público open e changeCombo (mude segredo) e campos de dados privados que armazenem o segredo. O segredo deve ser inicializado no construtor. Desabilite a cópia de cadeados de segredo.
  10. Escreva uma classe que dê suporte a números racionais. Os campos devem ser duas variáveis do tipo long, uma armazenando o numerador e a outra o denominador. Armazene o número racional sempre na forma reduzida, isto é, com o numerador sempre não-negativo. Inclua um conjunto razoável de construtores; os métodos add, subtract, multiply, e divide; também inclua toString, equals, compareTo (que se comporta como o método semelhante da classe String). Tenha certeza que toString se comporte corretamente caso o denominador seja zero.
  11. Implemente uma classe Date simples. Você deve ser capaz de representar qualquer data de 1 de janeiro de 1800 até 31 de dezembro de 1500; subtrair datas; incrementar uma data por um número de dias; e comprar duas datas usando equals e compareTo. Uma data é representada internamente como o número de dias desde uma data inicial, que, neste caso, é o início de 1800. Isto faz com que todos os métodos com exceção dos construtores e toString triviais.

    A regra para anos bissextos é que um ano é bissexto se for divisível por 4 e não for divisível por 100 a não ser que seja divisível por 400. Desta forma, 1800, 1900 e 2100 não são anos bissextos mas 2000 o é. O construtor deve verificar a validade da data e toString também. Uma data pode estar errada se uma operação de incrementação ou uma subtração a deixar fora de faixa.

    Quando você tiver terminado a especificação, você poderá passar à implementação. A parte difícil é a conversão entre a representação interna e a representação externa de uma data. O que segue é um possível algoritmo.

    Use dois arrays que são campos estáticos. O primeiro array, daysTillFirstOfMonth contém o número de dias até o primeiro dia de cada mês num ano não-bissexto. Isto é, ele contém 0, 31, 59, 90, e assim por diante. O segundo array, daysTillJan1, contém o número de dias até o início de cada ano, iniciando com firstYear. Isto é, ele contém 0, 365, 730, 1095, 1460, 1826, e assim por diante já que 1800 não é bissexto mas 1804 o é. Seu programa ode inicializar este array uma única vez usando um inicializador estático. Você pode então usar o array para converter da representação interna para a representação externa.
  12. Implemente uma classe de número complexo. Lembre que um número complexo consiste de uma parte real e uma parte imaginária. Forneça as mesma operações da classe Rational, quando isso fizer sentido (por exemplo, compareTo não faz sentido). Adicione método de acesso para extrair a parte real e a parte imaginária.
  13. Implemente uma classe completa IntType que tenha um conjunto razoavelmente completo de construtores, add, subtract, multiply, divide, equals, compareTo e toString. Implemente IntType usando um array suficientemente grande. Para esta classe, a operação difícil é a divisão seguida de perto da multiplicação.

Capítulo 4: Inheritance

  1. Quais membros de uma classe herdada podem ser usados na classe derivada? Quais membros se tornam públicos para os usuários da classe derivada?
  2. O que é composição?
  3. Explique polimorfismo.
  4. Explique binding (amarração) dinâmico.
  5. O que é um método final?
  6. Considere o programa abaixo para testar a visibilidade:

public class Base {

public int bPublic;

protected int bProtect;

private int bPrivate;

// Public methods omitted

}

public class Derived extends Base {

public int dPublic;

private int dPrivate;

// Public methods omitted

}

public class Tester {

public static void main( String [] args ) {

Base b = new Base();

Derived d = new Derived();

System.out.println( b.bPublic + " " + b.bProtect + " "

+ b.bPrivate + " " + d.dPublic + " "

+ d.dPrivate );

}

}

a. Quais acessos são legais?
b. Coloque main como método de Base. Que acessos são legais?
c. Coloque main como método de Derived. Que acessos são legais?
d. Como essas respostas mudam se a palavra protected for removida na classe Base?
e. Escreva um construtor de três parâmetros para Base. Em seguida, escreva um construtor de cinco métodos para Derived.
f. A classe Derived consiste de cinco inteiros. Quais estão acessíveis à classe Derived?
g. Um método na classe Derived é passado para um objeto de classe Base. Quais entre os membros do objeto podem ser acessados pela classe Derived?

  1. Qual é a diferença entre uma classe final e outras classes? Para que classes finais são usadas?
  2. O que é um método abstrato?
  3. O que é uma classe abstrata?
  4. O que é uma interface? Como uma interface difere de uma classe abstrata? Que membros podem estar numa interface?
  5. Como são implementados algoritmos genéricos em java?
  6. Escreva métodos genéricos min e max, cada um dos quais aceita dois parâmetros do tipo Comparable. Então use esses métodos com tipo MyInteger.
  7. Escreva métodos genéricos min e max, cada um dos quais aceita um array do tipo Comparable. Então use esses métodos com tipo MyInteger.
  8. Para o exemplo Shape (do livro) modifique readShape e main atirando (?) e capturando uma exceção (em vez de criar um círculo de raio zero) ao detectar um erro de entrada.
  9. Modifique a classe Shape (do livro) para que passe a usar um algoritmo de ordenação genérico.
  10. Um SingleBuffer tem os métodos get e put: o SingleBuffer armazena um item único e um membro de dados que indica se o SingleBuffer está logicamente vazio. Um put pode ser aplicado apenas a um buffer vazio, e ele insere um item no buffer. Um get pode ser aplicado somente num buffer não vazio, e ele remove e retorna o conteúdo do buffer. Escreva uma classe genérica para implementar SingleBuffer. Defina uma exceção para sinalizar erros.
  11. Reescreva a hierarquia Shape (do livro) de forma a armazenar a área como membro de dados e faça com que seja calculado pelo construtor de Shape. Os construtores das classes derivadas devem calcular uma área e passar o resultado para o método super. Faça com que area seja um método final que apenas retorne o valor deste membro de dados.
  12. Adicione o conceito de uma posição à hierarquia Shape (do livro) pela inclusão de coordenadas como membors de dados. Então acrescente um método distance.
  13. Escreva uma classe abstrata para Date e sua classe derivada GregorianDate.
  14. Implemente uma hierarquia de pagadores de impostos que consista de uma interface TaxPayer e das classes SinglePayer e MarriedPayer que implementem a interface.

Exemplo maior de Programação: O Jogo Mancala de Arnow e Weiss

  1. De várias formas, a implementação do Jogo de Mancala de Arnow e Weiss tem falhas. Identifique essas falhas e explique por que são falhas.
  2. Reescreva o programa do Jogo de Mancala de forma a remover as falhas.
  3. Repita para a versão applet.

Os Exercícios do Livro: "UML Toolkit"

"Os exercícios apresentados aqui permitirão que você comece a utilizar a UML imediatamente.Eles estão divididos em categorias de Análise e Projeto/Construção. A primeiraq categoria lista novos requisitos do sistema; eles devem ser analizados, projetados e implementados no sistema. A segunda categoria contém mudanças técnicas e melhorias que afetam principalmente o projeto e a implementação. [...] observe que alguns [exercícios] só podem ser feitos nos modelos de análise e projeto. [...]

O exercício inicial serve para você se familiarizar com Rational Rose [...]. Inicie a ferramenta, abra o modelo de análise ou de projeto, e brinque com o modelo. Examine as diferentes views, os diferentes diagramas, e as especificações; em seguida, imprima o modelo completo.

Exercícios de Análise

  1. Introduza funcionalidade para informar um usuário com uma reserva pendente quando um item do título reservado retorna à biblioteca. O usuário com a reserva mais antiga deve ser avisado primeiro.
  2. Introduza funcionalidade para informar uma pessoa sobre o vencimento de um empréstimo.
  3. Estenda o sistema de forma a remover reservas depois de um dado tempo.
  4. Estenda o tratamento de títulos para que eles possam ser colocados em diferentes categorias e para adicionar a cada título informação definida pelo usuário (ex. um resenha sobre um livro).
  5. Estenda o sistema para gerenciar a aquisição de novos itens.
  6. Introduza regras no sistema de biblioteca para limitar empréstimos. Por exemplo, permita apenas cinco reservas por pessoa ou dez empréstimos por pessoa. Faça com que a definição das regras seja simples.
  7. Insira uma classe genérica para imprimir listas e cartas; por exemplo, listas de títulos e itens para fins de inventário e cartas para usuários sobre reservas e empréstimos.
  8. Estenda o modelo com uma conexão à Internet de forma que usuários possam pesquisar títulos e itens num site da World Wide Web.
  9. No modelo atual, a administração de serviços é feita usando objetos da interface do usuário que fazem ações nos objetos do domínio (business objects). Mude a arquitetura para que classes de objetos de controle (classes que tratam um serviço específico do início até o fim) sejam usadas. Um exemplo de uma classe de objeto de controle coletaria estatísticas sobre a situação atual da biblioteca - o número de usuários, títulos, itens e empréstimos atuais - e imprimiria os resultados numa janela.
  10. Refaça o modelo de biblioteca para dar suporte à integração de outras bibliotecas que utilizem o mesmo sistema. Isto significa que uma biblioteca deveria ser capaz de pesquisar um título ou item numa outra biblioteca. Uma biblioteca deve poder tomar um item emprestado através do envio de uma mensagem para a biblioteca detentora de um item, a qual aciona os procedimentos de empréstimo e devolve o item via correio para a biblioteca original. Mostre um diagrama de implantação (deployment) para este novo sistema.

Exercícios de Projeto e Construção

  1. Adicione as classes "Book Title" e "Magazine Title" ao projeto e adicione alguns novos atributos adequados a cada uma das classes. Faça com que a classe existente "Title" seja abstrata e tenha certeza de que as novas classes possam ser armazenadas de forma persistente.
  2. Mude a janela "Browse All" para permitir que um usuário clique duas vezes num título ou num usuário nas list-boxes abrindo imediatamente assim a janela de atualização correta.
  3. Mude o projeto da pesquisa de objetos para aceitar metacaracteres ("wild cards") para pesquisar títulos, autores ou usuários (ex. "UML*" localiza todos os títulos iniciando com "UML").
  4. Mude o projeto da pesquisa de objetos para manusear resultados múltiplos de pesquisa (correntemente, apenas o primeiro casamento é retornado). O número de "sucessos" deve ser informado e o usuário deve poder escolher entre os registros resultantes.
  5. Adicione na interface do usuário um toolbar contendo botões para escolher funções específicas.
  6. Melhore o desempenho do banco de dados através da reutilização de registros removidos de um arquivo e através do uso de um arquivo de índices quando uma pesquisa mais eficiente de um objeto específico pode ser realizada (atualmente, a pesquisa é sequencial).
  7. Mude o projeto do Database Package para utilizar um banco de dados relacional em vez da solução atual usando arquivos. Serão necessárias novas classes no Database Package. Tente não mudar a interface para a classe Persistent, de forma a não afetar o resto da aplicação.
  8. Mude a interface do usuário para que a aplicação utilize uma única janela; desta forma, a janela principal muda de acordo com a função sendo realizada.
  9. Adicione uma nova classe utilitária para criar um log utilizável por todas as partes da aplicação para logar mensagens de depuração ou de rastreio de sua operação. O tipo de informação mantida no log deve ser configurável através da interface do usuário.
  10. Remova a necessidade de usar as operações read() e write() numa classe persistente. Alternativamente, use uma solução pela qual uma classe mantém meta-dados (dados sobre si mesma - i.e., uma descrição dos seus atributos), para que uma classe de banco de dados possa perguntar a um objeto persistente desconhecido sobre seus atributos e valores destes atributos e então armazená-los num banco de dados. Uma nova classe Metadata deve ser definida e um objeto de meta-dados deve ser agregado por todas as classes persistentes. [Jacques: em vez da solução proposta, sugiro fazer a mesma coisa usando o conceito de JavaBeans].