Herança e Composição/Exercício 04: Arabian Nights in Java

From Wiki**3

Problema

Aplicando os conceitos OO que já conhece, concretize as classes necessárias para representar a funcionalidade que se descreve de seguida. Pode ser necessária a criação de classes adicionais não descritas abaixo. A correcta execução dos testes depende da estrita aderência à nomenclatura das classes apresentadas. Todas as classes indicadas devem pertencer à "package" arabiannights.

Funcionalidade da lâmpada mágica (classe "MagicLamp")

Uma lâmpada mágica liberta génios quando esfregada (método rub). Os génios podem ser bem ou mal-humorados. O humor dos génios é determinado pelas condições da lâmpada: sempre que a lâmpada tiver sido esfregada um número par de vezes (sem contar a actual), o génio sai mal-humorado. A quantidade de génios disponíveis é determinada no momento de encantamento da lâmpada (criação). Depois de esgotados os génios disponíveis, já não adianta esfregar a lâmpada para obter um génio, bem ou mal-humorado: nestas condições, a lâmpada cria um pequeno demónio que responde a pedidos de forma literal mas perversa. Devido a requisitos de sustentabilidade ambiental, as normas de produção exigem que as lâmpadas sejam recarregáveis. Assim, é possível voltar a obter génios quando se esfrega a lâmpada (em número igual ao inicial). O processo de recarregamento exige apenas que um demónio seja alimentado à lâmpada (método feedDemon).

Quando se cria uma nova lâmpada é necessário indicar a quantidade inicial de génios que é possível invocar. É possível saber quantos génios ainda estão disponíveis na lâmpada (método getGenies). É ainda possível saber quantas vezes a lâmpada já foi recarregada (método getDemons). Quando se esfrega a lâmpada, deve-se indicar quantos desejos se espera que o génio realize (independentemente de o génio os poder negar).

A classe MagicLamp deve saber comparar as suas instâncias (através do método equals). Considera-se que duas lâmpadas são iguais se tiverem a mesma capacidade e se os valores retornados pelos métodos getGenies e getDemons forem iguais.

Nota: a lâmpada liberta apenas um génio de cada vez.

Funcionalidade do génio bem-humorado (classe "FriendlyGenie")

O génio bem-humorado concede todos os desejos que lhe forem colocados (método grantWish e retorno true), até ao limite com que foi chamado da lâmpada. Depois do limite já não são concedidos desejos (retorno false). É possível saber quantos desejos já foram concedidos (método getGrantedWishes) e quantos ainda existem disponíveis (método getRemainingWishes).

Nota: o génio concede apenas um desejo de cada vez.

Funcionalidade do génio mal-humorado (classe "GrumpyGenie")

O génio mal-humorado concede apenas o primeiro desejo que lhe for colocado (método grantWish e retorno true), independentemente do limite com que foi chamado da lâmpada (retorno false após o primeiro). É possível saber se o desejo já foi realizado (método getGrantedWishes retorna 1).

Funcionalidade do demónio reciclável (classe "RecyclableDemon")

O demónio concede todos os desejos que lhe forem colocados (método grantWish e retorno true), independentemente do limite com que foi chamado da lâmpada. Se o demónio for recolocado na lâmpada (para a recarregar), já não pode realizar mais desejos (retorno false). É possível saber quantos desejos já foram concedidos (método getGrantedWishes).

Nota: o demónio concede apenas um desejo de cada vez.

Observações

Todas as classes devem ter métodos de acesso (get e set) (quando apropriado) para os seus atributos.

O método toString, aplicado aos génios e ao demónio, deve devolver uma das seguintes cadeias de caracteres:

  • Friendly genie has granted # wishes and still has # to grant. (os # representam os contadores apropriados)
  • Grumpy genie has granted a wish. / Grumpy genie has a wish to grant. (consoante já concedeu ou não o pedido)
  • Recyclable demon has granted # wishes. / Demon has been recycled. (antes e depois de recarregar uma lâmpada)

A classe cliente, de nome ArabianNights deve possuir um método (static) main que execute a seguinte sequência de operações:

  1. Criar uma lâmpada mágica com capacidade para 4 génios.
  2. Esfregar 5 vezes a lâmpada, indicando os números de desejos 2, 3, 4, 5, 1.
  3. Invocar e imprimir o resultado do método toString sobre cada um dos génios.
  4. Pedir um desejo a cada um dos génios.
  5. Invocar e imprimir o resultado do método toString sobre cada um dos génios.
  6. Pedir um desejo a cada um dos génios.
  7. Invocar e imprimir o resultado do método toString sobre cada um dos génios.
  8. Colocar o demónio reciclável na lâmpada.
  9. Esfregar a lâmpada, indicando 7 como número de desejos.
  10. Invocar e imprimir o resultado do método toString sobre o génio obtido.

Solution

The following corresponds to a possible telling of a special version of the Arabian Nights stories. In any implementation, the following concepts will exist in one form or another: MagicLamp, Genie (a general type of genie, which may also describe the recyclable demon), FriendlyGenie, GrumpyGenie, and RecyclableDemon.

UML Class Diagram

Diagrama de classes

Class MagicLamp

'Ficheiro MagicLamp.java'
{{{2}}}

Class Genie

Class Genie defines the basic behaviour for all genies.

Note that, since Genie is a class whose methods are to be redefined by subclasses and whose references will only point to subclass instances.

'Ficheiro Genie.java'
{{{2}}}

Class FriendlyGenie

A friendly genie is almost like a general genie (it differs in the output messages).

'Ficheiro FriendlyGenie.java'

<java5> package arabiannights;

/**

* A friendly genie is actually a normal genie, but with special descriptive text.
*/

public class FriendlyGenie extends Genie {

/** * @param limit * the maximum number of wishes to grant. */ public FriendlyGenie(int limit) { super(limit); }

/** * @return the number of wishes left to grant. */ public int getRemainingWishes() { return getLimit() - getGrantedWishes(); }

/** * @see java.lang.Object#toString() */ @Override public String toString() { return "Friendly genie has granted " + getGrantedWishes() + " wishes and still has " + getRemainingWishes() + " to grant."; }

} </java5>

Class GrumpyGenie

Redefines a few methods.

'Ficheiro GrumpyGenie.java'
{{{2}}}

Class RecyclableDemon

The RecyclableDemon is a genie that implements some of the control methods in a special way (but still adheres to the template method defined by class Genie).

'Ficheiro RecyclableDemon.java'
{{{2}}}

The Application

In this case, the main class is straightforward.

Numbers in comments correspond to the specified steps in the problem above.

'Ficheiro ArabianNights.java'
{{{2}}}

Compiling and Running

How to Compile?

The compilation is as follows:

javac arabiannights/MagicLamp.java
javac arabiannights/Genie.java
javac arabiannights/FriendlyGenie.java
javac arabiannights/GrumpyGenie.java
javac arabiannights/RecyclableDemon.java
javac ArabianNights.java

In fact, compiling ArabianNights.java would cause the rest of them be compiled as well (the Java compiler accounts for all explicit class dependencies).

We assume that the CLASSPATH environment variable contains the current directory

Running

The program starts at a main function (in this case, contained in the ArabianNights class):

java ArabianNights

See Also