Difference between revisions of "Introdução aos Objectos/Exercício 02: Energia"

From Wiki**3

< Introdução aos Objectos
(Conceito de Gato)
 
(44 intermediate revisions by the same user not shown)
Line 18: Line 18:
 
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.
 
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.
+
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).
 
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).
Line 30: Line 30:
 
= Solução =
 
= 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 boa definição de solução''' são objecto de estudo em fases mais adiantadas da exposição da matéria.
+
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 ==
 
== UML: Diagrama de Classes ==
Line 36: Line 36:
 
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).
 
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.png]]
+
Existem opções de desenho sub-óptimas. Consegue detectá-las?
  
== Conceito de Cão: Dog ==
+
BUG: o método "escaped" deveria ter como tipo de retorno "void" e não "boolean".
  
<java5>
+
{{CollapsedCode|Diagrama de classes|
 +
[[Image:PO-dog-cat-mouse-bird-energy-noinheritance.png]]
 +
}}
 +
 
 +
== Conceito de Cão ==
 +
 
 +
{{CollapsedCode|Ficheiro '''Dog.java'''|
 +
<source lang="java">
 
public class Dog {
 
public class Dog {
  
/**
+
    /**
* We define the base energy as a constant, but it does not have to be this
+
    * 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
+
    * way. It could be defined differently for each dog (but this requirement
* does not exist in this case).
+
    * does not exist in this case).
*/
+
    */
private static final int BASE_ENERGY = 1000;
+
    private static final int BASE_ENERGY = 1000;
 +
 
 +
    /**
 +
    * The dog's name.
 +
    */
 +
    private String _name;
  
/**
+
    /**
* The dog's name.
+
    * The dog's current energy value.
*/
+
    */
private String _name;
+
    private int _energy = BASE_ENERGY;
  
/**
+
    /**
* The dog's current energy value.
+
    * Initialize a dog with a name. Default energy levels are used.
*/
+
    *
private int _energy = BASE_ENERGY;
+
    * @param name
 +
    */
 +
    public Dog(String name) {
 +
        _name = name;
 +
    }
  
/**
+
    /**
* @return dog's current energy level.
+
    * @return dog's current energy level.
*/
+
    */
private int getEnergy() {
+
    public int getEnergy() {
return _energy;
+
        return _energy;
}
+
    }
  
/**
+
    /**
* @return dog's name
+
    * @return dog's name
*/
+
    */
public String getName() {
+
    public String getName() {
return _name;
+
        return _name;
}
+
    }
  
/**
+
    /**
* Set the dog's name
+
    * Set the dog's name
*  
+
    *
* @param name
+
    * @param name
*            the dog's name
+
    *            the dog's name
*/
+
    */
public void setName(String name) {
+
    public void setName(String name) {
_name = name;
+
        _name = name;
}
+
    }
  
/**
+
    /**
* When a dog runs, the energy decreases by 50 units. This value could be
+
    * When a dog runs, the energy decreases by 50 units. This value could be
* defined as an attribute or as a constant.
+
    * defined as an attribute or as a constant.
*  
+
    *
* @return whether the dog was able to run.
+
    * @return whether the dog was able to run.
*/
+
    */
public boolean run() {
+
    public boolean run() {
if (_energy < 50)
+
        if (_energy < 50)
return false;
+
            return false;
_energy -= 50;
+
        _energy -= 50;
return true;
+
        return true;
}
+
    }
  
/**
+
    /**
* Call "run" to account for spent energy.
+
    * Call "run" to account for spent energy.
*  
+
    *
* @param mouse
+
    * @param mouse
*            the mouse to be chased.
+
    *            the mouse to be chased.
* @return whether the dog was able to catch the mouse. If the mouse
+
    * @return whether the dog was able to catch the mouse. If the mouse
*        escapes, its energy increases.
+
    *        escapes, its energy increases.
*/
+
    */
public boolean caughtMouse(Mouse mouse) {
+
    public boolean caughtMouse(Mouse mouse) {
run();
+
        run();
mouse.run();
+
        mouse.run();
if (0 == (int) (25 * Math.random())) {
+
        if (0 == (int) (25 * Math.random())) {
return true;
+
            return true;
}
+
        }
mouse.escaped();
+
        mouse.escaped();
return false;
+
        return false;
}
+
    }
  
/**
+
    /**
* Eating is more or less like a vampire feeding...
+
    * Eating is more or less like a vampire feeding...
*  
+
    *
* @param mouse
+
    * @param mouse
*            the mouse to eat.
+
    *            the mouse to eat.
*/
+
    */
public void eatMouse(Mouse mouse) {
+
    public void eatMouse(Mouse mouse) {
if (caughtMouse(mouse))
+
        if (caughtMouse(mouse))
_energy += mouse.drain();
+
            _energy += mouse.drain();
}
+
    }
  
/**
+
    /**
* We assume that the dog is always able to attack the cat. The parameter to
+
    * 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.
+
    * ''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
+
    * Note that we are assuming that the degree of loss depends on the attacker
* (hence the value being defined in the dog class).
+
    * (hence the value being defined in the dog class).
*  
+
    *
* The energy values could be defined as attributes or as constants.
+
    * The energy values could be defined as attributes or as constants.
*  
+
    *
* @param cat
+
    * @param cat
*            the cat the dog attacks
+
    *            the cat the dog attacks
*/
+
    */
public void attackCat(Cat cat) {
+
    public void attackCat(Cat cat) {
_energy -= 100;
+
        _energy -= 100;
cat.attacked(25);
+
        cat.attacked(25);
}
+
    }
  
/**
+
    /**
* Energy is recovered when sleeping.
+
    * Energy is recovered when sleeping.
*/
+
    */
public void sleep() {
+
    public void sleep() {
_energy = BASE_ENERGY;
+
        _energy = BASE_ENERGY;
}
+
    }
  
/**
+
    /**
* @see java.lang.Object#equals(java.lang.Object)
+
    * @see java.lang.Object#equals(java.lang.Object)
*/
+
    */
@Override
+
    @Override
public boolean equals(Object o) {
+
    public boolean equals(Object o) {
if (o instanceof Dog) {
+
        if (o instanceof Dog) {
Dog dog = (Dog) o;
+
            Dog dog = (Dog) o;
return _name.equals(dog.getName()) && _energy == dog.getEnergy();
+
            return _name.equals(dog.getName()) && _energy == dog.getEnergy();
}
+
        }
return false;
+
        return false;
}
+
    }
  
/**
+
    /**
* @see java.lang.Object#toString()
+
    * @see java.lang.Object#toString()
*/
+
    */
@Override
+
    @Override
public String toString() {
+
    public String toString() {
return _name + " (dog) (" + _energy + ")";
+
        return _name + " (dog) (" + _energy + ")";
}
+
    }
 
}
 
}
</java5>
+
</source>
 +
}}
  
== Conceito de Gato: Cat ==
+
== Conceito de Gato ==
  
<java5>
+
{{CollapsedCode|Ficheiro '''Cat.java'''|
 +
<source lang="java">
 
public class Cat {
 
public class Cat {
  
/**
+
    /**
* We define the base energy as a constant, but it does not have to be this
+
    * 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
+
    * way. It could be defined differently for each dog (but this requirement
* does not exist in this case).
+
    * does not exist in this case).
*/
+
    */
private static final int BASE_ENERGY = 500;
+
    private static final int BASE_ENERGY = 500;
 +
 
 +
    /**
 +
    * The cat's name.
 +
    */
 +
    private String _name;
  
/**
+
    /**
* The cat's name.
+
    * The cat's current energy value.
*/
+
    */
private String _name;
+
    private int _energy = BASE_ENERGY;
  
/**
+
    /**
* The cat's current energy value.
+
    * Initialize a cat with a name. Default energy levels are used.
*/
+
    *
private int _energy = BASE_ENERGY;
+
    * @param name
 +
    */
 +
    public Cat(String name) {
 +
        _name = name;
 +
    }
  
/**
+
    /**
* @return cat's current energy level.
+
    * @return cat's current energy level.
*/
+
    */
private int getEnergy() {
+
    public int getEnergy() {
return _energy;
+
        return _energy;
}
+
    }
  
/**
+
    /**
* @return cat's name
+
    * @return cat's name
*/
+
    */
public String getName() {
+
    public String getName() {
return _name;
+
        return _name;
}
+
    }
  
/**
+
    /**
* Set the cat's name
+
    * Set the cat's name
*  
+
    *
* @param name
+
    * @param name
*            the cat's name
+
    *            the cat's name
*/
+
    */
public void setName(String name) {
+
    public void setName(String name) {
_name = name;
+
        _name = name;
}
+
    }
  
/**
+
    /**
* When a cat runs, the energy decreases by 25 units. This value could be
+
    * When a cat runs, the energy decreases by 25 units. This value could be
* defined as an attribute or as a constant.
+
    * defined as an attribute or as a constant.
*  
+
    *
* @return whether the cat was able to run.
+
    * @return whether the cat was able to run.
*/
+
    */
public boolean run() {
+
    public boolean run() {
if (_energy < 25)
+
        if (_energy < 25)
return false;
+
            return false;
_energy -= 25;
+
        _energy -= 25;
return true;
+
        return true;
}
+
    }
  
/**
+
    /**
* Call "run" to account for spent energy.
+
    * Call "run" to account for spent energy.
*  
+
    *
* @param mouse
+
    * @param mouse
*            the mouse to be caught.
+
    *            the mouse to be caught.
* @return whether the cat was able to catch the mouse. If the mouse
+
    * @return whether the cat was able to catch the mouse. If the mouse
*        escapes, its energy increases.
+
    *        escapes, its energy increases.
*/
+
    */
public boolean caughtMouse(Mouse mouse) {
+
    public boolean caughtMouse(Mouse mouse) {
run();
+
        run();
mouse.run();
+
        mouse.run();
if (0 == (int) (5 * Math.random())) {
+
        if (0 == (int) (5 * Math.random())) {
return true;
+
            return true;
}
+
        }
mouse.escaped();
+
        mouse.escaped();
return false;
+
        return false;
}
+
    }
  
/**
+
    /**
* Call "run" ("fly"??) to account for spent energy.
+
    * Call "run" ("fly"??) to account for spent energy.
*  
+
    *
* @param bird
+
    * @param bird
*            the bird to be caught.
+
    *            the bird to be caught.
* @return whether the cat was able to catch the bird. If the bird escapes,
+
    * @return whether the cat was able to catch the bird. If the bird escapes,
*        its energy increases.
+
    *        its energy increases.
*/
+
    */
public boolean caughtBird(Bird bird) {
+
    public boolean caughtBird(Bird bird) {
run();
+
        run();
bird.fly(); // run??
+
        bird.fly(); // run??
if (0 == (int) (10 * Math.random())) {
+
        if (0 == (int) (10 * Math.random())) {
return true;
+
            return true;
}
+
        }
bird.escaped();
+
        bird.escaped();
return false;
+
        return false;
}
+
    }
  
/**
+
    /**
* Eating is more or less like a vampire feeding...
+
    * Eating is more or less like a vampire feeding...
*  
+
    *
* @param mouse
+
    * @param mouse
*            the mouse to eat.
+
    *            the mouse to eat.
*/
+
    */
public void eatMouse(Mouse mouse) {
+
    public void eatMouse(Mouse mouse) {
if (caughtMouse(mouse))
+
        if (caughtMouse(mouse))
_energy += mouse.drain();
+
            _energy += mouse.drain();
}
+
    }
  
/**
+
    /**
* Eating is more or less like a vampire feeding...
+
    * Eating is more or less like a vampire feeding...
*  
+
    *
* @param bird
+
    * @param bird
*            the mouse to eat.
+
    *            the mouse to eat.
*/
+
    */
public void eatBird(Bird bird) {
+
    public void eatBird(Bird bird) {
if (caughtBird(bird))
+
        if (caughtBird(bird))
_energy += bird.drain();
+
            _energy += bird.drain();
}
+
    }
  
/**
+
    /**
* We should probably check for large decrease values. Nevertheless, in this
+
    * We should probably check for large decrease values. Nevertheless, in this
* case, for simplicity, we will let the energy go negative and, later on,
+
    * case, for simplicity, we will let the energy go negative and, later on,
* the cat can recover after a nap.
+
    * the cat can recover after a nap.
*  
+
    *
* @param energyDecrease
+
    * @param energyDecrease
*/
+
    */
public void attacked(int energyDecrease) {
+
    public void attacked(int energyDecrease) {
_energy -= energyDecrease;
+
        _energy -= energyDecrease;
}
+
    }
  
/**
+
    /**
* Energy is recovered when sleeping.
+
    * Energy is recovered when sleeping.
*/
+
    */
public void sleep() {
+
    public void sleep() {
_energy = BASE_ENERGY;
+
        _energy = BASE_ENERGY;
}
+
    }
  
/**
+
    /**
* @see java.lang.Object#equals(java.lang.Object)
+
    * @see java.lang.Object#equals(java.lang.Object)
*/
+
    */
@Override
+
    @Override
public boolean equals(Object o) {
+
    public boolean equals(Object o) {
if (o instanceof Cat) {
+
        if (o instanceof Cat) {
Cat cat = (Cat) o;
+
            Cat cat = (Cat) o;
return _name.equals(cat.getName()) && _energy == cat.getEnergy();
+
            return _name.equals(cat.getName()) && _energy == cat.getEnergy();
}
+
        }
return false;
+
        return false;
}
+
    }
  
/**
+
    /**
* @see java.lang.Object#toString()
+
    * @see java.lang.Object#toString()
*/
+
    */
@Override
+
    @Override
public String toString() {
+
    public String toString() {
return _name + " (cat) (" + _energy + ")";
+
        return _name + " (cat) (" + _energy + ")";
}
+
    }
 
}
 
}
</java5>
+
</source>
 +
}}
  
== Conceito de Rato: Mouse ==
+
== Conceito de Rato ==
  
<java5>
+
{{CollapsedCode|Ficheiro '''Mouse.java'''|
 +
<source lang="java">
 
public class Mouse {
 
public class Mouse {
  
/**
+
  /**
* We define the base energy as a constant, but it does not have to be this
+
  * 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
+
  * way. It could be defined differently for each dog (but this requirement
* does not exist in this case).
+
  * does not exist in this case).
*/
+
  */
private static final int BASE_ENERGY = 50;
+
  private static final int BASE_ENERGY = 50;
  
/**
+
  /**
* Tje mouse's current energy value.
+
  * The mouse's current energy value.
*/
+
  */
private int _energy = BASE_ENERGY;
+
  private int _energy = BASE_ENERGY;
  
/**
+
  /**
* @return mouse's current energy level.
+
  * @return mouse's current energy level.
*/
+
  */
private int getEnergy() {
+
  public int getEnergy() {
return _energy;
+
    return _energy;
}
+
  }
  
/**
+
  /**
* When a mouse runs, the energy decreases by 2 units. This value could be
+
  * When a mouse runs, the energy decreases by 2 units. This value could be
* defined as an attribute or as a constant.
+
  * defined as an attribute or as a constant.
*  
+
  *
* @return whether the mouse was able to run.
+
  * @return whether the mouse was able to run.
*/
+
  */
public boolean run() {
+
  public boolean run() {
if (_energy < 2)
+
    if (_energy < 2)
return false;
+
      return false;
_energy -= 2;
+
    _energy -= 2;
return true;
+
    return true;
}
+
  }
  
/**
+
  /**
* Energy goes up 5 points in a narrow escape.
+
  * Energy goes up 5 points in a narrow escape.
*/
+
  */
public void escaped() {
+
  public void escaped() {
_energy += 5;
+
    _energy += 5;
}
+
  }
  
/**
+
  /**
* @return the energy level in this mouse
+
  * @return the energy level in this mouse
*/
+
  */
public int drain() {
+
  public int drain() {
int energy = _energy;
+
    int energy = _energy;
_energy = 0;
+
    _energy = 0;
return energy;
+
    return energy;
}
+
  }
  
/**
+
  /**
* Energy is recovered when sleeping.
+
  * Energy is recovered when sleeping.
*/
+
  */
public void sleep() {
+
  public void sleep() {
_energy = BASE_ENERGY;
+
    _energy = BASE_ENERGY;
}
+
  }
  
/**
+
  /**
* @see java.lang.Object#equals(java.lang.Object)
+
  * @see java.lang.Object#equals(java.lang.Object)
*/
+
  */
@Override
+
  @Override
public boolean equals(Object o) {
+
  public boolean equals(Object o) {
if (o instanceof Mouse) {
+
    if (o instanceof Mouse) {
Mouse mouse = (Mouse) o;
+
      Mouse mouse = (Mouse) o;
return _energy == mouse.getEnergy();
+
      return _energy == mouse.getEnergy();
}
+
    }
return false;
+
    return false;
}
+
  }
  
/**
+
  /**
* @see java.lang.Object#toString()
+
  * @see java.lang.Object#toString()
*/
+
  */
@Override
+
  @Override
public String toString() {
+
  public String toString() {
return "mouse (" + _energy + ")";
+
    return "mouse (" + _energy + ")";
}
+
  }
 
}
 
}
</java5>
+
</source>
 +
}}
  
== Conceito de Pássaro: Bird ==
+
== Conceito de Pássaro ==
  
<java5>
+
{{CollapsedCode|Ficheiro '''Bird.java'''|
 +
<source lang="java">
 
public class Bird {
 
public class Bird {
  
/**
+
  /**
* We define the base energy as a constant, but it does not have to be this
+
  * 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
+
  * way. It could be defined differently for each dog (but this requirement
* does not exist in this case).
+
  * does not exist in this case).
*/
+
  */
private static final int BASE_ENERGY = 20;
+
  private static final int BASE_ENERGY = 20;
  
/**
+
  /**
* Bird's current energy value.
+
  * The bird's current energy value.
*/
+
  */
private int _energy = BASE_ENERGY;
+
  private int _energy = BASE_ENERGY;
  
/**
+
  /**
* @return mouse's current energy level.
+
  * @return mouse's current energy level.
*/
+
  */
private int getEnergy() {
+
  public int getEnergy() {
return _energy;
+
    return _energy;
}
+
  }
  
/**
+
  /**
* When a bird runs, the energy decreases by 5 units. This value could be
+
  * When a bird runs, the energy decreases by 5 units. This value could be
* defined as an attribute or as a constant.
+
  * defined as an attribute or as a constant.
*  
+
  *
* @return whether the bird was able to run.
+
  * @return whether the bird was able to run.
*/
+
  */
public boolean run() {
+
  public boolean run() {
if (_energy < 5)
+
    if (_energy < 5)
return false;
+
      return false;
_energy -= 5;
+
    _energy -= 5;
return true;
+
    return true;
}
+
  }
  
/**
+
  /**
* When a bird flies, the energy decreases by 2 units. This value could be
+
  * When a bird flies, the energy decreases by 2 units. This value could be
* defined as an attribute or as a constant.
+
  * defined as an attribute or as a constant.
*  
+
  *
* @return whether the bird was able to fly.
+
  * @return whether the bird was able to fly.
*/
+
  */
public boolean fly() {
+
  public boolean fly() {
if (_energy < 2)
+
    if (_energy < 2)
return false;
+
      return false;
_energy -= 2;
+
    _energy -= 2;
return true;
+
    return true;
}
+
  }
  
/**
+
  /**
* Energy goes up 5 points in a narrow escape.
+
  * Energy goes up 5 points in a narrow escape.
*/
+
  */
public void escaped() {
+
  public void escaped() {
_energy += 5;
+
    _energy += 5;
}
+
  }
  
/**
+
  /**
* @return the energy level in this mouse
+
  * @return the energy level in this mouse
*/
+
  */
public int drain() {
+
  public int drain() {
int energy = _energy;
+
    int energy = _energy;
_energy = 0;
+
    _energy = 0;
return energy;
+
    return energy;
}
+
  }
  
/**
+
  /**
* Energy is recovered when sleeping.
+
  * Energy is recovered when sleeping.
*/
+
  */
public void sleep() {
+
  public void sleep() {
_energy = BASE_ENERGY;
+
    _energy = BASE_ENERGY;
}
+
  }
  
/**
+
  /**
* @see java.lang.Object#equals(java.lang.Object)
+
  * @see java.lang.Object#equals(java.lang.Object)
*/
+
  */
@Override
+
  @Override
public boolean equals(Object o) {
+
  public boolean equals(Object o) {
if (o instanceof Bird) {
+
    if (o instanceof Bird) {
Bird bird = (Bird) o;
+
      Bird bird = (Bird) o;
return _energy == bird.getEnergy();
+
      return _energy == bird.getEnergy();
}
+
    }
return false;
+
    return false;
}
+
  }
  
/**
+
  /**
* @see java.lang.Object#toString()
+
  * @see java.lang.Object#toString()
*/
+
  */
@Override
+
  @Override
public String toString() {
+
  public String toString() {
return "bird (" + _energy + ")";
+
    return "bird (" + _energy + ")";
}
+
  }
 
}
 
}
</java5>
+
</source>
 +
}}
  
 
== Programa Principal ==
 
== Programa Principal ==
  
<java5>
+
Este programa implementa o cenário descrito no enunciado do problema.
 +
 
 +
{{CollapsedCode|Ficheiro '''Application.java'''|
 +
<source lang="java">
 
public class Application {
 
public class Application {
  
/**
+
    /**
* The application scenario.
+
    * @param args
*
+
    */
* @param args
+
    public static void main(String[] args) {
*/
+
        Dog d1 = new Dog("Piloto");
public static void main(String[] args) {
+
        Dog d2 = new Dog("Átila");
Dog d1 = new Dog();
+
 
d1.setName("Piloto");   // could be passed to the constructor
+
        Cat c1 = new Cat("Tareco");
Dog d2 = new Dog();
+
        Cat c2 = new Cat("Pantufa");
d2.setName("Átila");   // could be passed to the constructor
+
        Cat c3 = new Cat("Kitty");
+
       
Cat c1 = new Cat();
+
        Bird[] birds = new Bird[20];
c1.setName("Tareco");   // could be passed to the constructor
+
        for (int ix = 0; ix < birds.length; ix++)
Cat c2 = new Cat();
+
            birds[ix] = new Bird();
c2.setName("Pantufa"); // could be passed to the constructor
+
 
Cat c3 = new Cat();
+
        Mouse[] mice = new Mouse[50];
c3.setName("Kitty");   // could be passed to the constructor
+
        for (int ix = 0; ix < mice.length; ix++)
+
            mice[ix] = new Mouse();
Bird[] birds = new Bird[20];
+
 
for (int ix = 0; ix < birds.length; ix++)
+
        // snapshot: present everything
birds[ix] = new Bird();
+
        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.
  
Mouse[] mice = new Mouse[50];
+
        for (int ix = 0; ix < birds.length; ix++)
for (int ix = 0; ix < mice.length; ix++)
+
            birds[ix].fly();
mice[ix] = new Mouse();
 
  
    // snapshot: present everything
+
        d1.run();
System.out.println("BEFORE");
+
        d2.attackCat(c1);
System.out.println(d1.toString());
+
        c2.eatBird(birds[2]);
System.out.println(d2.toString());
+
        c3.eatBird(birds[9]);
System.out.println(c1.toString());
+
        c3.eatMouse(mice[0]);
System.out.println(c2.toString());
+
        d2.eatMouse(mice[1]);
System.out.println(c3.toString());
+
        mice[3].run();
 
for (int ix = 0; ix < birds.length; ix++)
 
System.out.println(birds[ix]);
 
  
for (int ix = 0; ix < mice.length; ix++)
+
        // snapshot: present everything
System.out.println(mice[ix]);
+
        System.out.println("AFTER");
+
        System.out.println(d1);
// run, chase, eat, sleep, etc.
+
        System.out.println(d2);
+
        System.out.println(c1);
for (int ix = 0; ix < birds.length; ix++)
+
        System.out.println(c2);
birds[ix].fly();
+
        System.out.println(c3);
 
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
+
        for (int ix = 0; ix < birds.length; ix++)
System.out.println("AFTER");
+
            System.out.println(birds[ix]);
System.out.println(d1.toString());
 
System.out.println(d2.toString());
 
System.out.println(c1.toString());
 
System.out.println(c2.toString());
 
System.out.println(c3.toString());
 
 
for (int ix = 0; ix < birds.length; ix++)
 
System.out.println(birds[ix]);
 
  
for (int ix = 0; ix < mice.length; ix++)
+
        for (int ix = 0; ix < mice.length; ix++)
System.out.println(mice[ix]);
+
            System.out.println(mice[ix]);
 
}
 
  
 +
    }
 
}
 
}
</java5>
+
</source>
 +
}}
 +
 
 +
= 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 ==
  
== Code ==
+
O programa começa a sua execução na função '''main''' da classe escolhida para iniciar a aplicação (neste caso, '''Application'''):
  
* Java archive with solution: [[media:energy.jar]]
+
  java Application
  
[[category:Teaching]]
 
 
[[category:PO]]
 
[[category:PO]]
 +
[[category:PO Exemplos]]
 +
[[category:Java]]
 +
[[category:Ensino]]

Latest revision as of 01:30, 15 September 2023

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.

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 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 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).

Existem opções de desenho sub-óptimas. Consegue detectá-las?

BUG: o método "escaped" deveria ter como tipo de retorno "void" e não "boolean".

Diagrama de classes

PO-dog-cat-mouse-bird-energy-noinheritance.png

Conceito de Cão

Ficheiro Dog.java
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.
     */
    public 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
    public String toString() {
        return _name + " (dog) (" + _energy + ")";
    }
}

Conceito de Gato

Ficheiro Cat.java
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.
     */
    public 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
    public String toString() {
        return _name + " (cat) (" + _energy + ")";
    }
}

Conceito de Rato

Ficheiro Mouse.java
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 + ")";
  }
}

Conceito de Pássaro

Ficheiro Bird.java
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 + ")";
  }
}

Programa Principal

Este programa implementa o cenário descrito no enunciado do problema.

Ficheiro Application.java
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]);

    }
}

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