Reputation: 5660
Assume we have a class Animal, with subclasses as cat, eagle
Now I have a method:
public void process(Animal animal) {
if (animal instanceof Cat) {
if (!animal.meow()) {
throw exception("cat does not meow");
} else {
animal.feedFish();
}
}
if (animal instanceof eagle) {
if (!animal.fly()) {
throw exception("eagle does not fly");
} else {
animal.checkMaxFlightAltitude();
}
}
}
Here cat has 2 methods meow
and feedfish
which are completely different than eagle's methods fly
and checkmaxflight
Most design patterns revolve around assumptions that subclasses have a common method like Shape draw()
inherited by circle draw
and square draw
Is there some way to do validations on subclasses, such as cat and eagle without instanceof check ?
Any good design pattern ( assuming subclasses dont share a method in base class ? )
Upvotes: 4
Views: 1033
Reputation: 2977
This is when polymorphism comes in handy.
abstract class Animal {
abstract public void process(Animal animal);
}
class Cat extends Animal {
@Override
public void process(Animal animal) {
if (!this.meow()) {
throw exception("cat does not meow");
} else {
this.feedFish();
}
}
}
class Eagle extends Animal {
@Override
public void process(Animal animal) {
if (!this.fly()) {
throw exception("eagle does not fly");
} else {
this.checkMaxFlightAltitude();
}
}
}
Upvotes: 1
Reputation: 686
(1) Is there some way to do validations on subclasses, such as cat and eagle without instanceof check ?
yes, there is. You could define a "validate" method (abstract in "Animal" class) and implement it in the specific subclasses. Depending on the validation result (e.g. exception / problem list) you can have the validate method throw some kind of "InvalidContentException" or provide the method call with an "ErrorHandler" that is informed about the bad things of an instance.
(2) assuming that the subclasses don't share a method in the base class: well, that one is a bit counter intuitive. On one hand you want to be able to do something on an "Animal", yet you don't want to define that capability on it?
You could define a Validator class that has separate validation methods (on for each kind of "Animal" subclass). That would eliminate the instanceof checks, however you would never be able to pass this Validator class other "Animals" (such as "Dog"), only "Cat" and "Eagle" (or subclasses thereof). You might also want to consider what you want to happen when passing subclasses of "Cat": are all sublasses of Cat validated in the same way or is there subclass specific behavior (like color, size, ...) for the different cat classes?
--> I think you should ask yourself if you want to be able to validate animals in general. Without having insight into your problem domain (which might have reasons not to do it), I'd recommend to have a "validate" method on the animal. You could also go for a visitor pattern, but that requires the Animal to have a "accept(AnimalVisitor visitor)" method and is slightly more code to write (presumably more than you want to)
Upvotes: 1
Reputation: 729
You could use double dispatch by employing a visitor.
Example:
public class Animal {
public abstract void accept(AnimalVisitor v);
public boolean meow() {return false;}
public boolean fly() {return false;}
public void feedFish() {};
public void checkMaxFlightAltitude() {};
}
public class Cat extends Animal {
public void accept(AnimalVisitor v) {
v.visitCat(this);
}
public boolean meow() {return true;}
}
public class Eagle extends Animal {
public void accept(AnimalVisitor v) {
v.visitEagle(this);
}
public boolean fly() {return true;}
}
public interface AnimalVisitor {
void visitEagle(Eagle eagle);
void visitCat(Cat cat);
}
public class AnimalVisitorExample implements AnimalVisitor {
public void visitEagle(Eagle eagle) {
eagle.checkMaxFlightAltitude();
}
public void visitCat(Cat cat) {
cat.feedFish();
}
}
Animal animal = new Cat();
animal.accept(new AnimalVisitorExample());
Upvotes: 1
Reputation: 328568
You could have an abstract process
method in Animal
and implement it in the subclasses:
class Animal {
protected abstract void process();
public static void process(Animal a) { a.process(); }
}
class Cat {
void process() {
if (!meow()) throw exception("cat does not meow");
else feedFish();
}
public boolean meow() { ... }
public void feedFish() { ... }
}
Upvotes: 7