Difference between revisions of "Herança e Composição/Exercício 03: Energia"

From Wiki**3

< Herança e Composição
(Conceito de Rato)
 
(One intermediate revision by the same user not shown)
Line 45: Line 45:
  
 
{{CollapsedCode|Ficheiro '''Animal.java'''|
 
{{CollapsedCode|Ficheiro '''Animal.java'''|
<java5>
+
<source lang="java">
 
public class Animal {
 
public class Animal {
  
/** The animal's base energy value. */
+
    /** The animal's base energy value. */
private final int _baseEnergy;
+
    private final int _baseEnergy;
  
/** The dog's current energy value. */
+
    /** The dog's current energy value. */
private int _energy;
+
    private int _energy;
  
/** The animal's energy spent when running. */
+
    /** The animal's energy spent when running. */
private final int _runEnergy;
+
    private final int _runEnergy;
  
/**
+
    /**
* Note that baseEnergy and runEnergy are final and thus, constant after
+
    * Note that baseEnergy and runEnergy are final and thus, constant after
* initialization.
+
    * initialization.
*  
+
    *
* @param baseEnergy
+
    * @param baseEnergy
* @param energy
+
    * @param energy
* @param runEnergy
+
    * @param runEnergy
*/
+
    */
Animal(int baseEnergy, int energy, int runEnergy) {
+
    Animal(int baseEnergy, int energy, int runEnergy) {
_energy = Math.min(energy, baseEnergy);
+
        _energy = Math.min(energy, baseEnergy);
_baseEnergy = baseEnergy;
+
        _baseEnergy = baseEnergy;
_runEnergy = Math.min(runEnergy, baseEnergy);
+
        _runEnergy = Math.min(runEnergy, baseEnergy);
}
+
    }
  
/**
+
    /**
* @param baseEnergy
+
    * @param baseEnergy
* @param runEnergy
+
    * @param runEnergy
*/
+
    */
Animal(int baseEnergy, int runEnergy) {
+
    Animal(int baseEnergy, int runEnergy) {
 
                 this(baseEnergy, baseEnergy, runEnergy);
 
                 this(baseEnergy, baseEnergy, runEnergy);
}
+
    }
  
/**
+
    /**
* @return the animal's base energy level.
+
    * @return the animal's base energy level.
*/
+
    */
public int getBaseEnergy() {
+
    public int getBaseEnergy() {
return _energy;
+
        return _baseEnergy;
}
+
    }
  
/**
+
    /**
* @return the animal's current energy level.
+
    * @return the animal's current energy level.
*/
+
    */
public int getEnergy() {
+
    public int getEnergy() {
return _energy;
+
        return _energy;
}
+
    }
  
/**
+
    /**
* @param energy
+
    * @param energy
*            the animal's new energy level.
+
    *            the animal's new energy level.
*/
+
    */
public void setEnergy(int energy) {
+
    public void setEnergy(int energy) {
_energy = energy;
+
        _energy = energy;
}
+
    }
  
/**
+
    /**
* @return the animal's energy spent when running
+
    * @return the animal's energy spent when running
*/
+
    */
public int getRunEnergy() {
+
    public int getRunEnergy() {
return _runEnergy;
+
        return _runEnergy;
}
+
    }
  
/**
+
    /**
* @param delta
+
    * @param delta
*/
+
    */
void increaseEnergy(int delta) {
+
    void increaseEnergy(int delta) {
_energy += delta;
+
        _energy += delta;
}
+
    }
  
/**
+
    /**
* When an animal runs, the energy decreases.
+
    * When an animal runs, the energy decreases.
*  
+
    *
* @return whether the dog was able to run.
+
    * @return whether the dog was able to run.
*/
+
    */
public boolean run() {
+
    public boolean run() {
if (_energy < _runEnergy)
+
        if (_energy < _runEnergy)
return false;
+
            return false;
_energy -= _runEnergy;
+
        _energy -= _runEnergy;
return true;
+
        return true;
}
+
    }
  
/**
+
    /**
* Energy is recovered when sleeping.
+
    * Energy is recovered when sleeping.
*/
+
    */
public void sleep() {
+
    public void sleep() {
_energy = _baseEnergy;
+
        _energy = _baseEnergy;
}
+
    }
  
/**
+
    /**
* @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 Animal) {
+
        if (o instanceof Animal) {
Animal animal = (Animal) o;
+
            Animal animal = (Animal) o;
return _baseEnergy == animal.getBaseEnergy() && _energy == animal.getEnergy()
+
            return _baseEnergy == animal.getBaseEnergy() && _energy == animal.getEnergy()
&& _runEnergy == animal.getRunEnergy();
+
                    && _runEnergy == animal.getRunEnergy();
}
+
        }
return false;
+
        return false;
}
+
    }
  
/**
+
    /**
* @see java.lang.Object#toString()
+
    * @see java.lang.Object#toString()
*/
+
    */
@Override
+
    @Override
public String toString() {
+
    public String toString() {
return "base energy: " + _baseEnergy + ", energy left: " + _energy + ", spent running: "
+
        return "base energy: " + _baseEnergy + ", energy left: " + _energy + ", spent running: "
+ _runEnergy;
+
                + _runEnergy;
}
+
    }
 
}
 
}
</java5>
+
</source>
 
}}
 
}}
  
