I'm new to java and came across some advanced Enum code in my organization.
I am familiar with enums defined as follows: public enum someList { VALUE1, VALUE2, ..}
But in the advanced enum that I came across, a lot more seems to be going on..
/**
* Defines ways to compare records in {#link ApplicationStatus} to see if they
* are the same.
*/
public enum SourceStatusComparisonType
{
CONTEXT_KEY
{
#Override
public boolean compareKeys(SourceStatus source, ApplicationStatus status)
{
return source.getContextKey() == status.getSourceContextId();
}
},
DATE
{
#Override
public boolean compareKeys(SourceStatus source, ApplicationStatus status)
{
return source.getCobDate().equals(status.getCobDate());
}
};
public abstract boolean compareKeys(SourceStatus source,
ApplicationStatus status);
}
Could someone enlighten me on what's going on with the abstract method that's being overridden and overloaded. I don't understand what's going on in the above. I was told this is being used to abstract away if/else blocks from the code that uses it. But I'm not sure I understand.
Thank you in advance.
Each enum constants can be optionally followed by a class body, as specified in JLS §8.9.
The optional class body of an enum constant implicitly defines an anonymous class declaration (§15.9.5) that extends the immediately enclosing enum type. The class body is governed by the usual rules of anonymous classes; in particular it cannot contain any constructors.
So, it is like creating an abstract class SourceStatusComparisonType, with an abstract method - compareKeys(). You create 2 instances of that class:
CONTEXT_KEY = new SourceStatusComparisonType() {
#Override
public void compareKeys() { .. }
};
DATE = new SourceStatusComparisonType() {
#Override
public void compareKeys() { .. }
};
And override the abstract method for each instances. You can't have any instance, without having an implementation of that method.
Similarly, all the enum constants, must provide an implementation of the abstract method in it's respective anonymous class body. Else, you can't have that method as abstract. You have to provide a body, which will be used by default for the enum constants, that don't provide that method implementation:
public enum SourceStatusComparisonType
{
CONTEXT_KEY
{
#Override
public boolean compareKeys(SourceStatus source, ApplicationStatus status)
{
return source.getContextKey() == status.getSourceContextId();
}
},
DATE
{
#Override
public boolean compareKeys(SourceStatus source, ApplicationStatus status)
{
return source.getCobDate().equals(status.getCobDate());
}
},
DEFAULT;
public boolean compareKeys(SourceStatus source,
ApplicationStatus status) {
// return somedefaultvalue;
}
}
So, for the first 2 constants, when you invoke compareKeys method, their specific implementation will be used, and for DEFAULT, the method defined outside will be used.
Enum type can have body like abstract methods and all enum constants should implement those abstract methods.
Look at the JSL here http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9.2 and go to the section Example 8.9.2-4. Enum Constants with Class Bodies.
You even can implement an ENUM with an interface rather having a abstract method in it. Something like public enum SourceStatusComparisonType implements StatusComparable.
First thing you need to know about Enum in Java is that they are classes, think of them as classes. As such all the object oriented design/programming concepts you have learned apply to them.
Imagine a universe of your making, in which only 3 creatures exists, a Cat and Cow and a dog. One implementation would be
public abstract class Animal
{
private final String name;
public Animal(String name) {
this.name = name;
}
public abstract String sayHello(Animal other);
}
public class Cat extends Animal
{
public Cat(String name) {
super(name);
}
#Override
public String sayHello(Animal other) {
System.out.println(this.name + " says Meow!!! to " + other.name);
}
}
public class Cow extends Animal
{
public Cow(String name) {
super(name);
}
#Override
public String sayHello(Animal other) {
System.out.println(this.name + " says Moo!!! to " + other.name);
}
}
public class Dog extends Animal
{
public Dog(String name) {
super(name);
}
#Override
public String sayHello(Animal other) {
System.out.println(this.name + " says Woof!!! to " + other.name);
}
}
public Universe {
public List<Animal> animals;
public Universe(List<Animal> animals) {
this.animals = animals;
}
public void run() {
for (Animal animal : animals) {
for (Animal other : animals) {
if (other != animal) {
animal.sayHello(other);
}
}
}
}
}
You are satisfied with your universe and deploy it in production. Only to find, another malicious developer has introduced a new creature to your universe, a zombie
public class Zombie extends Animal
{
public Zombie(String name) {
super(name);
}
public String sayHello(Animal other) {
System.out.println(this.name + " says Arrggggg!!! to " + other.name);
eat(other);
}
private void eat(Animal other) {
System.out.println("nomm nomm " + other.name);
}
}
Zombies in the guise of saying hello eat all the animals they run into. Pretty soon there will be no Cats, Dogs and Cows left. You decide to deploy version 2 of your universe to prevent this and guard against zombies
public Universe2 {
public List<Animal> animals;
public Universe(List<Animal> animals) {
this.animals = animals;
}
public void run() {
for (Animal animal : animals) {
for (Animal other : animals) {
if (other != animal) {
if (!(animal instanceof Zombie))
animal.sayHello(other);
}
}
}
}
}
You are happy now, but you notice the cat populations decreasing, turns out cats and dogs are no longer friends, the zombies have infected their brains, you deploy version 3 of the universe.
public Universe3 {
public List<Animal> animals;
public Universe(List<Animal> animals) {
this.animals = animals;
}
public void run() {
for (Animal animal : animals) {
for (Animal other : animals) {
if (other != animal) {
if (!(animal instanceof Zombie) && !((animal instanceof Cat) && (animal instanceof Dog)))
animal.sayHello(other);
}
}
}
}
}
In this version, there are no zombies. Cats and Dogs say hello to Cows but not each other. The universe is in equilibrium but you have a nagging feeling that not everything is right with the world. You sleep on it and come to the realization that you are open to attack similar to the zombie ones, you decide to lock down the universe and implement a rewrite to start from scratch and eliminate the zombie epidemic entirely. Except you like friendly zombies that say hello.
public Enum Animal {
Cat {
#Override
public String sayHello(Animal other) {
System.out.println(this.name + " says Meow!!! to " + other.name);
}
},
Cow {
#Override
public String sayHello(Animal other) {
System.out.println(this.name + " says Moo!!! to " + other.name);
}
},
Dog {
#Override
public String sayHello(Animal other) {
System.out.println(this.name + " says Woof!!! to " + other.name);
}
},
Zombie {
#Override
public String sayHello(Animal other) {
System.out.println(this.name + " says Argggg!!! to " + other.name);
}
};
private String name;
public Animal(String name) {
this.name.
}
public String sayHello(Animal other);
}
public PerfectUniverse {
public List<Animal> animals;
public Universe(List<Animal> animals) {
this.animals = animals;
}
public void run() {
for (Animal animal : animals) {
for (Animal other : animals) {
if (other != animal) {
animal.sayHello(other);
}
}
}
}
}
You have eliminated the conditional if's using inheritance but locking down the extensibility by using an enumeration. You can do the same using classes, restricting access to Animal outside the package and making the derived types final. This of the enum Cat as an instance of Cat extending Animal. The derived types with overridden method avoid the need for instanceof checks with if conditionals.
Related
I have a collection of Animal objects.
My core code wants to treat all of these as Animals, all the same. Each Animal needs to be processed in some way. The nature of the processing depends on the sub-type of the Animal (bird, mammal, etc).
My code currently looks as follows.
public interface Animal {
public String getTaxonomyClass();
}
public abstract class Bird implements Animal {
#Override
public String getTaxonomyClass() {
return "aves";
}
// Specific to birds
public abstract float getWingspan();
}
public abstract class Mammal implements Animal {
#Override
public String getTaxonomyClass() {
return "mammalia";
}
// Specific to mammals
public abstract int getToothCount();
}
public interface AnimalProcessor {
public String getSupportedTaxonomyClass();
public void process(Animal a);
}
public class MammalProcessor implements AnimalProcessor {
#Override
public String getSupportedTaxonomyClass() {
return "mammalia";
}
#Override
public void process(Animal a) {
System.out.println("Tooth count is " + ((Mammal)a).getToothCount());
}
}
public class BirdProcessor implements AnimalProcessor {
#Override
public String getSupportedTaxonomyClass() {
return "aves";
}
#Override
public void process(Animal a) {
System.out.print("Wingspan is " + ((Bird)a).getWingspan());
}
}
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ZooKeeper {
Map<String, AnimalProcessor> registry = new HashMap<String, AnimalProcessor>();
public void registerProcessor(AnimalProcessor ap)
{
registry.put(ap.getSupportedTaxonomyClass(), ap);
}
public void processNewAnimals(List<Animal> newcomers)
{
for(Animal critter : newcomers)
{
String taxonomy = critter.getTaxonomyClass();
if(registry.containsKey(taxonomy))
{
// if I can process the animal, I will
AnimalProcessor ap = registry.get(taxonomy);
ap.process(critter);
}
}
}
}
import java.util.LinkedList;
import java.util.List;
public class MainClass {
public static void main(String[] args) {
ZooKeeper keeper = new ZooKeeper();
keeper.registerProcessor(new MammalProcessor());
keeper.registerProcessor(new BirdProcessor());
List<Animal> animals = new LinkedList<Animal>();
animals.add(new Mammal() { // badger
#Override
public int getToothCount() {
return 40;
} }
);
animals.add(new Bird() { // condor
#Override
public float getWingspan() {
return 2.9f;
} }
);
keeper.processNewAnimals(animals);
}
}
Generally this is easy to understand and works nicely! I can add plug-in new processors and animal types at my leisure without changing the ZooKeeper class or any of the interfaces. You can imagine a more advanced main class, loading the Animals from a database, and processing them all in turn.
However, I worry about the downcasts inside the AnimalProcessor subclasses! This strikes me as something which should not be there, and may be a violation of OO principles. After all, at the moment I can pass a Bird to a MammalProcessor's process() method, and there will be a ClassCastException.
Can anyone suggest a design pattern to solve this? I looked at the Visitor pattern, but couldn't quite figure out how to apply it in this case! The key is to make the core code (ZooKeeper) treat all animals the same, and make it so that support for new Animals can be added trivially. Thanks!
I would suggest the following:
public interface Animal {
public AnimalProcessor<? extends Animal> getProcessor();
}
so each animal will return it's matching processor.
public interface AnimalProcessor<T extends Animal> {
public void process(T a);
}
so the processors will be typed with their matching type it's should process.
so the implantation will be like this:
public abstract class Bird implements Animal {
private BirdProcessor processor = new BirdProcessor();
public abstract float getWingspan();
#Override
public AnimalProcessor<Bird> getProcessor() {
return processor;
}
}
public class BirdProcessor implements AnimalProcessor<Bird> {
#Override
public void process(Bird b) {
System.out.print("Wingspan is " + b.getWingspan());
}
}
This is where generics work great.
First, you need to make AnimalProcessor generic:
public interface AnimalProcessor <T extends Animal> {
public String getSupportedTaxonomyClass();
public void process(T a);
}
Next, in your specific processors, you specify the generic type - eg for mammals:
public class MammalProcessor implements AnimalProcessor<Mammal> {
public String getSupportedTaxonomyClass() {
return "mammalia";
}
public void process(Mammal a) {
System.out.println("Tooth count is " + a.getToothCount());
}
}
Now, the process method only accepts Mammal objects, no birds here.
I suggest the following :
public interface Animal {
public String getTaxonomyClass();
public void process();
}
Now each animal class implementing Animal should implement its own processing logic.
For example :
public class Bird implements Animal {
public Bird(float wingSpan) {
this.wingSpan = wingSpan;
}
#Override
public String getTaxonomyClass() {
return "aves";
}
#Override
public void process() {
System.out.print("Wingspan is " + wingSpan);
}
// Specific to birds
private float wingspan;
}
Now you can have only one AnimalProcessor which processes as follows :
public void process(Animal a) {
a.process();
}
Make you AnimalProcessor generic;
public interface AnimalProcessor<T extends Animal> {
public String getSupportedTaxonomyClass();
public void process(T a);
}
public class MammalProcessor implements AnimalProcessor<Mammal> {
#Override
public String getSupportedTaxonomyClass() {
return "mammalia";
}
#Override
public void process(Mammal a) {
System.out.println("Tooth count is " + a.getToothCount());
}
}
So you've got a class like this...
public abstract class Bird implements Animal {
#Override
public String getTaxonomyClass() {
return "aves";
}
// Specific to birds
public abstract float getWingspan();
}
All Birds will have a wingspan, even if the wingspan is 0. So, why don't you change the class to something like this...
public class Bird implements Animal {
float wingspan = 0.0f;
public Bird(float wingspan){
this.wingspan = wingspan;
}
#Override
public String getTaxonomyClass() {
return "aves";
}
// Specific to birds
public float getWingspan(){
return wingspan;
}
}
So, to create a new Bird, instead of doing this...
animals.add(new Bird() { // condor
#Override
public float getWingspan() {
return 2.9f;
} }
);
You would just do this...
animals.add(new Bird(2.9f)); // condor
This would seem to make the whole thing a lot simpler and nicer for your purposes. You would do a similar change for your Mammal class too.
Now, for the processing of animals... if all Animals are going to be processed, you could just implement process() in Bird rather than needing a separate BirdProcessor class. To do this, in Animal, declare a method public void process();. Your Bird would implement it like this...
public void process() {
System.out.print("Wingspan is " + getWingspan());
}
and you would change your AnimalProcessor to simply do this (note: no longer an interface)...
public class AnimalProcessor {
public void process(Animal a) {
a.process();
}
}
Your AnimalProcessor class would then be able to handle all Animals.
Alternatively, if you want to leave AnimalProcessor as it is, it would probably be good to change the following though, to avoid the ClassCastException (this code here is for the BirdProcessor)...
public void process(Animal a) {
if (a instanceof Bird){
System.out.print("Wingspan is " + ((Bird)a).getWingspan());
}
}
Is this kinda what you were looking for?
Your problem are methods such as
public abstract int getToothCount();
...aren't defined in Animal. Instead, they are defined in specific subclasses of Animal. This means you can't treat Animals generically since they are fundamentally different.
To overcome this, the one approach would be to create abstract methods for all these in the Animal class.
Bird might respond to getToothCount() with "0".
Since all animals could respond to getWingspan(), getTootCount(), etc, you would not have to perform any type-specific checking. If this isn't good enough, create abstract implementations of "boolean hasWings()", "boolean hasTeeth()" etc etc in Animal.
Now you could say, for some animal a:
if (a.hasWings()) System.out.println("My wingspan is "+a.getWingSpan());
which would work for any animal. Of course, each subclass of Animal would have to implement all the various methods.
Another option is to add non-abstract methods to Animal. These methods would supply default answers. For example, getWingSpan() would return 0, getToothCount() would return 0, etc. Shark would override getToothCount(). Eagle would override getWingSpan()...
Then your subclasses would only have to override (or even know about) methods related directly to them.
So the compiler complains when ever i do a explicit cast. I can prevent this by using a #SuppressWarnings annotation.
At this point i would have this annotation a lot in my code which lets me suspect that there is another way i'm just not aware of.
Lets have a look at this example
class CutePet
{
public void pet()
{
System.out.println( "The cute pet gets some pets" );
}
}
class Cat extends CutePet
{
public void letOutside()
{
System.out.println( "The cat goes outside" );
}
public void letInside()
{
System.out.println( "The cat comes inside" );
}
public void removeTick()
{
System.out.println( "The cat looses all ticks" );
}
}
class Dog extends CutePet
{
public void goForAWalk()
{
System.out.println( "The Dog goes for a walk" );
}
public void tellHimWhatHeIs()
{
System.out.println( "The Dog is a good boy" );
}
}
class caretaker
{
public void takeCare( CutePet pet )
{
if( pet instanceof Cat )
{
pet.pet();
((Cat)pet).letOutside();
((Cat)pet).letInside();
((Cat)pet).removeTick();
}
else if( pet instanceof Dog )
{
pet.pet();
((Dog)pet).goForAWalk();
((Dog)pet).tellHimWhatHeIs();
}
}
}
The Caretaker does not know what kind of Pet he will get in advance and he my has several pets of different kinds.
I tried to give the Cute pet class a getType() method which returns a enum. With this enum i can remove the "instanceof" but the cast is still there.
Am i missing something?
If this were a real world problem, the caretaker would recognize which kind of pet he has based on the pet's appearance. While "instance of" is one way of looking at it, you might want to consider overloading the takeCare method directly with the subtypes as required. For example:
class Caretaker {
public void takeCare(Cat pet) {
pet.pet();
pet.letOutside();
pet.letInside();
pet.removeTick();
}
public void takeCare(Dog pet) {
pet.pet();
pet.goForAWalk();
pet.tellHimWhatHeIs();
}
}
in other words, the caretaker knows what to do (has methods already in place) for the kind of pet he receives.
EDIT
In response to some of the comments, yes, the original example shifts the problem further up. If you have an array or a list of generic pets then you still have to figure out what kinds of pets you have to give them to the caretaker. Conceptually it seems strange that the pet should be able to pet itself, take itself for a walk, etc. (these methods are part of the pet class when it should be the caretaker doing these actions ON the pet).
I've since rewritten the code with a full working example below with a Job class that has a perform method. This method will return the appropriate job based on the type of animal the caretaker has. The caretaker can then perform the job on the pet in question. See below.
Doing things this way avoids instanceof. While it is debatable how good/bad instanceof actually is, where possible it should be the object itself to tell me what it needs, otherwise the whole polymorphism concept can get pretty hairy pretty quick.
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
Caretaker caretaker = new Caretaker();
Arrays.asList(
new Cat("Cat1"),
new Cat("Cat2"),
new Dog("Dog1")
).forEach(caretaker::takeCare);
}
interface CutePet {
String whoAmI();
Job whatINeed();
}
abstract static class NamedCutePet implements CutePet {
private final String name;
public NamedCutePet(String name) {
this.name = name;
}
public String whoAmI() {
return this.name;
}
}
static class Cat extends NamedCutePet {
public Cat(String name) {
super(name);
}
#Override
public Job whatINeed() {
return new CatJob(this);
}
}
static class Dog extends NamedCutePet {
public Dog(String name) {
super(name);
}
#Override
public Job whatINeed() {
return new DogJob(this);
}
}
static class Caretaker {
void takeCare(CutePet pet) {
pet.whatINeed().perform();
}
}
static abstract class BaseJob implements Job {
void pet(CutePet pet) {
System.out.println(String.format("The cute pet %s gets some pets", pet.whoAmI()));
}
}
static class DogJob extends BaseJob {
private final Dog dog;
public DogJob(Dog dog) {
this.dog = dog;
}
#Override
public void perform() {
pet(dog);
takeDogFarAWalk(dog);
tellHimWhatHeIs(dog);
}
private void takeDogFarAWalk(Dog dog) {
System.out.println(String.format("The dog %s goes for a walk", dog.whoAmI()));
}
private void tellHimWhatHeIs(Dog dog) {
System.out.println(String.format("The dog %s is a good boy", dog.whoAmI()));
}
}
static class CatJob extends BaseJob {
private final Cat cat;
public CatJob(Cat cat) {
this.cat = cat;
}
#Override
public void perform() {
pet(cat);
letOutside(cat);
letInside(cat);
removeTick(cat);
}
private void letOutside(Cat cat) {
System.out.println(String.format("The cat %s goes outside", cat.whoAmI()));
}
private void letInside(Cat cat) {
System.out.println(String.format("The cat %s comes inside", cat.whoAmI()));
}
private void removeTick(Cat cat) {
System.out.println(String.format("The cat %s loses all ticks", cat.whoAmI()));
}
}
interface Job {
void perform();
}
}
Let's make it clear: you can't call subclass specific methods without typecasting to subclass type.
Now, let me suggest an alternate way. Define a method takeCare() in the superclass and let the subclasses implement it by calling several specific methods specific to subclasses. Then from CareTaker#takeCare(), call only takeCare() method without typecasting.
Several other alternate approaches can be used to solve the situation.
Here is how you would do it with interfaces and reflection. Note that only the interface methods are called for each pet type. It could also be extended to call other methods.
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class PetProblem {
public static void main(String[] args) {
Caretaker caretaker = new Caretaker();
Dog dog = new Dog();
caretaker.takeCare(dog);
System.out.println("\nNow do it for the cat\n");
Cat cat = new Cat();
caretaker.takeCare(cat);
}
}
interface CuteCat {
void letOutside();
void letInside();
void removeTick();
}
interface CuteDog {
void goForAWalk();
void tellHimWhatHeIs();
}
interface CutePet {
default void pet() {
System.out.println("The cute pet gets some pets");
}
}
class Cat implements CutePet, CuteCat {
public void letOutside() {
System.out.println("The cat goes outside");
}
public void letInside() {
System.out.println("The cat comes inside");
}
public void removeTick() {
System.out.println("The cat looses all ticks");
}
}
class Dog implements CutePet, CuteDog {
public void goForAWalk() {
System.out.println("The Dog goes for a walk");
}
public void tellHimWhatHeIs() {
System.out.println("The Dog is a good boy");
}
}
class Caretaker {
public void takeCare(Object pet) {
Class<?>[] ifss = pet.getClass().getInterfaces();
for (Class<?> ifs : ifss) {
Method[] methods = ifs.getDeclaredMethods();
for (Method m : methods) {
try {
m.invoke(pet);
}
catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
}
Note however, that using interfaces and having a method so named that it can be used for all pets is easier. Here is an example. Since both dogs and cats need to eat, a common method feedMe() can be implemented for each.
public class AnimalShelter {
public static void main(String[] args) {
Caretaker caretaker = new Caretaker();
Dog dog = new Dog();
Cat cat = new Cat();
caretaker.feedThePets(dog);
caretaker.feedThePets(cat);
}
}
interface SupperTime {
void feedMe();
}
class Caretaker {
public void feedThePets(SupperTime pet) {
pet.feedMe();
}
}
class Dog implements SupperTime {
public void feedMe() {
System.out.println("Oh boy, Kibbles n' Bits");
}
}
class Cat implements SupperTime {
public void feedMe() {
System.out.println("Yum. Purina Cat Chow");
}
}
Here is some enum with get() method.
public class ZooTest {
public enum Animals {
CHLOE("cat"),
MOLLY("dog"),
LUNA("cat"),
TOBY("dog"),
ZOE("parrot"),
SNICKERS("cat");
private final String type;
Animals(String type) {
this.type = type;
}
public class Animal {
}
public class Cat extends Animal {
}
public class Dog extends Animal {
}
public class Parrot extends Animal {
}
public Animal get() {
return "cat".equals(type)
? new Cat()
: "dog".equals(type)
? new Dog()
: new Parrot();
}
}
#Test
public void shouldReturnSpecificClass() {
assertTrue(Animals.CHLOE.get() instanceof Cat);
}
#Test(expectedExceptions = {ClassCastException.class})
public void shouldReturnSpecificClass2() {
Dog dog = (Dog) Animals.CHLOE.get();
}
}
The question is how can it be improved to return specific type of animal without using type casting outside enum. Of course I can use methods like
public <T extends Animal> T get(Class<T> clazz) { return (T) get(); }
but maybe there is less clumsy way.
This answer is based on assumption that you don't actually need separate instances of Cat for CHLOE, LUNA, or SNICKERS. Also since your Animals didn't have any methods or state it doesn't look like you really need them as separate classes. So maybe something like this will be easier:
public enum AnimalType {
Cat, Dog, Parrot;
}
public enum Animals {
CHLOE(AnimalType.Cat),
MOLLY(AnimalType.Dog),
LUNA(AnimalType.Cat),
TOBY(AnimalType.Dog),
ZOE(AnimalType.Parrot),
SNICKERS(AnimalType.Cat);
private final AnimalType type;
Animals(AnimalType type) {
this.type = type;
}
public AnimalType get() {
return type;
}
}
You can create an abstract method get that and each instance of Animals has to implement:
public enum Animals {
CHLOE("cat") {
#Override
public Animal get() { return new Cat(); }
},
MOLLY("dog") {
#Override
public Animal get() { return new Dog(); }
}
//... and so on
public abstract Animal get();
}
You have two mistakes of enum using. The first enum entities must provided something like type not instance (how it pointed Quirliom), and then your Animal enum must contains members cat, dog etc. The second unfortunately you can not extend any class from enum.
I have a collection of Animal objects.
My core code wants to treat all of these as Animals, all the same. Each Animal needs to be processed in some way. The nature of the processing depends on the sub-type of the Animal (bird, mammal, etc).
My code currently looks as follows.
public interface Animal {
public String getTaxonomyClass();
}
public abstract class Bird implements Animal {
#Override
public String getTaxonomyClass() {
return "aves";
}
// Specific to birds
public abstract float getWingspan();
}
public abstract class Mammal implements Animal {
#Override
public String getTaxonomyClass() {
return "mammalia";
}
// Specific to mammals
public abstract int getToothCount();
}
public interface AnimalProcessor {
public String getSupportedTaxonomyClass();
public void process(Animal a);
}
public class MammalProcessor implements AnimalProcessor {
#Override
public String getSupportedTaxonomyClass() {
return "mammalia";
}
#Override
public void process(Animal a) {
System.out.println("Tooth count is " + ((Mammal)a).getToothCount());
}
}
public class BirdProcessor implements AnimalProcessor {
#Override
public String getSupportedTaxonomyClass() {
return "aves";
}
#Override
public void process(Animal a) {
System.out.print("Wingspan is " + ((Bird)a).getWingspan());
}
}
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ZooKeeper {
Map<String, AnimalProcessor> registry = new HashMap<String, AnimalProcessor>();
public void registerProcessor(AnimalProcessor ap)
{
registry.put(ap.getSupportedTaxonomyClass(), ap);
}
public void processNewAnimals(List<Animal> newcomers)
{
for(Animal critter : newcomers)
{
String taxonomy = critter.getTaxonomyClass();
if(registry.containsKey(taxonomy))
{
// if I can process the animal, I will
AnimalProcessor ap = registry.get(taxonomy);
ap.process(critter);
}
}
}
}
import java.util.LinkedList;
import java.util.List;
public class MainClass {
public static void main(String[] args) {
ZooKeeper keeper = new ZooKeeper();
keeper.registerProcessor(new MammalProcessor());
keeper.registerProcessor(new BirdProcessor());
List<Animal> animals = new LinkedList<Animal>();
animals.add(new Mammal() { // badger
#Override
public int getToothCount() {
return 40;
} }
);
animals.add(new Bird() { // condor
#Override
public float getWingspan() {
return 2.9f;
} }
);
keeper.processNewAnimals(animals);
}
}
Generally this is easy to understand and works nicely! I can add plug-in new processors and animal types at my leisure without changing the ZooKeeper class or any of the interfaces. You can imagine a more advanced main class, loading the Animals from a database, and processing them all in turn.
However, I worry about the downcasts inside the AnimalProcessor subclasses! This strikes me as something which should not be there, and may be a violation of OO principles. After all, at the moment I can pass a Bird to a MammalProcessor's process() method, and there will be a ClassCastException.
Can anyone suggest a design pattern to solve this? I looked at the Visitor pattern, but couldn't quite figure out how to apply it in this case! The key is to make the core code (ZooKeeper) treat all animals the same, and make it so that support for new Animals can be added trivially. Thanks!
I would suggest the following:
public interface Animal {
public AnimalProcessor<? extends Animal> getProcessor();
}
so each animal will return it's matching processor.
public interface AnimalProcessor<T extends Animal> {
public void process(T a);
}
so the processors will be typed with their matching type it's should process.
so the implantation will be like this:
public abstract class Bird implements Animal {
private BirdProcessor processor = new BirdProcessor();
public abstract float getWingspan();
#Override
public AnimalProcessor<Bird> getProcessor() {
return processor;
}
}
public class BirdProcessor implements AnimalProcessor<Bird> {
#Override
public void process(Bird b) {
System.out.print("Wingspan is " + b.getWingspan());
}
}
This is where generics work great.
First, you need to make AnimalProcessor generic:
public interface AnimalProcessor <T extends Animal> {
public String getSupportedTaxonomyClass();
public void process(T a);
}
Next, in your specific processors, you specify the generic type - eg for mammals:
public class MammalProcessor implements AnimalProcessor<Mammal> {
public String getSupportedTaxonomyClass() {
return "mammalia";
}
public void process(Mammal a) {
System.out.println("Tooth count is " + a.getToothCount());
}
}
Now, the process method only accepts Mammal objects, no birds here.
I suggest the following :
public interface Animal {
public String getTaxonomyClass();
public void process();
}
Now each animal class implementing Animal should implement its own processing logic.
For example :
public class Bird implements Animal {
public Bird(float wingSpan) {
this.wingSpan = wingSpan;
}
#Override
public String getTaxonomyClass() {
return "aves";
}
#Override
public void process() {
System.out.print("Wingspan is " + wingSpan);
}
// Specific to birds
private float wingspan;
}
Now you can have only one AnimalProcessor which processes as follows :
public void process(Animal a) {
a.process();
}
Make you AnimalProcessor generic;
public interface AnimalProcessor<T extends Animal> {
public String getSupportedTaxonomyClass();
public void process(T a);
}
public class MammalProcessor implements AnimalProcessor<Mammal> {
#Override
public String getSupportedTaxonomyClass() {
return "mammalia";
}
#Override
public void process(Mammal a) {
System.out.println("Tooth count is " + a.getToothCount());
}
}
So you've got a class like this...
public abstract class Bird implements Animal {
#Override
public String getTaxonomyClass() {
return "aves";
}
// Specific to birds
public abstract float getWingspan();
}
All Birds will have a wingspan, even if the wingspan is 0. So, why don't you change the class to something like this...
public class Bird implements Animal {
float wingspan = 0.0f;
public Bird(float wingspan){
this.wingspan = wingspan;
}
#Override
public String getTaxonomyClass() {
return "aves";
}
// Specific to birds
public float getWingspan(){
return wingspan;
}
}
So, to create a new Bird, instead of doing this...
animals.add(new Bird() { // condor
#Override
public float getWingspan() {
return 2.9f;
} }
);
You would just do this...
animals.add(new Bird(2.9f)); // condor
This would seem to make the whole thing a lot simpler and nicer for your purposes. You would do a similar change for your Mammal class too.
Now, for the processing of animals... if all Animals are going to be processed, you could just implement process() in Bird rather than needing a separate BirdProcessor class. To do this, in Animal, declare a method public void process();. Your Bird would implement it like this...
public void process() {
System.out.print("Wingspan is " + getWingspan());
}
and you would change your AnimalProcessor to simply do this (note: no longer an interface)...
public class AnimalProcessor {
public void process(Animal a) {
a.process();
}
}
Your AnimalProcessor class would then be able to handle all Animals.
Alternatively, if you want to leave AnimalProcessor as it is, it would probably be good to change the following though, to avoid the ClassCastException (this code here is for the BirdProcessor)...
public void process(Animal a) {
if (a instanceof Bird){
System.out.print("Wingspan is " + ((Bird)a).getWingspan());
}
}
Is this kinda what you were looking for?
Your problem are methods such as
public abstract int getToothCount();
...aren't defined in Animal. Instead, they are defined in specific subclasses of Animal. This means you can't treat Animals generically since they are fundamentally different.
To overcome this, the one approach would be to create abstract methods for all these in the Animal class.
Bird might respond to getToothCount() with "0".
Since all animals could respond to getWingspan(), getTootCount(), etc, you would not have to perform any type-specific checking. If this isn't good enough, create abstract implementations of "boolean hasWings()", "boolean hasTeeth()" etc etc in Animal.
Now you could say, for some animal a:
if (a.hasWings()) System.out.println("My wingspan is "+a.getWingSpan());
which would work for any animal. Of course, each subclass of Animal would have to implement all the various methods.
Another option is to add non-abstract methods to Animal. These methods would supply default answers. For example, getWingSpan() would return 0, getToothCount() would return 0, etc. Shark would override getToothCount(). Eagle would override getWingSpan()...
Then your subclasses would only have to override (or even know about) methods related directly to them.
Animal
public abstract class Animal {
String name;
public Animal(String name) {
this.name = name;
}
}
Lion
public class Lion extends Animal {
public Lion(String name) {
super(name);
// TODO Auto-generated constructor stub
}
public void roar() {
System.out.println("Roar");
}
}
Deer
public class Deer extends Animal {
public Deer(String name) {
super(name);
}
public void runAway() {
System.out.println("Running...");
}
}
TestAnimals
public class TestAnimals {
public static void main(String[] args) {
Animal lion = new Lion("Geo");
Animal deer1 = new Deer("D1");
Animal deer2 = new Deer("D2");
List<Animal> li = new ArrayList<Animal>();
li.add(lion);
li.add(deer1);
li.add(deer2);
for (Animal a : li) {
if (a instanceof Lion) {
Lion l = (Lion) a;
l.roar();
}
if (a instanceof Deer) {
Deer l = (Deer) a;
l.runAway();
}
}
}
}
Is there a better way to iterate through the list without having to cast ?In the above case it seem's ok but if you have many extensions of the base class then we'll need that many if block too.Is there a design pattern or principle to address this problem ?
An elegant way of avoiding instanceof without inventing some new artificial method in the base class (with a non-descriptive name such as performAction or doWhatYouAreSupposedToDo) is to use the visitor pattern. Here is an example:
Animal
import java.util.*;
abstract class Animal {
String name;
public Animal(String name) {
this.name = name;
}
public abstract void accept(AnimalVisitor av); // <-- Open up for visitors.
}
Lion and Deer
class Lion extends Animal {
public Lion(String name) {
super(name);
}
public void roar() {
System.out.println("Roar");
}
public void accept(AnimalVisitor av) {
av.visit(this); // <-- Accept and call visit.
}
}
class Deer extends Animal {
public Deer(String name) {
super(name);
}
public void runAway() {
System.out.println("Running...");
}
public void accept(AnimalVisitor av) {
av.visit(this); // <-- Accept and call visit.
}
}
Visitor
interface AnimalVisitor {
void visit(Lion l);
void visit(Deer d);
}
class ActionVisitor implements AnimalVisitor {
public void visit(Deer d) {
d.runAway();
}
public void visit(Lion l) {
l.roar();
}
}
TestAnimals
public class TestAnimals {
public static void main(String[] args) {
Animal lion = new Lion("Geo");
Animal deer1 = new Deer("D1");
Animal deer2 = new Deer("D2");
List<Animal> li = new ArrayList<Animal>();
li.add(lion);
li.add(deer1);
li.add(deer2);
for (Animal a : li)
a.accept(new ActionVisitor()); // <-- Accept / visit.
}
}
Animal
public abstract class Animal {
String name;
public Animal(String name) {
this.name = name;
}
public abstract void exhibitNaturalBehaviour();
}
Lion
public class Lion extends Animal {
public Lion(String name) {
super(name);
}
public void exhibitNaturalBehaviour() {
System.out.println("Roar");
}
}
Deer
public class Deer extends Animal {
public Deer(String name) {
super(name);
}
public void exhibitNaturalBehaviour() {
System.out.println("Running...");
}
}
TestAnimals
public class TestAnimals {
public static void main(String[] args) {
Animal[] animalArr = {new Lion("Geo"), new Deer("D1"), new Deer("D2")};
for (Animal a : animalArr) {
a.exhibitNaturalBehaviour();
}
}
}
Yes provide a method called action() in abstract class , implement it in both of the child class, one will roar other will runaway
Pattern matching support in the language eliminates the need for the ugly visitor pattern.
See this Scala code for example:
abstract class Animal(name: String)
class Lion(name: String) extends Animal(name) {
def roar() {
println("Roar!")
}
}
class Deer(name: String) extends Animal(name) {
def runAway() {
println("Running!")
}
}
object TestAnimals {
def main(args: Array[String]) {
val animals = List(new Lion("Geo"), new Deer("D1"), new Deer("D2"))
for(animal <- animals) animal match {
case l: Lion => l.roar()
case d: Deer => d.runAway()
case _ => ()
}
}
}
If your method is not polymorphic you can't do without the cast. To make it polymorphic, declare a method in the base class and override it in the descendant classes.
Here you have a List of animals. Usually when you have a list of Objects, all these objects must be able to do the same thing without being casted.
So the best two solutions are :
Having a common method for the two concrete classes (so defined as abstract in Animal)
Separate Lion from Deer from the start, and have two different lists.
It turns out that instanceof is faster than the visitor pattern presented above; I think this should make us question, is the visitor pattern really more elegant than instanceof when it's doing the same thing more slowly with more lines of code?
Here's my test. I compared 3 methods: the visitor pattern above, instanceof, and an explicit type field in Animal.
OS: Windows 7 Enterprise SP1, 64-bit
Processor: Intel(R) Core(TM) i7 CPU 860 # 2.80 GHz 2.93 GHz
RAM: 8.00 GB
JRE: 1.7.0_21-b11, 32-bit
import java.util.ArrayList;
import java.util.List;
public class AnimalTest1 {
public static void main(String[] args) {
Animal lion = new Lion("Geo");
Animal deer1 = new Deer("D1");
Animal deer2 = new Deer("D2");
List<Animal> li = new ArrayList<Animal>();
li.add(lion);
li.add(deer1);
li.add(deer2);
int reps = 10000000;
long start, elapsed;
start = System.nanoTime();
for (int i = 0; i < reps; i++) {
for (Animal a : li)
a.accept(new ActionVisitor()); // <-- Accept / visit.
}
elapsed = System.nanoTime() - start;
System.out.println("Visitor took " + elapsed + " ns");
start = System.nanoTime();
for (int i = 0; i < reps; i++) {
for (Animal a : li) {
if (a instanceof Lion) {
((Lion) a).roar();
} else if (a instanceof Deer) {
((Deer) a).runAway();
}
}
}
elapsed = System.nanoTime() - start;
System.out.println("instanceof took " + elapsed + " ns");
start = System.nanoTime();
for (int i = 0; i < reps; i++) {
for (Animal a : li) {
switch (a.type) {
case Animal.LION_TYPE:
((Lion) a).roar();
break;
case Animal.DEER_TYPE:
((Deer) a).runAway();
break;
}
}
}
elapsed = System.nanoTime() - start;
System.out.println("type constant took " + elapsed + " ns");
}
}
abstract class Animal {
public static final int LION_TYPE = 0;
public static final int DEER_TYPE = 1;
String name;
public final int type;
public Animal(String name, int type) {
this.name = name;
this.type = type;
}
public abstract void accept(AnimalVisitor av); // <-- Open up for visitors.
}
class Lion extends Animal {
public Lion(String name) {
super(name, LION_TYPE);
}
public void roar() {
// System.out.println("Roar");
}
public void accept(AnimalVisitor av) {
av.visit(this); // <-- Accept and call visit.
}
}
class Deer extends Animal {
public Deer(String name) {
super(name, DEER_TYPE);
}
public void runAway() {
// System.out.println("Running...");
}
public void accept(AnimalVisitor av) {
av.visit(this); // <-- Accept and call visit.
}
}
interface AnimalVisitor {
void visit(Lion l);
void visit(Deer d);
}
class ActionVisitor implements AnimalVisitor {
public void visit(Deer d) {
d.runAway();
}
public void visit(Lion l) {
l.roar();
}
}
Test results:
Visitor took 920842192 ns
instanceof took 511837398 ns
type constant took 535296640 ns
This visitor pattern introduces 2 extra method calls that are unnecessary with instanceof. This is probably why it's slower.
Not that performance is the only consideration, but notice how 2 instanceofs are faster than even a 2-case switch statement. Plenty of people have worried about the performance of instanceof, but this should put the worry to rest.
As a Java Developer, I feel frustrated when people have a dogmatic attitude about avoiding the use of instanceof, because there have been several times in my work I wanted to clean up or write new clean code by using instanceof, but coworkers/superiors didn't approve of this approach , because they have more or less blindly accepted the idea that instanceof should never be used. I feel frustrated because this point is often driven home with toy examples that don't reflect real business concerns.
Whenever you pursue modular software design, there will always be times when type-dependent decisions need to be isolated from the types in question, so that the types have as few dependencies as possible.
This visitor pattern doesn't break modularity, but it's not a superior alternative to instanceof.
Consider adding an interface for the action (Roar, Run away, etc) which is set on the animal in the constructor. Then have an abstract method such as act() on the Animal class which gets called similar to what Adeel has.
This will let you swap in actions to act out via a field at any time.
The simplest approach is to have the super class implement a default behaviour.
public enum AnimalBehaviour {
Deer { public void runAway() { System.out.println("Running..."); } },
Lion { public void roar() { System.out.println("Roar"); } }
public void runAway() { }
public void roar() { }
}
public class Animal {
private final String name;
private final AnimalBehaviour behaviour;
public Animal(String name, AnimalBehaviour behaviour) {
this.name = name;
this.behaviour = behaviour;
}
public void runAway() { behaviour.runAway(); }
public void roar() { behaviour.roar(); }
}
public class TestAnimals {
public static void main(String... args) {
Animal[] animals = {
new Animal("Geo", AnimalBehaviour.Lion),
new Animal("Bambi", AnimalBehaviour.Deer),
new Animal("D2", AnimalBehaviour.Deer)
};
for (Animal a : animals) {
a.roar();
a.runAway();
}
}
}