Reputation: 116
I have this code:
public abstract class Character {
public abstract void attack(Character victim);
public abstract void receiveAttack(Attack attack);
}
public class CharacterA extends Character {
public void attack(Character victim) {
if (victim.getClass().equals(this.getClass())
return;
victim.receiveAttack(new Attack(BASE_DMG));
}
}
The idea is that a Character can attack and receiveAttacks to/from other Characters, but it cannot receive an attack that comes from a character of its own class (CharacterA cannot attack another CharacterA but could attack CharacterB or receive an attack from a CharacterB).
I know that checking for the type of an object is a bad smell and is usually caused because of a bad design, so the question is how could I change the design so I don't have to check for the object type?
EDIT
The class is not actually named Character
, the name is just to simplify the example.
There are no teams. CharacterA
can attack any other Character
that is not a CharacterA
.
FINAL EDIT
Thanks everyone, I solved it by using the Visitor pattern.
Upvotes: 1
Views: 615
Reputation: 5455
You could achieve this by adding an overloaded attack method to each subclass that's declared to take an instance of the specific subclass, and making this method a no-op, or printing a warning.
For CharacterA the signature would be
public void attack(CharacterA victim)
However, this will only work if your subclass instances are declared with the specific type, not the base Character type.
class Character
{
public void attack(Character victim)
{
System.out.println(getClass() + " attacking " + victim.getClass());
victim.receiveAttack(new Attack());
}
public void receiveAttack(Attack attack) {}
}
class CharacterA extends Character
{
public void attack(CharacterA victim)
{
System.out.println(getClass() + " cannot attack " + victim.getClass());
}
}
class CharacterB extends Character
{
public void attack(CharacterB victim)
{
System.out.println(getClass() + " cannot attack " + victim.getClass());
}
}
class Attack
{
}
public class Test
{
public static void main(String[] args)
{
CharacterA a = new CharacterA();
CharacterB b = new CharacterB();
a.attack(a);
a.attack(b);
b.attack(a);
b.attack(b);
// redeclare a & b to have the base type
Character c = a;
Character d = b;
c.attack(c);
c.attack(d);
d.attack(c);
d.attack(d);
}
}
Output:
class CharacterA cannot attack class CharacterA
class CharacterA attacking class CharacterB
class CharacterB attacking class CharacterA
class CharacterB cannot attack class CharacterB
class CharacterA attacking class CharacterA
class CharacterA attacking class CharacterB
class CharacterB attacking class CharacterA
class CharacterB attacking class CharacterB
Upvotes: 0
Reputation: 351
A very simple solution/ work-around could be to have only one class, and every Character
Object has a String
field named characterTeam
or something of the like. For characters on the A team, set that field to "A"
or "ATeam"
. For B Team, set that field to "B"
or "BTeam"
. Then compare their characterTeam
String
s in the attack
method.
Also, I would advise against having a class named Character
as this might interfere with the wrapper class for char
, also named Character
.
Upvotes: 1