Line 164: Line 164:
  
 
{{CollapsedCode|Ficheiro '''NamedAnimal.java'''|
 
{{CollapsedCode|Ficheiro '''NamedAnimal.java'''|
<java5>
+
<source lang="java">
 
public class NamedAnimal extends Animal {
 
public class NamedAnimal extends Animal {
  
/**
+
    /**
* The animal's name.
+
    * The animal's name.
*/
+
    */
private String _name;
+
    private String _name;
  
/**
+
    /**
* Catch rate: success in catching mice.
+
    * Catch rate: success in catching mice.
*/
+
    */
private int _catchRate;
+
    private int _catchRate;
+
   
/**
+
    /**
* Note that baseEnergy and runEnergy are final and thus, constant after
+
    * Note that baseEnergy and runEnergy are final and thus, constant after
* initialization.
+
    * initialization.
*  
+
    *
* @param name
+
    * @param name
* @param catchRate  
+
    * @param catchRate
* @param baseEnergy
+
    * @param baseEnergy
* @param energy
+
    * @param energy
* @param runEnergy
+
    * @param runEnergy
*/
+
    */
NamedAnimal(String name, int catchRate, int baseEnergy, int energy, int runEnergy) {
+
    NamedAnimal(String name, int catchRate, int baseEnergy, int energy, int runEnergy) {
super(baseEnergy, energy, runEnergy);
+
        super(baseEnergy, energy, runEnergy);
_name = name;
+
        _name = name;
_catchRate = catchRate;
+
        _catchRate = catchRate;
}
+
    }
  
/**
+
    /**
* @param name
+
    * @param name
* @param catchRate  
+
    * @param catchRate
* @param baseEnergy
+
    * @param baseEnergy
* @param runEnergy
+
    * @param runEnergy
*/
+
    */
NamedAnimal(String name, int catchRate, int baseEnergy, int runEnergy) {
+
    NamedAnimal(String name, int catchRate, int baseEnergy, int runEnergy) {
super(baseEnergy, runEnergy);
+
        super(baseEnergy, runEnergy);
_name = name;
+
        _name = name;
_catchRate = catchRate;
+
        _catchRate = catchRate;
}
+
    }
  
/**
+
    /**
* @return the animal's name.
+
    * @return the animal's name.
*/
+
    */
public String getName() {
+
    public String getName() {
return _name;
+
        return _name;
}
+
    }
  
/**
+
    /**
* Set the animal's name
+
    * Set the animal's name
*  
+
    *
* @param name
+
    * @param name
*            the animal's name
+
    *            the animal's name
*/
+
    */
public void setName(String name) {
+
    public void setName(String name) {
_name = name;
+
        _name = name;
}
+
    }
  
/**
+
    /**
* This is not really a good place for this method, but since only named
+
    * This is not really a good place for this method, but since only named
* animals catch mice, we will leave it here for the time being.
+
    * animals catch mice, we will leave it here for the time being.
*  
+
    *
* 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) (_catchRate * Math.random())) {
+
        if (0 == (int) (_catchRate * Math.random())) {
return true;
+
            return true;
}
+
        }
mouse.escaped();
+
        mouse.escaped();
return false;
+
        return false;
}
+
    }
  
/**
+
    /**
* This is not really a good place for this method, but since only named
+
    * This is not really a good place for this method, but since only named
* animals eat mice, we will leave it here for the time being.
+
    * animals eat mice, we will leave it here for the time being.
*  
+
    *
* 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))
increaseEnergy(mouse.drain());
+
            increaseEnergy(mouse.drain());
}
+
    }
  
/**
+
    /**
* @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 NamedAnimal) {
+
        if (o instanceof NamedAnimal) {
NamedAnimal animal = (NamedAnimal) o;
+
            NamedAnimal animal = (NamedAnimal) o;
return super.equals(o) && _name.equals(animal.getName());
+
            return super.equals(o) && _name.equals(animal.getName());
}
+
        }
return false;
+
        return false;
}
+
    }
  
/**
+
    /**
* @see java.lang.Object#toString()
+
    * @see java.lang.Object#toString()
*/
+
    */
@Override
+
    @Override
public String toString() {
+
    public String toString() {
return _name + ", " + super.toString();
+
        return _name + ", " + super.toString();
}
+
    }
 
}
 
}
</java5>
+
</source>
 
}}
 
}}
  
