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
- Qual é o objetivo principal de um Processo de
Desenvolvimento de Software?
- Qual é diferença entre desenvolver um software com e
sem um processo adequado?
- Nas suas palavras, defina o que significa Software de
Qualidade.
- Descreva brevemente as grandes etapas necessárias ao
desenvolvimento de software de qualidade.
- Comente o que se entende pela frase seguinte: "Os
requisitos devem falar dos problemas e não das
soluções".
- Comente o que se entende pela frase seguinte: "Os
requisitos existem para reduzir o espaço de
solução".
- Os produtos de informática de hoje frequentemente exibem
funcionalidades que claramente sairam da cabeça da
equipe de desenvolvimento. Isso é ruim? É bom? Comente.
- Usando UML, qual é o resultado de cada etapa do processo
de desenvolvimento?
- O que deve fazer parte dos requisitos além dos
requisitos funcionais?
- Escreva um parágrafo típico que poderia fazer parte de
um documento de requisitos com respeito a cada um dos
itens seguintes:
- Sinopse do problema a ser resolvido
- Como o usuário opera hoje e que problemas ele
enfrenta
- Ambiente típico do usuário que usará o produto
- Facilidade de uso necessária
- Quem utilizará o produto
- Hardware/software alvo para o produto
- Qualidade
- Desempenho
- Segurança
- Compatibilidade com outros produtos/versões e
necessidades de migração
- Necessidades de internacionalização do produto ou
de alguma de suas partes
- Suporte
- Preço da solução
- Documentação
- Uso de padrões
- Aspectos legais
- Integração com outros produtos
- Packaging
- Quem deve aprovar um documento de requisitos?
- Argumente a favor ou contra a afirmação de que
"Todo documento gerado no processo de
desenvolvimento deve ter um dono único".
- Quais são os objetivos principais do design de alto
nível (arquitetural)?
- Por que um produto deve ter um único projetista
principal?
- Por que o design de alto nível se preocupar tanto com as
interfaces entre componentes?
- Justifique a atividade de design de baixo nível.
- O documento de design de baixo nível é preparado por
quantas pessoas?
- Descreva como UML descreve a atividade de design de baixo
nível.
- O que é code review? Qual é sua importância?
- Quais são os tipos de atividades de teste de software?
Descreva cada atividade em uma ou duas frases.
- Por que existem tantos tipos de testes?
- O que se perde quando testes não são automatizados?
- O que é scaffolding?
- O que um plano de testes de unidade deve conter?
- Como a função main pode ser utilizada em Java para os
propósitos de testes?
- Que fase de testes pretende testar as interfaces entre
módulos?
- Dê um exemplo de uma "função" típica que
seria testada num teste de função.
- O que um plano de teste de função deve tipicamente
conter?
- Explique a importância de manter um histórico dos erros
descobertos durante os testes numa base de dados.
- Quais tipos de testes podem ser considerados black
box e quais podem ser considerados white box?
- Qual é o motivo principal que explica a utilização de
testes de componentes?
- O que um plano de teste de componente deve conter?
- Como identificar um "componente" na atividade
de teste de componentes?
- O que é um Total System Environment? Por que
testar nessas condições?
- Quem deve executar cada tipo de teste?
- Qual é a diferença entre testes de sistema e testes de
regressão?
- Descreve o que é um teste alfa e como ele deve ser
feito.
- Quem deve ser responsável pela condução de um teste
alfa?
- O que um teste alfa deve testar?
- Descreve o que é um teste beta e como ele deve ser
feito.
- Quem deve ser responsável pela condução de um teste
beta?
- O que um teste beta deve testar?
- O que diferencia um teste alfa de um teste beta?
- O que são as Publicações de um produto?
- 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
- Que extensões são usadas para arquivos contendo código
fonte e codigo compilado em Java?
- Descreva os três tipos de comentários utlizados em
programa Java.
- Quais são os oito tipos primitivos em Java?
- Qual é a diferença entre os operadores * e *=?
- Explique a diferença entre os operadores de
incrementação pré-fixados e pós-fixados.
- Descreva os três tipos de laços em Java.
- Descreva todos os usos do comando break. O que é um comando break com rótulo?
- O que é feito pelo comando continue?
- O que é sobrecarga de métodos?
- Descreva a chamada por valor.
- 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;
- Qual é o resultado de true
&& false || true?
- 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;
}
- 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
);
}
}
- Escreva um comando while
que seja equivalente ao seguinte fragmento for. Por que isso seria útil?
for( ; ; )
statement
- 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).
- 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.
- 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.
- 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.
- 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.
- 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.
- 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
- Liste as diferenças principais entre tipos de
referência e tipos primitivos.
- Liste cinco operações que podem ser aplicadas a um tipo
de referência.
- Descreva como exceções funcionam em Java.
- Liste as operações básicas que podem ser aplicadas a
strings.
- 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 );
- 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.
- 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.
- 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.
- 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
- O que significa esconder informação? O que é
encapsulação? COmo Java dá suporte a estes conceitos?
- Explique as seções públicas e privadas da classe.
- Descreva o papel do construtor.
- Qual é o resultado quando uma classe não provê um
construtor?
- O que significa acesso package friendly?
- Como a saída é feita para uma classe ClassName?
- Dê as duas formas de diretivas de importação que
permitem que longPause
seja usado sem ter que mencionar o nome do package Supporting.
- Por que classes não podem ser declaradas como privadas?
- 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.
- 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.
- 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.
- 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.
- 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
- 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?
- O que é composição?
- Explique polimorfismo.
- Explique binding (amarração) dinâmico.
- O que é um método final?
- 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?
- Qual é a diferença entre uma classe final e outras
classes? Para que classes finais são usadas?
- O que é um método abstrato?
- O que é uma classe abstrata?
- O que é uma interface? Como uma interface difere de uma
classe abstrata? Que membros podem estar numa interface?
- Como são implementados algoritmos genéricos em java?
- 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.
- 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.
- 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.
- Modifique a classe Shape
(do livro) para que passe a usar um algoritmo de
ordenação genérico.
- 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.
- 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.
- 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.
- Escreva uma classe abstrata para Date
e sua classe derivada GregorianDate.
- 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
- 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.
- Reescreva o programa do Jogo de Mancala de forma a
remover as falhas.
- Repita para a versão applet.
"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
- 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.
- Introduza funcionalidade para informar uma pessoa sobre o
vencimento de um empréstimo.
- Estenda o sistema de forma a remover reservas depois de
um dado tempo.
- 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).
- Estenda o sistema para gerenciar a aquisição de novos
itens.
- 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.
- 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.
- 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.
- 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.
- 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
- 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.
- 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.
- 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").
- 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.
- Adicione na interface do usuário um toolbar
contendo botões para escolher funções específicas.
- 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).
- 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.
- 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.
- 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.
- 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].