(→Conceito de Animal) |
|||
Line 137: | Line 137: | ||
return "base energy: " + _baseEnergy + ", energy left: " + _energy + ", spent running: " | return "base energy: " + _baseEnergy + ", energy left: " + _energy + ", spent running: " | ||
+ _runEnergy; | + _runEnergy; | ||
+ | } | ||
+ | } | ||
+ | </java5> | ||
+ | |||
+ | == 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). | ||
+ | |||
+ | <java5> | ||
+ | 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 == animal.getName(); | ||
+ | } | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * @see java.lang.Object#toString() | ||
+ | */ | ||
+ | @Override | ||
+ | public String toString() { | ||
+ | return _name + ", " + super.toString(); | ||
} | } | ||
} | } |
Considere o Exercício 02 da Introdução aos Objectos.
Resolva agora o mesmo problema, mas considerando 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.
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?
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.
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).
<java5> 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) { _energy = _baseEnergy = baseEnergy; _runEnergy = Math.min(runEnergy, baseEnergy); }
/** * @return the animal's base energy level. */ public int getBaseEnergy() { return _energy; }
/** * @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 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 < _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; } } </java5>
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).
<java5> 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 == animal.getName(); } return false; }
/** * @see java.lang.Object#toString() */ @Override public String toString() { return _name + ", " + super.toString(); } } </java5>