Line 287: Line 287:
  
 
{{CollapsedCode|Ficheiro '''Dog.java'''|
 
{{CollapsedCode|Ficheiro '''Dog.java'''|
<java5>
+
<source lang="java">
 
public class Dog extends NamedAnimal {
 
public class Dog extends NamedAnimal {
  
/**
+
    /**
* Base energy level: 500. Run spending: 25.
+
    * Base energy level: 500. Run spending: 25.
*  
+
    *
* @param name
+
    * @param name
*/
+
    */
Dog(String name) {
+
    Dog(String name) {
super(name, 25, 1000, 50);
+
        super(name, 25, 1000, 50);
}
+
    }
+
   
/**
+
    /**
* 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) {
increaseEnergy(-100);
+
        increaseEnergy(-100);
cat.attacked(25);
+
        cat.attacked(25);
}
+
    }
  
/**
+
    /**
* @see java.lang.Object#toString()
+
    * @see java.lang.Object#toString()
*/
+
    */
@Override
+
    @Override
public String toString() {
+
    public String toString() {
return "Dog: " + super.toString();
+
        return "Dog: " + super.toString();
}
+
    }
  
/**
+
    /**
* @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)
return super.equals(o);
+
            return super.equals(o);
return false;
+
        return false;
}
+
    }
 
   
 
   
 
}
 
}
</java5>
+
</source>
 
}}
 
}}
  
Line 343: Line 343:
  
 
{{CollapsedCode|Ficheiro '''Cat.java'''|
 
{{CollapsedCode|Ficheiro '''Cat.java'''|
<java5>
+
<source lang="java">
 
public class Cat extends NamedAnimal {
 
public class Cat extends NamedAnimal {
  
/**
+
    /**
* Base energy level: 500. Run spending: 25.
+
    * Base energy level: 500. Run spending: 25.
*  
+
    *
* @param name
+
    * @param name
*/
+
    */
Cat(String name) {
+
    Cat(String name) {
super(name, 5, 500, 25);
+
        super(name, 5, 500, 25);
}
+
    }
  
/**
+
    /**
* 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 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))
increaseEnergy(bird.drain());
+
            increaseEnergy(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) {
increaseEnergy(-energyDecrease);
+
        increaseEnergy(-energyDecrease);
}
+
    }
  
/**
+
    /**
* @see java.lang.Object#toString()
+
    * @see java.lang.Object#toString()
*/
+
    */
@Override
+
    @Override
public String toString() {
+
    public String toString() {
return "Cat: " + super.toString();
+
        return "Cat: " + super.toString();
}
+
    }
  
/**
+
    /**
* @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)
return super.equals(o);
+
            return super.equals(o);
return false;
+
        return false;
}
+
    }
 
   
 
   
 
}
 
}
</java5>
+
</source>
 
}}
 
}}
  
Line 424: Line 424:
  
 
{{CollapsedCode|Ficheiro '''Mouse.java'''|
 
{{CollapsedCode|Ficheiro '''Mouse.java'''|
<java5>
+
<source lang="java">
 
public class Mouse extends Animal {
 
public class Mouse extends Animal {
  
/**
+
    /**
* Base energy level: 50. Run spending: 2.
+
    * Base energy level: 50. Run spending: 2.
*/
+
    */
Mouse() {
+
    Mouse() {
super(50, 2);
+
        super(50, 2);
}
+
    }
+
   
/**
+
    /**
* Energy goes up 5 points in a narrow escape.
+
    * Energy goes up 5 points in a narrow escape.
*/
+
    */
public void escaped() {
+
    public void escaped() {
increaseEnergy(5);
+
        increaseEnergy(5);
}
+
    }
  
/**
+
    /**
* @return the energy level in this mouse
+
    * @return the energy level in this mouse
*/
+
    */
public int drain() {
+
    public int drain() {
int energy = getEnergy();
+
        int energy = getEnergy();
setEnergy(0);
+
        setEnergy(0);
return energy;
+
        return energy;
}
+
    }
  
/**
+
    /**
* @see java.lang.Object#toString()
+
    * @see java.lang.Object#toString()
*/
+
    */
@Override
+
    @Override
public String toString() {
+
    public String toString() {
return "Mouse: " + super.toString();
+
        return "Mouse: " + super.toString();
}
+
    }
  
/**
+
    /**
* @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)
return super.equals(o);
+
            return super.equals(o);
return false;
+
        return false;
}
+
    }
 
   
 
   
 
}
 
}
</java5>
+
</source>
 
}}
 
}}
  
Line 479: Line 479:
  
 
{{CollapsedCode|Ficheiro '''Bird.java'''|
 
{{CollapsedCode|Ficheiro '''Bird.java'''|
<java5>
+
<source lang="java">
 
public class Bird extends Animal {
 
public class Bird extends Animal {
  
/**
+
    /**
* Base energy level: 20. Run spending: 5.
+
    * Base energy level: 20. Run spending: 5.
*/
+
    */
Bird() {
+
    Bird() {
super(20, 5);
+
        super(20, 5);
}
+
    }
+
   
/**
+
    /**
* 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 (getEnergy() < 2)
+
        if (getEnergy() < 2)
return false;
+
            return false;
increaseEnergy(-2);
+
        increaseEnergy(-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() {
increaseEnergy(5);
+
        increaseEnergy(5);
}
+
    }
  
/**
+
    /**
* @return the energy level in this bird
+
    * @return the energy level in this bird
*/
+
    */
public int drain() {
+
    public int drain() {
int energy = getEnergy();
+
        int energy = getEnergy();
setEnergy(0);
+
        setEnergy(0);
return energy;
+
        return energy;
}
+
    }
  
/**
+
    /**
* @see java.lang.Object#toString()
+
    * @see java.lang.Object#toString()
*/
+
    */
@Override
+
    @Override
public String toString() {
+
    public String toString() {
return "Bird: " + super.toString();
+
        return "Bird: " + super.toString();
}
+
    }
  
/**
+
    /**
* @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)
return super.equals(o);
+
            return super.equals(o);
return false;
+
        return false;
}
+
    }
 
   
 
   
 
}
 
}
</java5>
+
</source>
 
}}
 
}}
  
Line 545: Line 545:
  
 
{{CollapsedCode|Ficheiro '''Application.java'''|
 
{{CollapsedCode|Ficheiro '''Application.java'''|
<java5>
+
<source lang="java">
 
public class Application {
 
public class Application {
  
/**
+
    /**
* The application scenario.
+
    * The application scenario.
*  
+
    *
* @param args
+
    * @param args
*/
+
    */
public static void main(String[] args) {
+
    public static void main(String[] args) {
Dog d1 = new Dog("Piloto");
+
        Dog d1 = new Dog("Piloto");
Dog d2 = new Dog("Átila");
+
        Dog d2 = new Dog("Átila");
+
       
Cat c1 = new Cat("Tareco");
+
        Cat c1 = new Cat("Tareco");
Cat c2 = new Cat("Pantufa");
+
        Cat c2 = new Cat("Pantufa");
Cat c3 = new Cat("Kitty");
+
        Cat c3 = new Cat("Kitty");
+
       
Bird[] birds = new Bird[20];
+
        Bird[] birds = new Bird[20];
for (int ix = 0; ix < birds.length; ix++)
+
        for (int ix = 0; ix < birds.length; ix++)
birds[ix] = new Bird();
+
            birds[ix] = new Bird();
  
Mouse[] mice = new Mouse[50];
+
        Mouse[] mice = new Mouse[50];
for (int ix = 0; ix < mice.length; ix++)
+
        for (int ix = 0; ix < mice.length; ix++)
mice[ix] = new Mouse();
+
            mice[ix] = new Mouse();
  
    // snapshot: present everything
+
        // snapshot: present everything
System.out.println("BEFORE");
+
        System.out.println("BEFORE");
System.out.println(d1);
+
        System.out.println(d1);
System.out.println(d2);
+
        System.out.println(d2);
System.out.println(c1);
+
        System.out.println(c1);
System.out.println(c2);
+
        System.out.println(c2);
System.out.println(c3);
+
        System.out.println(c3);
+
       
for (int ix = 0; ix < birds.length; ix++)
+
        for (int ix = 0; ix < birds.length; ix++)
System.out.println(birds[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]);
+
       
// run, chase, eat, sleep, etc.
+
        // run, chase, eat, sleep, etc.
+
       
for (int ix = 0; ix < birds.length; ix++)
+
        for (int ix = 0; ix < birds.length; ix++)
birds[ix].fly();
+
            birds[ix].fly();
+
       
d1.run();
+
        d1.run();
d2.attackCat(c1);
+
        d2.attackCat(c1);
c2.eatBird(birds[2]);
+
        c2.eatBird(birds[2]);
c3.eatBird(birds[9]);
+
        c3.eatBird(birds[9]);
c3.eatMouse(mice[0]);
+
        c3.eatMouse(mice[0]);
d2.eatMouse(mice[1]);
+
        d2.eatMouse(mice[1]);
mice[3].run();
+
        mice[3].run();
  
    // snapshot: present everything
+
        // snapshot: present everything
System.out.println("AFTER");
+
        System.out.println("AFTER");
System.out.println(d1);
+
        System.out.println(d1);
System.out.println(d2);
+
        System.out.println(d2);
System.out.println(c1);
+
        System.out.println(c1);
System.out.println(c2);
+
        System.out.println(c2);
System.out.println(c3);
+
        System.out.println(c3);
+
       
for (int ix = 0; ix < birds.length; ix++)
+
        for (int ix = 0; ix < birds.length; ix++)
System.out.println(birds[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>
 
}}
 
}}
  

Latest revision as of 21:18, 8 November 2018

Considere o seguinte problema (baseado no domínio do exercício 02). Considere ainda as possíveis abstracções de comportamentos e propriedades comuns aos vários conceitos. Defina os conceitos do problema com base nas suas abstracções.

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

Discuta as opções da abstracção, em particular, no que respeita a aspectos menos flexíveis relativamente a possíveis alterações do modelo (constantes, propriedades, comportamentos comuns, etc.). Ainda neste sentido, compare a nova solução com a solução da anterior. Chegou à conclusão que a sua nova solução ainda apresenta dificuldades face à manutenção do código? Neste caso, quais são os aspectos problemáticos?

Solução

A solução apresentada procura uma abstracção adequada das propriedades e comportamentos intrínsecos dos conceitos em causa. Alguns aspectos, relativos à abstracção funcional não são ainda considerados.

UML: Diagrama de Classes

Diagrama de classes

PO-dog-cat-mouse-bird-energy-with-inheritance.png

Conceito de Animal

Conceito que gere a energia e o consumo quando se corre, i.e., todos os animais têm energia (boa abstracção) e todos correm (não tão boa, mas neste caso é aceitável, embora haja melhores soluções utilizando técnicas mais avançadas de modelação).

Ficheiro Animal.java
public class Animal {

    /** The animal's base energy value. */
    private final int _baseEnergy;

    /** The dog's current energy value. */
    private int _energy;

    /** The animal's energy spent when running. */
    private final int _runEnergy;

    /**
     * Note that baseEnergy and runEnergy are final and thus, constant after
     * initialization.
     *
     * @param baseEnergy
     * @param energy
     * @param runEnergy
     */
    Animal(int baseEnergy, int energy, int runEnergy) {
        _energy = Math.min(energy, baseEnergy);
        _baseEnergy = baseEnergy;
        _runEnergy = Math.min(runEnergy, baseEnergy);
    }

    /**
     * @param baseEnergy
     * @param runEnergy
     */
    Animal(int baseEnergy, int runEnergy) {
                this(baseEnergy, baseEnergy, runEnergy);
    }

    /**
     * @return the animal's base energy level.
     */
    public int getBaseEnergy() {
        return _baseEnergy;
    }

    /**
     * @return the animal's current energy level.
     */
    public int getEnergy() {
        return _energy;
    }

    /**
     * @param energy
     *            the animal's new energy level.
     */
    public void setEnergy(int energy) {
        _energy = energy;
    }

    /**
     * @return the animal's energy spent when running
     */
    public int getRunEnergy() {
        return _runEnergy;
    }

    /**
     * @param delta
     */
    void increaseEnergy(int delta) {
        _energy += delta;
    }

    /**
     * When an animal runs, the energy decreases.
     *
     * @return whether the dog was able to run.
     */
    public boolean run() {
        if (_energy < _runEnergy)
            return false;
        _energy -= _runEnergy;
        return true;
    }

    /**
     * Energy is recovered when sleeping.
     */
    public void sleep() {
        _energy = _baseEnergy;
    }

    /**
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object o) {
        if (o instanceof Animal) {
            Animal animal = (Animal) o;
            return _baseEnergy == animal.getBaseEnergy() && _energy == animal.getEnergy()
                    && _runEnergy == animal.getRunEnergy();
        }
        return false;
    }

    /**
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "base energy: " + _baseEnergy + ", energy left: " + _energy + ", spent running: "
                + _runEnergy;
    }
}

Conceito de Animal com Nome

Tal como no caso anterior, utilizando técnicas de modelação mais avançadas, este conceito poderia não ser sobrecarregado com alguns aspectos, presentes apenas por serem comuns às subclasses (nomeadamente, perseguir e comer ratos).

Ficheiro NamedAnimal.java
public class NamedAnimal extends Animal {

    /**
     * The animal's name.
     */
    private String _name;

    /**
     * Catch rate: success in catching mice.
     */
    private int _catchRate;
    
    /**
     * Note that baseEnergy and runEnergy are final and thus, constant after
     * initialization.
     *
     * @param name
     * @param catchRate
     * @param baseEnergy
     * @param energy
     * @param runEnergy
     */
    NamedAnimal(String name, int catchRate, int baseEnergy, int energy, int runEnergy) {
        super(baseEnergy, energy, runEnergy);
        _name = name;
        _catchRate = catchRate;
    }

    /**
     * @param name
     * @param catchRate
     * @param baseEnergy
     * @param runEnergy
     */
    NamedAnimal(String name, int catchRate, int baseEnergy, int runEnergy) {
        super(baseEnergy, runEnergy);
        _name = name;
        _catchRate = catchRate;
    }

    /**
     * @return the animal's name.
     */
    public String getName() {
        return _name;
    }

    /**
     * Set the animal's name
     *
     * @param name
     *            the animal's name
     */
    public void setName(String name) {
        _name = name;
    }

    /**
     * This is not really a good place for this method, but since only named
     * animals catch mice, we will leave it here for the time being.
     *
     * 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) (_catchRate * Math.random())) {
            return true;
        }
        mouse.escaped();
        return false;
    }

    /**
     * This is not really a good place for this method, but since only named
     * animals eat mice, we will leave it here for the time being.
     *
     * Eating is more or less like a vampire feeding...
     *
     * @param mouse
     *            the mouse to eat.
     */
    public void eatMouse(Mouse mouse) {
        if (caughtMouse(mouse))
            increaseEnergy(mouse.drain());
    }

    /**
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object o) {
        if (o instanceof NamedAnimal) {
            NamedAnimal animal = (NamedAnimal) o;
            return super.equals(o) && _name.equals(animal.getName());
        }
        return false;
    }

    /**
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return _name + ", " + super.toString();
    }
}

Conceito de Cão

Um cão é um animal com nome, com uma dada energia inicial e que consome uma determinada energia quando corre (ver definição destes parâmetros na chamada ao construtor).

Comparar a reduzida dimensão da classe, quando comparada com a versão sem herança.

Ficheiro Dog.java
public class Dog extends NamedAnimal {

    /**
     * Base energy level: 500. Run spending: 25.
     *
     * @param name
     */
    Dog(String name) {
        super(name, 25, 1000, 50);
    }
    
    /**
     * 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) {
        increaseEnergy(-100);
        cat.attacked(25);
    }

    /**
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "Dog: " + super.toString();
    }

    /**
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object o) {
        if (o instanceof Dog)
            return super.equals(o);
        return false;
    }
 
}

Conceito de Gato

Um gato é um animal com nome, com uma dada energia inicial e que consome uma determinada energia quando corre (ver definição destes parâmetros na chamada ao construtor).

Comparar a reduzida dimensão da classe, quando comparada com a versão sem herança.

Ficheiro Cat.java
public class Cat extends NamedAnimal {

    /**
     * Base energy level: 500. Run spending: 25.
     *
     * @param name
     */
    Cat(String name) {
        super(name, 5, 500, 25);
    }

    /**
     * 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 bird
     *            the mouse to eat.
     */
    public void eatBird(Bird bird) {
        if (caughtBird(bird))
            increaseEnergy(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) {
        increaseEnergy(-energyDecrease);
    }

    /**
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "Cat: " + super.toString();
    }

    /**
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object o) {
        if (o instanceof Cat)
            return super.equals(o);
        return false;
    }
 
}

Conceito de Rato

O conceito de rato poderia ser melhor definido, mas, nesta fase, utiliza-se um grau de abstracção menos conveniente, evitando definir conceitos apenas para evitar repetição de código (uma decisão que, na ausência de outras técnicas, poderia ter sido tomada na outra direcção -- ver, como exemplo, a classe NamedAnimal, que agrega alguma funcionalidade que não lhe pertence intrinsecamente).

Comparar a implementação com a versão sem herança e considerar outras possibilidades de abstracção.

Ficheiro Mouse.java
public class Mouse extends Animal {

    /**
     * Base energy level: 50. Run spending: 2.
     */
    Mouse() {
        super(50, 2);
    }
    
    /**
     * Energy goes up 5 points in a narrow escape.
     */
    public void escaped() {
        increaseEnergy(5);
    }

    /**
     * @return the energy level in this mouse
     */
    public int drain() {
        int energy = getEnergy();
        setEnergy(0);
        return energy;
    }

    /**
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "Mouse: " + super.toString();
    }

    /**
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object o) {
        if (o instanceof Mouse)
            return super.equals(o);
        return false;
    }
 
}

Conceito de Pássaro

O conceito de pássaro poderia ser melhor definido, mas, nesta fase, utiliza-se um grau de abstracção menos conveniente, evitando definir conceitos apenas para evitar repetição de código (uma decisão que, na ausência de outras técnicas, poderia ter sido tomada na outra direcção -- ver, como exemplo, a classe NamedAnimal, que agrega alguma funcionalidade que não lhe pertence intrinsecamente).

Comparar a implementação com a versão sem herança e considerar outras possibilidades de abstracção.

Ficheiro Bird.java
public class Bird extends Animal {

    /**
     * Base energy level: 20. Run spending: 5.
     */
    Bird() {
        super(20, 5);
    }
    
    /**
     * 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 (getEnergy() < 2)
            return false;
        increaseEnergy(-2);
        return true;
    }

    /**
     * Energy goes up 5 points in a narrow escape.
     */
    public void escaped() {
        increaseEnergy(5);
    }

    /**
     * @return the energy level in this bird
     */
    public int drain() {
        int energy = getEnergy();
        setEnergy(0);
        return energy;
    }

    /**
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "Bird: " + super.toString();
    }

    /**
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object o) {
        if (o instanceof Bird)
            return super.equals(o);
        return false;
    }
 
}

Programa Principal

Almost unchanged from the previous versions (only object construction was changed -- it is simpler now).

Ficheiro Application.java
public class Application {

    /**
     * The application scenario.
     *
     * @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]);
        
    }

}

Compiling and Running

How to Compile?

The compilation is as follows:

 javac Animal.java
 javac NamedAnimal.java
 javac Dog.java
 javac Cat.java
 javac Mouse.java
 javac Bird.java
 javac Application.java

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

Running

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

 java Application