0

I have three classes Dog.java, Cat.java and Monkey.java all implementing interface Animal.java. I then have DogManager.java, CatManager.java and MonkeyManager.java each having the following method and returning a Dog, Cat, Monkey instance respectively:

public Animal getAnimal(); 

Finally I have a factory class that takes an animal name and returns an appropriate animal instance.

public Animal getAnimal(String name);

This all works fine, till I have to use the Animal object returned by the factory class to my controller class where I expect to call the bark() method exposed by Dog.java when I get the Dog instance from the factory but I don't have that method available since my factory returns Animal type which does not have bark().

So I was thinking of trying passing a class object to the getAnimal() in my factory class:

public <T> T getAnimal(String name, Class<T implements Animal> clazz);    

However, this requires I know the class association for each animal name. I was trying the following:

IManager.java

Class<?> getClassName();
String getName();

DogManager.java

public Class<?> getClassName(){
    return Dog.class;
}

public String getName(){
    return "Dog";
}

public Dog getName(){
    return new Dog();
}

CatManager.java

Class<?> getClassName(){
    return Cat.class;
}

public String getName(){
    return "Cat";
}

And then in my factory call:

IManager manager = getManager(); //Here I will get one of the Cat/Dog/Monkey managers based on name
factory.getAnimal(name, manager.getClassName()); //Compilation fails here

But this does not work, since getAnimal takes Class and manager.getClassName() is returning Class.

Any idea how can I make this work?

2
  • 3
    This looks like abuse of both generics and the factory pattern. I could understand if you had makeSound() in Animal, but this is basically a lot of code for absolutely no benefits. Commented Feb 8, 2017 at 12:57
  • The problem is that even if though you get the right class from manager.getClassName, you won't know in what kind of variable to assign the result from the factory call. Sure, you know it is Animal, but you cannot be sure it is a Dog. Calling any methods that are Dog specific won't be possible without casting. If you know in advance it will be a dog, then you can pass Dog.class to getAnimal and the assignment will work. Commented Feb 8, 2017 at 13:13

3 Answers 3

2

Once you have an Animal instance and you know that it is a Dog, you can cast it as a Dog and use all the methods of the Dog class.

Let´s see an example:

Dog dog = new Dog();
Animal animal = dog;

Right now, you can not use the bark() method directly in the animal instance (animal.bark() is not possible).

But if you use casting '(Dog) animal', you will have all the Dog methods available for the object casted.

if(animal instanceof Dog){
    ((Dog) animal).bark();
}
Sign up to request clarification or add additional context in comments.

Comments

0

The way to solve this is to add in your method signature the Class of the Animal you want to get, as the compiler can't guess the Animal you want to get when you're coding factory.getAnimal(name, manager.getClassName()).

So the answer is to add a parameterized Type to your IManager so the getAnimal() method returns the good type. But even if you do this, you will have to cast an Animal in the subtype you are looking for as the getAnimal() method can only return an Animal without getting any compilation error.

You won't be able to have any Dog or Catunless, somewhere, you don't write it down in your code

Comments

0

This is a great example of a terrible technique. Consider saving it as a cautionary tale of "bad things people do". If you truly wish to continue walking this path to fiasco, then consider the following:

  1. None of this will be an example of good or quality software development.
  2. Add methods like "Dog getDog()" to the Animal interface. If the implementation is a Dog, this method will return the Animal cast to a Dog, if not, it will return null. Maybe add "boolean isDog()" as well.
  3. In the Dog class, implement the isDog as something like this: return true;.
  4. In the Cat class, implement the isDog method like this: return false.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.