Exercícios de Quiz
Nenhum exercício corresponde a esta pesquisa.
Encapsulamento e desenho de classes
Hierarquia Person, Attendee e SpeakerAutoavaliação
Quiz Event, 2018
Numa hierarquia de classes, Person é abstrata e guarda nome e idade. Attendee acrescenta hasPaid() (inicialmente false) e Speaker acrescenta getFee() (inicialmente 0). Um new Attendee("John") tem idade 0. Os toString devem devolver exatamente "Speaker Jane has a fee value of 0." e a mensagem de um participante que ainda não pagou, no formato "Attendee <nome> hasn't paid its registration.", para new Speaker("Jane", 38) e new Attendee("Mary", 27). Nenhum campo pode ser público. Escreva as três classes.
Solução
Person abstrata com name e age privados; Attendee com paid = false; Speaker com fee = 0; toString de Attendee como "Attendee " + name + (paid ? " has" : " hasn't") + " paid its registration." e de Speaker como "Speaker " + name + " has a fee value of " + fee + ".".
O estado inicial é decidido nos construtores e nos valores dos campos, não em métodos: um participante ainda não pagou e um orador ainda não tem taxa definida. O toString é polimórfico, pelo que cada subclasse formata a sua própria mensagem.
Confere a tua resposta:
- A classe
Personé declaradaabstracte os campos não são públicos. - O construtor de um só argumento dá idade
0. hasPaid()devolvefalseegetFee()devolve0por omissão.- Os dois
toStringseguem exatamente as cadeias do enunciado.
Sorvete Icecream: bolas e sabores distintosAutoavaliação
Quiz Flavor, 2020
A classe Icecream guarda uma lista de bolas de sabor (Flavor). Depois de addScoop(chocolate), addScoop(vanilla) e addScoop(chocolate), getScoopCount() devolve 3, getFlavorCount() devolve 2, contains("chocolate") e contains("vanilla") são true e contains("strawberry") é false. A classe Flavor guarda apenas o nome. Nenhum campo pode ser público. Escreva as duas classes.
Solução
Icecream com List<Flavor> scoops privada; getFlavorCount() percorre a lista e conta nomes ainda não vistos; contains(String) compara flavor.getName() com o texto pedido.
Há duas agregações diferentes sobre a mesma lista: o número de bolas é o tamanho da lista, mas o número de sabores exige comparar nomes, porque o mesmo sabor pode aparecer em várias bolas.
Confere a tua resposta:
getScoopCount()conta todas as bolas, incluindo repetidas.getFlavorCount()conta sabores distintos.contains(String)testa o nome do sabor, não a referência.- Os campos de
IcecreameFlavornão são públicos.
Igualdade e coleções
Igualdade de Event por título, data e descriçãoAutoavaliação
Quiz Event, 2018
A classe Event tem título, data e descrição, e um construtor de cópia new Event(e). Cópias de new Event("WebSummit", "Next year again", "world-wide tech event") são equals ao original, mas depois de e1.setTitle("TalkABit"), e2.setDate(...) ou e3.setDescription(...) deixam de ser. Implemente equals e hashCode de Event.
Solução
equals: true se for o mesmo objeto; false se o argumento for null ou de outra classe; caso contrário compara title, date e description com Objects.equals. hashCode: Objects.hash(title, date, description).
Dois eventos são o mesmo evento quando os três atributos coincidem. O construtor de cópia copia os valores, não a referência, pelo que os objetos são distintos mas iguais. Para HashSet funcionar, hashCode tem de depender exatamente dos mesmos campos usados em equals.
Confere a tua resposta:
equalscompara título, data e descrição, e rejeitanulle outras classes.- O construtor de cópia cria um objeto diferente (
assertNotSame) mas igual. hashCodeusa os mesmos três campos queequals.
Conjunto de Concert com hashCode consistenteAutoavaliação
Quiz Act, 2019
Um Concert fica definido por cidade, país e data. Num HashSet<Concert> colocam-se cinco concertos: Paris/France/2019-10-10, Paris/USA/2019-10-10, New York/USA/2019-10-10, New York/USA/2019-05-20 e outra vez New York/USA/2019-05-20. O conjunto fica com 4 elementos. Justifique por que é 4 e não 5, escrevendo equals e hashCode.
Solução
O conjunto fica com 4 elementos: só os dois últimos concertos coincidem em todos os campos. equals e hashCode sobre (city, country, date) garantem que o HashSet guarda um só deles.
Um HashSet só rejeita um elemento se hashCode coincidir e equals confirmar. Se hashCode ignorasse algum campo usado em equals, o conjunto podia guardar duplicados; se usasse campos a mais, podia rejeitar elementos iguais.
Confere a tua resposta:
equalscompara cidade, país e data; concertos com país ou data diferentes não são iguais.- Os dois concertos de New York/USA/2019-05-20 são iguais.
hashCodeusa os mesmos três campos, pelo que oHashSetdeteta a duplicação.- A resposta indica que o conjunto final tem 4 elementos.
Audiência de um Event sem nomes repetidosAutoavaliação
Quiz Event, 2018
Event.addPerson(p) só adiciona a pessoa se ainda não existir alguém com o mesmo nome no evento. Adicionam-se, por esta ordem, Attendee("John", 21), Attendee("Mary", 31), Speaker("Jane", 51), Attendee("Carl", 41), Attendee("John", 33), Attendee("Mary", 15), Attendee("Bill", 15) e Speaker("Bill", 60). Indique getAudienceCount() depois de cada adição e justifique a regra de comparação usada.
Solução
Contagens: 3, 4, 4, 4, 5, 5. A audiencia só cresce quando o nome é novo: "John" e "Mary" repetidos são ignorados, "Bill" entra uma vez, e o orador "Bill" também é ignorado.
A regra de não duplicação usa o nome como identidade da pessoa, não a referência do objeto nem a idade. Assim, Attendee("John", 33) e Attendee("Mary", 15) são ignorados porque esses nomes já existem, Attendee("Bill", 15) entra porque "Bill" ainda não estava na audiência, e o Speaker("Bill", 60) posterior já não conta pelo mesmo motivo.
Confere a tua resposta:
- A resposta dá a sequência de contagens 3, 4, 4, 4, 5, 5.
- A justificação compara apenas o nome, ignorando idade e tipo.
Speaker("Bill", 60)não aumenta a contagem porque já existe um "Bill".
TreeSet<Person> sem duplicados por nomeAutoavaliação
Quiz Event, 2018
Num TreeSet<Person> adiciona-se primeiro new Speaker("John") e depois new Attendee("John"). O conjunto fica com 1 elemento. Que contrato de comparação (entre Comparable e equals) torna isto possível, e por que TreeSet não usa equals/hashCode?
Solução
O conjunto fica com 1 elemento porque compareTo compara apenas o nome: compareTo devolve 0 para dois nomes iguais, e o TreeSet trata compareTo == 0 como duplicado.
Um TreeSet está ordenado e não usa hashCode: a pertinência testa-se por compareTo. Assim, duas pessoas de tipos diferentes com o mesmo nome são o mesmo elemento do conjunto.
Confere a tua resposta:
- A resposta explica que
PersonimplementaComparablecomcompareToa comparar o nome. - A justificação indica que
TreeSetusacompareTo == 0para detetar duplicados. - A conclusão é que Speaker("John") e Attendee("John") contam como a mesma pessoa.
addIngredient rejeita ingredientes repetidosAutoavaliação
Quiz Pizza, 2021
Numa MediumPizza, addIngredient só adiciona o ingrediente se ainda não existir outro com o mesmo nome, e devolve true nesse caso e false caso contrário. Adicionam-se Tomato, Cheese, Cheese (outro objeto) e novamente Tomato: as contagens de ingredientes ficam 1, 2, 2, 2. Explique a comparação usada e por que duas instância distintas de Ingredient("Cheese") são o mesmo ingrediente.
Solução
Contagens: depois de Tomato fica 1, depois de Cheese fica 2, e as repetições devolvem false sem alterar a lista. A comparação é i.getName().equals(ingredient.getName()), pelo que dois objetos Ingredient com o mesmo nome são equivalentes.
A lista só cresce quando o nome ainda não existe. Como a identidade de um ingrediente é o seu nome, criar outro objeto com o mesmo nome não conta como ingrediente novo.
Confere a tua resposta:
- A resposta indica as contagens 1, 2, 2, 2 e os valores de retorno true, true, false, false.
- A comparação usa o nome do ingrediente, não a referência do objeto.
- A justificação refere que a pertinência se testa antes de adicionar.
Herança, interfaces e polimorfismo
Party estende Event e agrega audiênciasAutoavaliação
Quiz Event, 2018
Party é uma subclasse de Event. Uma Party p começa com Attendee("John") e Artist("Beck"), dando getAudienceCount() == 2. Depois p.addEvent(e1) com duas pessoas e p.addEvent(e2) com três pessoas fazem a contagem passar para 4 e depois 7. Como deve addEvent combinar as audiências, e por que a contagem de p e de (Event) p coincidem?
Solução
Contagens: 2, 4, 7. addEvent(e) executa people.addAll(e.getPeople()), juntando a audiência do evento à da festa. Como p e (Event) p são o mesmo objeto, getAudienceCount() devolve o mesmo valor nas duas referências.
A festa agrega os participantes dos eventos que a compõem. A herança dá a Party todo o comportamento de Event; o addEvent apenas funde as duas listas de pessoas.
Confere a tua resposta:
- A resposta dá as contagens 2, 4 e 7.
addEventcopia todas as pessoas do evento para a lista da festa.- A justificação nota que
Partyherda o método, logo as duas referências contam o mesmo estado.
Act abstrata com Band e ArtistAutoavaliação
Quiz Act, 2019
Act é uma classe abstrata com nome e país. new Band("Radiohead", "UK") e new Artist("Bob Dylan", "USA") devolvem getName() e getCountry() respetivos. Nenhum campo pode ser público e Act tem de ser abstrata. Escreva a hierarquia.
Solução
Act abstrata com campos privados name e country, construtor e dois getters; Band extends Act e Artist extends Act com construtores que chamam super(name, country).
Nome e país são comuns a todos os artistas de um concerto, pelo que pertencem à superclasse; cada subclasse concreto só fija o tipo. Os campos privados na superclasse impedem acesso direto pelas subclasses e de fora.
Confere a tua resposta:
- A classe
Actéabstracte guardanameecountryem campos não públicos. BandeArtistsão concretos e delegam nos construtores da superclasse.getName()egetCountry()devolvem os valores do construtor.
Concert.participates para artistas e bandasAutoavaliação
Quiz Act, 2019
Um concerto tem uma lista de Act. participates(artist) deve devolver true para Artist("Bob Dylan", "USA") adicionado diretamente e para Artist("Thom Yorke", "UK") pertencente a uma Band adicionada, e false para Artist("Bob Dylan", "UK") ou Artist("Tom Yorke", "UK"). Que técnica de polimorfismo resolve isto sem testar o tipo concreto de cada Act?
Solução
Percorre-se a lista de Act: se o elemento for uma Band e band.getArtists().contains(artist) for true, ou se act.equals(artist), então participates devolve true. Artist("Bob Dylan", "UK") falha porque o país não coincide.
Um artista participa num concerto se está na lista diretamente ou nos artistas de uma banda da lista. A pertinência à banda usa o equals do artista, que compara nome e país, pelo que mudar só o país não engana o método.
Confere a tua resposta:
- A resposta lista os casos verdadeiros e falsos do enunciado.
- A justificação usa
instanceof Bandmaisequalsdo artista, ou um método polimórfico equivalente. - A comparação do artista exige nome e país coincidentes.
Username como nome concatenado com a idadeAutoavaliação
Quiz Event, 2018
Todo User tem getUsername() igual ao nome seguido da idade, sem separador: new Attendee("John", 43) produz "John43", new Speaker("Bill Gates", 12) produz "Bill Gates12" e new Artist("Beck", 20) produz "Beck20". Percorrendo uma ArrayList<User> com essas três pessoas, a concatenação dos usernames com vírgula inicial dá ",John43,Bill Gates12,Beck20". Onde deve viver o getUsername() para todas as subclasses o herdarem corretamente?
Solução
getUsername() fica em Person (a superclasse comum) e devolve getName() + getAge(). Assim Attendee, Speaker e Artist herdam o mesmo método, cada um com os seus dados.
O username depende só de nome e idade, que são comuns a todas as pessoas. Definir o método uma vez na superclasse evita repetir código em cada subclasse e garante o mesmo formato para todos.
Confere a tua resposta:
- A resposta coloca
getUsername()na superclasse, comoname + age. - A resposta indica a cadeia final
",John43,Bill Gates12,Beck20". - A justificação nota que cada subclasse usa os seus próprios nome e idade.
Exceções e contratos
Ticket inválido e validação pelo concertoAutoavaliação
Quiz Act, 2019
Um Ticket tem número e concerto. new Ticket(-1, concert) deve lançar a exceção InvalidTicket. concert.isValid(ticket) devolve true para o concerto do bilhete e false para um concerto na mesma cidade no dia seguinte. Escreva o construtor de Ticket com a validação e o método isValid.
Solução
No construtor: if (number < 0) throw new InvalidTicket();. Em Concert: isValid(ticket) devolve ticket.getConcert().equals(this).
O número negativo viola o contrato do bilhete, pelo que a exceção é lançada na construção, antes de o objeto existir. A validade testa-se por igualdade de concertos (cidade, país e data), e não por identidade da referência.
Confere a tua resposta:
- O construtor de
TicketlançaInvalidTicketquando o número é negativo. isValidcompara o concerto do bilhete com o recetor usandoequals.- Um bilhete do concerto de 2019-10-11 não é válido no concerto de 2019-10-10.
Padrões de desenho
Command abstrato e AddScoopCommandAutoavaliação
Quiz Flavor, 2020
A classe Command é abstrata com execute(Icecream) e undo(Icecream). AddScoopCommand guarda um Flavor e, ao executar, adiciona uma bola desse sabor ao sorvete; ao desfazer, remove a última bola. new AddScoopCommand(chocolate).execute(icecream) faz icecream.contains("chocolate") devolver true. Descreva a estrutura das duas classes.
Solução
Command abstrata com execute(Icecream) e undo(Icecream); AddScoopCommand extends Command guarda flavor e implementa execute como icecream.addScoop(flavor) e undo como remover a última bola.
Encapsular o pedido num objeto permite guardá-lo, executá-lo e desfazê-lo mais tarde, sem que quem chama conheça os detalhes. É a base do padrão Command.
Confere a tua resposta:
Commandé declaradaabstractcom os dois métodos abstratos.AddScoopCommandguarda o sabor num campo não público.executeadiciona o sabor eundoremove a última bola.
IcecreamMachine com anulação do último comandoAutoavaliação
Quiz Flavor, 2020
A IcecreamMachine guarda o sorvete e uma pilha de comandos. executeCommand executa e empilha; undoLastCommand desfaz o comando do topo e tira-o da pilha; os métodos devolvem a própria máquina para encadear chamadas. Executam-se chocolate, strawberry e chocolate (3 bolas, 2 sabores); undoLastCommand() seguido de vanilla deixa 3 bolas e 3 sabores; depois dois undoLastCommand() e um novo chocolate deixam 2 bolas e 1 sabor. Confirme estes valores e explique o papel da pilha.
Solução
Valores confirmados: (3 bolas, 2 sabores), depois (3 bolas, 3 sabores), no final (2 bolas, 1 sabor, só chocolate). A pilha guarda os comandos por ordem de execução e undoLastCommand desfaz o mais recente primeiro (LIFO).
A pilha desfaz os comandos por ordem inversa: o primeiro undoLastCommand retira o terceiro comando (chocolate repetido), quedando 2 bolas e 2 sabores; o vanilla leva a 3 bolas e 3 sabores. As duas anulações seguintes retiram o vanilla e o strawberry, e o novo chocolate deixa 2 bolas e apenas o sabor chocolate.
Confere a tua resposta:
- A resposta confirma 3 bolas e 2 sabores após os três comandos.
- A resposta confirma 3 bolas e 3 sabores após a anulação e o vanilla.
- A resposta confirma 2 bolas e 1 sabor no final.
- A justificação associa a pilha à ordem inversa das anulações.
MargueritaCertifier: estratégia de certificaçãoAutoavaliação
Quiz Pizza, 2021
PizzaCertifier é abstrata com isCertified(Pizza). Uma pizza marguerita leva exatamente Tomato, Mozzarella e Basil, por qualquer ordem, e mais nenhum ingrediente. MargueritaCertifier.isCertified devolve true para as duas pizzas com esses três ingredientes, false se falta o Basil, e deixa de ser true depois de adicionar Ham. Implemente a verificação.
Solução
isCertified devolve true quando a pizza tem 3 ingredientes e contém Tomato, Mozzarella e Basil; false caso contrário (falta algum ou sobra algum, como o Ham).
O certificar é uma estratégia trocável: a mesma interface PizzaCertifier pode ter outras implementações para outros tipos de pizza. A regra da marguerita é de quantidade e de conteúdo, não de ordem.
Confere a tua resposta:
- A resposta lista os casos do enunciado com os respetivos valores de
isCertified. - A verificação exige exatamente três ingredientes: Tomato, Mozzarella e Basil.
- A ordem dos ingredientes não altera o resultado.
- Qualquer ingrediente extra faz a certificação falhar.
GenericRecipe copia a lista de ingredientesAutoavaliação
Quiz Pizza, 2021
Recipe é abstrata com makeMediumPizza(). new GenericRecipe(ingredients) recebe uma lista com Mozzarella, Ham e Pineapple. A primeira pizza não é certificada como marguerita. Depois alteram-se a lista original (removem-se Ham e Pineapple, adicionam-se Tomato e Basil) e a segunda pizza passa a ser certificada. Explique que contrato isto revela sobre a forma como a receita guarda a lista.
Solução
A primeira makeMediumPizza() produz pizza com Mozzarella, Ham e Pineapple (isCertified falso); a segunda, depois das alterações na lista original, produz Mozzarella, Tomato e Basil (isCertified verdadeiro).
Como a segunda pizza já reflete as alterações feitas depois da construção, a receita não copiou a lista: guardou a referência original. Quem altera a lista depois de criar a receita altera o resultado das pizzas seguintes, sem aviso. Uma cópia defensiva no construtor impediria esse efeito.
Confere a tua resposta:
- A primeira pizza tem Mozzarella, Ham e Pineapple e não é marguerita.
- A segunda pizza tem Mozzarella, Tomato e Basil e é certificada.
- A justificação é que a receita guarda a referência da lista original, não uma cópia.
SlicedPizza: decorador que soma 2 ao preçoAutoavaliação
Quiz Pizza, 2021
SlicedPizza implementa a mesma interface Pizza que a pizza embrulhada e guarda slices. Uma new SlicedPizza(pizza, 8) tem getSlices() == 8, é instanceof Pizza, e getPrice() devolve o preço da pizza mais 2: com preço 8.0 devolve 10.0, e depois de pizza.setPrice(6.0) devolve 8.0. setPrice e addIngredient delegam na pizza embrulhada. Descreva a estrutura do decorador.
Solução
Decorador: getPrice() = pizza.getPrice() + 2.0, pelo que 8.0 dá 10.0 e, depois de setPrice(6.0) na base, 6.0 + 2.0 = 8.0. setPrice, addIngredient, contains e getIngredientCount delegam na pizza guardada; getSlices() devolve 8.
O decorador envolve outro objeto da mesma interface e acrescenta comportamento (o custo extra de 2 e o número de fatias) sem mudar a interface. Como o preço é calculado a partir da pizza embrulhada, mudar o preço da base reflete-se no preço final.
Confere a tua resposta:
SlicedPizza implements Pizzae guarda a pizza embrulhada e o número de fatias.getPrice()devolvepizza.getPrice() + 2.0(10.0 e depois 8.0).getSlices()devolve 8 e os restantes métodos delegam na pizza embrulhada.- A justificação refere que o acréscimo de 2 ao preço é fixo, qualquer que seja o preço da pizza base.