|
|
(10 intermediate revisions by the same user not shown) |
Line 1: |
Line 1: |
| {{TOCright}}
| | #REDIRECT [[ist:Introdução aos Objectos/Exercício 02: Energia]] |
| = Problema =
| |
| | |
| Numa casa de campo existem vários animais.
| |
| | |
| Alguns animais são domésticos: cães, gatos e pássaros (canários, etc.). Os donos acreditam em dar liberdade completa aos animais, o que causa alguns problemas de interacção nem sempre do agrado geral.
| |
| | |
| Outros animais, embora vivam na casa ou perto dela, não são oficialmente considerados animais domésticos: ratos, cobras, insectos, aranhas, etc. Estes animais também se deslocam pela propriedade, livre mas nem sempre impunemente.
| |
| | |
| Todos os animais podem correr (e os pássaros voar), consumindo energia para o efeito. Quando a energia termina, não podem correr mais e têm de dormir para recuperar forças.
| |
| | |
| Além do repouso, os cães e os gatos podem recuperar energia comendo ratos. Um rato devorado perde, claro está, toda a energia (é transferida para o predador). Os gatos, por serem ágeis, também conseguem comer pássaros (com efeitos muito semelhantes aos da relação gato-rato).
| |
| | |
| Por vezes, os cães perdem a paciência e atacam os gatos. Ambos perdem energia no processo.
| |
| | |
| Modele os conceitos "cão", "gato", "pássaro" e "rato". Além da energia, os cães e os gatos têm nome (uma cadeia de caracteres).
| |
| | |
| Considere que a energia disponível inicialmente para os cães, gatos, pássaros e ratos é, respectivamente, de 1000, 500, 20 e 50 unidades. Quando os animais correm, gastam, respectivamente, 50, 25, 5 e 2 unidades. Um pássaro, quando voa, gasta apenas 2 unidades. Um cão que ataque um gato gasta 100 unidades e faz com que o gato perca 25.
| |
| | |
| Para um predador comer uma presa tem de a perseguir para a capturar (podendo a perseguição ser ou não bem sucedida). Um cão consegue capturar um rato em cada 25 tentativas. Para os gatos, o rácio é 1 em 5 (ratos) e 1 em 10 (pássaros). A perseguição consome a mesma energia que correr (para cada interveniente), mas a presa recebe um bónus de 5 unidades se escapar. Se a presa estiver a dormir, é apanhada 1 em cada 2 tentativas.
| |
| | |
| Construa uma aplicação onde existem 2 cães ("Piloto" e "Átila"), 3 gatos ("Tareco", "Pantufa" e "Kitty"), 20 pássaros e 50 ratos (os pássaros e ratos podem ser organizados em arrays).
| |
| | |
| Neste cenário, os gatos correm, perseguem pássaros e ratos e são atacados pelos cães, que também podem correr e perseguir e comer ratos. Os animais dormem automaticamente se ficam sem energia (excepto quando são devorados: nesse caso devem ser considerados mortos).
| |
| | |
| Apresente o estado inicial dos animais (métodos toString) e o estado final (depois de algumas interacções).
| |
| | |
| (Pode utilizar parte do resultado do [[Introdução aos Objectos/Exercício 01: Gato simples|Exercício 01]] na resolução deste exercicio.)
| |
| | |
| = Solução =
| |
| | |
| A solução apresentada procura manter-se simples e a um nível que ainda não implica utilizar abstracção de propriedade comuns, como por exemplo, a energia, ou de conceitos mais básicos (o de Animal, por exemplo). Estes aspectos, '''necessários numa [[Herança e Composição/Exercício 03: Energia|boa definição de solução]]''', são objecto de estudo em fases mais adiantadas da exposição da matéria.
| |
| | |
| == UML: Diagrama de Classes ==
| |
| | |
| Neste caso, como se escolheu (dada a fase introdutória) não representar os conceitos hierarquizados, apenas existem relações de dependência entre as classes (representadas pelas setas a tracejado).
| |
| | |
| [[Image:PO-dog-cat-mouse-bird-energy-noinheritance.png]]
| |
| | |
| There are several suboptimal design choices. Can you spot them?
| |
| | |
| == Conceito de Cão: Dog ==
| |
| | |
| <java5>
| |
| public class Dog {
| |
| | |
| /**
| |
| * We define the base energy as a constant, but it does not have to be this
| |
| * way. It could be defined differently for each dog (but this requirement
| |
| * does not exist in this case).
| |
| */
| |
| private static final int BASE_ENERGY = 1000;
| |
| | |
| /**
| |
| * The dog's name.
| |
| */
| |
| private String _name;
| |
| | |
| /**
| |
| * The dog's current energy value.
| |
| */
| |
| private int _energy = BASE_ENERGY;
| |
| | |
| /**
| |
| * Initialize a dog with a name. Default energy levels are used.
| |
| *
| |
| * @param name
| |
| */
| |
| public Dog(String name) {
| |
| _name = name;
| |
| }
| |
| | |
| /**
| |
| * @return dog's current energy level.
| |
| */
| |
| private int getEnergy() {
| |
| return _energy;
| |
| }
| |
| | |
| /**
| |
| * @return dog's name
| |
| */
| |
| public String getName() {
| |
| return _name;
| |
| }
| |
| | |
| /**
| |
| * Set the dog's name
| |
| *
| |
| * @param name
| |
| * the dog's name
| |
| */
| |
| public void setName(String name) {
| |
| _name = name;
| |
| }
| |
| | |
| /**
| |
| * When a dog runs, the energy decreases by 50 units. This value could be
| |
| * defined as an attribute or as a constant.
| |
| *
| |
| * @return whether the dog was able to run.
| |
| */
| |
| public boolean run() {
| |
| if (_energy < 50)
| |
| return false;
| |
| _energy -= 50;
| |
| return true;
| |
| }
| |
| | |
| /**
| |
| * Call "run" to account for spent energy.
| |
| *
| |
| * @param mouse
| |
| * the mouse to be chased.
| |
| * @return whether the dog was able to catch the mouse. If the mouse
| |
| * escapes, its energy increases.
| |
| */
| |
| public boolean caughtMouse(Mouse mouse) {
| |
| run();
| |
| mouse.run();
| |
| if (0 == (int) (25 * Math.random())) {
| |
| return true;
| |
| }
| |
| mouse.escaped();
| |
| return false;
| |
| }
| |
| | |
| /**
| |
| * Eating is more or less like a vampire feeding...
| |
| *
| |
| * @param mouse
| |
| * the mouse to eat.
| |
| */
| |
| public void eatMouse(Mouse mouse) {
| |
| if (caughtMouse(mouse))
| |
| _energy += mouse.drain();
| |
| }
| |
| | |
| /**
| |
| * We assume that the dog is always able to attack the cat. The parameter to
| |
| * ''attacked'' is used to specify the amount of energy lost by the cat.
| |
| * Note that we are assuming that the degree of loss depends on the attacker
| |
| * (hence the value being defined in the dog class).
| |
| *
| |
| * The energy values could be defined as attributes or as constants.
| |
| *
| |
| * @param cat
| |
| * the cat the dog attacks
| |
| */
| |
| public void attackCat(Cat cat) {
| |
| _energy -= 100;
| |
| cat.attacked(25);
| |
| }
| |
| | |
| /**
| |
| * Energy is recovered when sleeping.
| |
| */
| |
| public void sleep() {
| |
| _energy = BASE_ENERGY;
| |
| }
| |
| | |
| /**
| |
| * @see java.lang.Object#equals(java.lang.Object)
| |
| */
| |
| @Override
| |
| public boolean equals(Object o) {
| |
| if (o instanceof Dog) {
| |
| Dog dog = (Dog) o;
| |
| return _name.equals(dog.getName()) && _energy == dog.getEnergy();
| |
| }
| |
| return false;
| |
| }
| |
| | |
| /**
| |
| * @see java.lang.Object#toString()
| |
| */
| |
| @Override
| |
| @SuppressWarnings("nls")
| |
| public String toString() {
| |
| return _name + " (dog) (" + _energy + ")";
| |
| }
| |
| }
| |
| </java5>
| |
| | |
| == Conceito de Gato: Cat ==
| |
| | |
| <java5>
| |
| public class Cat {
| |
| | |
| /**
| |
| * We define the base energy as a constant, but it does not have to be this
| |
| * way. It could be defined differently for each dog (but this requirement
| |
| * does not exist in this case).
| |
| */
| |
| private static final int BASE_ENERGY = 500;
| |
| | |
| /**
| |
| * The cat's name.
| |
| */
| |
| private String _name;
| |
| | |
| /**
| |
| * The cat's current energy value.
| |
| */
| |
| private int _energy = BASE_ENERGY;
| |
| | |
| /**
| |
| * Initialize a cat with a name. Default energy levels are used.
| |
| *
| |
| * @param name
| |
| */
| |
| public Cat(String name) {
| |
| _name = name;
| |
| }
| |
| | |
| /**
| |
| * @return cat's current energy level.
| |
| */
| |
| private int getEnergy() {
| |
| return _energy;
| |
| }
| |
| | |
| /**
| |
| * @return cat's name
| |
| */
| |
| public String getName() {
| |
| return _name;
| |
| }
| |
| | |
| /**
| |
| * Set the cat's name
| |
| *
| |
| * @param name
| |
| * the cat's name
| |
| */
| |
| public void setName(String name) {
| |
| _name = name;
| |
| }
| |
| | |
| /**
| |
| * When a cat runs, the energy decreases by 25 units. This value could be
| |
| * defined as an attribute or as a constant.
| |
| *
| |
| * @return whether the cat was able to run.
| |
| */
| |
| public boolean run() {
| |
| if (_energy < 25)
| |
| return false;
| |
| _energy -= 25;
| |
| return true;
| |
| }
| |
| | |
| /**
| |
| * Call "run" to account for spent energy.
| |
| *
| |
| * @param mouse
| |
| * the mouse to be caught.
| |
| * @return whether the cat was able to catch the mouse. If the mouse
| |
| * escapes, its energy increases.
| |
| */
| |
| public boolean caughtMouse(Mouse mouse) {
| |
| run();
| |
| mouse.run();
| |
| if (0 == (int) (5 * Math.random())) {
| |
| return true;
| |
| }
| |
| mouse.escaped();
| |
| return false;
| |
| }
| |
| | |
| /**
| |
| * Call "run" ("fly"??) to account for spent energy.
| |
| *
| |
| * @param bird
| |
| * the bird to be caught.
| |
| * @return whether the cat was able to catch the bird. If the bird escapes,
| |
| * its energy increases.
| |
| */
| |
| public boolean caughtBird(Bird bird) {
| |
| run();
| |
| bird.fly(); // run??
| |
| if (0 == (int) (10 * Math.random())) {
| |
| return true;
| |
| }
| |
| bird.escaped();
| |
| return false;
| |
| }
| |
| | |
| /**
| |
| * Eating is more or less like a vampire feeding...
| |
| *
| |
| * @param mouse
| |
| * the mouse to eat.
| |
| */
| |
| public void eatMouse(Mouse mouse) {
| |
| if (caughtMouse(mouse))
| |
| _energy += mouse.drain();
| |
| }
| |
| | |
| /**
| |
| * Eating is more or less like a vampire feeding...
| |
| *
| |
| * @param bird
| |
| * the mouse to eat.
| |
| */
| |
| public void eatBird(Bird bird) {
| |
| if (caughtBird(bird))
| |
| _energy += bird.drain();
| |
| }
| |
| | |
| /**
| |
| * We should probably check for large decrease values. Nevertheless, in this
| |
| * case, for simplicity, we will let the energy go negative and, later on,
| |
| * the cat can recover after a nap.
| |
| *
| |
| * @param energyDecrease
| |
| */
| |
| public void attacked(int energyDecrease) {
| |
| _energy -= energyDecrease;
| |
| }
| |
| | |
| /**
| |
| * Energy is recovered when sleeping.
| |
| */
| |
| public void sleep() {
| |
| _energy = BASE_ENERGY;
| |
| }
| |
| | |
| /**
| |
| * @see java.lang.Object#equals(java.lang.Object)
| |
| */
| |
| @Override
| |
| public boolean equals(Object o) {
| |
| if (o instanceof Cat) {
| |
| Cat cat = (Cat) o;
| |
| return _name.equals(cat.getName()) && _energy == cat.getEnergy();
| |
| }
| |
| return false;
| |
| }
| |
| | |
| /**
| |
| * @see java.lang.Object#toString()
| |
| */
| |
| @Override
| |
| @SuppressWarnings("nls")
| |
| public String toString() {
| |
| return _name + " (cat) (" + _energy + ")";
| |
| }
| |
| }
| |
| </java5>
| |
| | |
| == Conceito de Rato: Mouse ==
| |
| | |
| <java5>
| |
| public class Mouse {
| |
| | |
| /**
| |
| * We define the base energy as a constant, but it does not have to be this
| |
| * way. It could be defined differently for each dog (but this requirement
| |
| * does not exist in this case).
| |
| */
| |
| private static final int BASE_ENERGY = 50;
| |
| | |
| /**
| |
| * The mouse's current energy value.
| |
| */
| |
| private int _energy = BASE_ENERGY;
| |
| | |
| /**
| |
| * @return mouse's current energy level.
| |
| */
| |
| public int getEnergy() {
| |
| return _energy;
| |
| }
| |
| | |
| /**
| |
| * When a mouse runs, the energy decreases by 2 units. This value could be
| |
| * defined as an attribute or as a constant.
| |
| *
| |
| * @return whether the mouse was able to run.
| |
| */
| |
| public boolean run() {
| |
| if (_energy < 2)
| |
| return false;
| |
| _energy -= 2;
| |
| return true;
| |
| }
| |
| | |
| /**
| |
| * Energy goes up 5 points in a narrow escape.
| |
| */
| |
| public void escaped() {
| |
| _energy += 5;
| |
| }
| |
| | |
| /**
| |
| * @return the energy level in this mouse
| |
| */
| |
| public int drain() {
| |
| int energy = _energy;
| |
| _energy = 0;
| |
| return energy;
| |
| }
| |
| | |
| /**
| |
| * Energy is recovered when sleeping.
| |
| */
| |
| public void sleep() {
| |
| _energy = BASE_ENERGY;
| |
| }
| |
| | |
| /**
| |
| * @see java.lang.Object#equals(java.lang.Object)
| |
| */
| |
| @Override
| |
| public boolean equals(Object o) {
| |
| if (o instanceof Mouse) {
| |
| Mouse mouse = (Mouse) o;
| |
| return _energy == mouse.getEnergy();
| |
| }
| |
| return false;
| |
| }
| |
| | |
| /**
| |
| * @see java.lang.Object#toString()
| |
| */
| |
| @Override
| |
| public String toString() {
| |
| return "mouse (" + _energy + ")";
| |
| }
| |
| }
| |
| </java5>
| |
| | |
| == Conceito de Pássaro: Bird ==
| |
| | |
| <java5>
| |
| public class Bird {
| |
| | |
| /**
| |
| * We define the base energy as a constant, but it does not have to be this
| |
| * way. It could be defined differently for each dog (but this requirement
| |
| * does not exist in this case).
| |
| */
| |
| private static final int BASE_ENERGY = 20;
| |
| | |
| /**
| |
| * The bird's current energy value.
| |
| */
| |
| private int _energy = BASE_ENERGY;
| |
| | |
| /**
| |
| * @return mouse's current energy level.
| |
| */
| |
| public int getEnergy() {
| |
| return _energy;
| |
| }
| |
| | |
| /**
| |
| * When a bird runs, the energy decreases by 5 units. This value could be
| |
| * defined as an attribute or as a constant.
| |
| *
| |
| * @return whether the bird was able to run.
| |
| */
| |
| public boolean run() {
| |
| if (_energy < 5)
| |
| return false;
| |
| _energy -= 5;
| |
| return true;
| |
| }
| |
| | |
| /**
| |
| * When a bird flies, the energy decreases by 2 units. This value could be
| |
| * defined as an attribute or as a constant.
| |
| *
| |
| * @return whether the bird was able to fly.
| |
| */
| |
| public boolean fly() {
| |
| if (_energy < 2)
| |
| return false;
| |
| _energy -= 2;
| |
| return true;
| |
| }
| |
| | |
| /**
| |
| * Energy goes up 5 points in a narrow escape.
| |
| */
| |
| public void escaped() {
| |
| _energy += 5;
| |
| }
| |
| | |
| /**
| |
| * @return the energy level in this mouse
| |
| */
| |
| public int drain() {
| |
| int energy = _energy;
| |
| _energy = 0;
| |
| return energy;
| |
| }
| |
| | |
| /**
| |
| * Energy is recovered when sleeping.
| |
| */
| |
| public void sleep() {
| |
| _energy = BASE_ENERGY;
| |
| }
| |
| | |
| /**
| |
| * @see java.lang.Object#equals(java.lang.Object)
| |
| */
| |
| @Override
| |
| public boolean equals(Object o) {
| |
| if (o instanceof Bird) {
| |
| Bird bird = (Bird) o;
| |
| return _energy == bird.getEnergy();
| |
| }
| |
| return false;
| |
| }
| |
| | |
| /**
| |
| * @see java.lang.Object#toString()
| |
| */
| |
| @Override
| |
| public String toString() {
| |
| return "bird (" + _energy + ")";
| |
| }
| |
| }
| |
| </java5>
| |
| | |
| == Programa Principal ==
| |
| | |
| Este programa implementa o cenário descrito no enunciado do problema.
| |
| <java5>
| |
| @SuppressWarnings("nls")
| |
| public class Application {
| |
| | |
| /**
| |
| * @param args
| |
| */
| |
| public static void main(String[] args) {
| |
| Dog d1 = new Dog("Piloto");
| |
| Dog d2 = new Dog("Átila");
| |
| | |
| Cat c1 = new Cat("Tareco");
| |
| Cat c2 = new Cat("Pantufa");
| |
| Cat c3 = new Cat("Kitty");
| |
|
| |
| Bird[] birds = new Bird[20];
| |
| for (int ix = 0; ix < birds.length; ix++)
| |
| birds[ix] = new Bird();
| |
| | |
| Mouse[] mice = new Mouse[50];
| |
| for (int ix = 0; ix < mice.length; ix++)
| |
| mice[ix] = new Mouse();
| |
| | |
| // snapshot: present everything
| |
| System.out.println("BEFORE");
| |
| System.out.println(d1);
| |
| System.out.println(d2);
| |
| System.out.println(c1);
| |
| System.out.println(c2);
| |
| System.out.println(c3);
| |
| | |
| for (int ix = 0; ix < birds.length; ix++)
| |
| System.out.println(birds[ix]);
| |
| | |
| for (int ix = 0; ix < mice.length; ix++)
| |
| System.out.println(mice[ix]);
| |
| | |
| // run, chase, eat, sleep, etc.
| |
| | |
| for (int ix = 0; ix < birds.length; ix++)
| |
| birds[ix].fly();
| |
| | |
| d1.run();
| |
| d2.attackCat(c1);
| |
| c2.eatBird(birds[2]);
| |
| c3.eatBird(birds[9]);
| |
| c3.eatMouse(mice[0]);
| |
| d2.eatMouse(mice[1]);
| |
| mice[3].run();
| |
| | |
| // snapshot: present everything
| |
| System.out.println("AFTER");
| |
| System.out.println(d1);
| |
| System.out.println(d2);
| |
| System.out.println(c1);
| |
| System.out.println(c2);
| |
| System.out.println(c3);
| |
| | |
| for (int ix = 0; ix < birds.length; ix++)
| |
| System.out.println(birds[ix]);
| |
| | |
| for (int ix = 0; ix < mice.length; ix++)
| |
| System.out.println(mice[ix]);
| |
| | |
| }
| |
| }
| |
| </java5>
| |
| | |
| = Compilação e Execução =
| |
| | |
| == Como compilar? ==
| |
| A compilação processa-se como indicado (poder-se-ia compilar ficheiro a ficheiro):
| |
| | |
| javac Dog.java Cat.java Mouse.java Bird.java
| |
| javac Application.java
| |
| | |
| De facto, a compilação do ficheiro '''Application.java''' seria suficiente para causar a compilação de todos os outros, já que são referidos a partir dele (o compilador de Java é capaz de seguir dependências explícitas entre classes).
| |
| | |
| == Execução ==
| |
| | |
| O programa começa a sua execução na função '''main''' da classe escolhida para iniciar a aplicação (neste caso, '''Application'''):
| |
| | |
| java Application
| |
| | |
| [[category:Teaching]]
| |
| [[category:PO]]
| |
| [[category:PO Exemplos]]
| |