Reputation: 3379
I had a question on an interview where I had 2 types of foods, say bread and cake, was given the following:
public class FoodFactory{};
public class Food{};
public static void main(String[] args) {
Food foo = FoodFactory.get("bread");
System.out.println(foo.getClass().getName());
}
Given the FoodFactory
class and Food
class, I wasn't sure how to make this work so that it would print out "bread"
for the class. It really seemed like the only way to have gotten it to print bread was to create a Bread
class and have the FoodFactory
return that.
I'm just wondering if I'm missing anything, because FoodFactory
and Food
were classes given so I assumed those were the only 2 classes I needed to change. Is there a way to have implemented the two classes given and made it print "bread"
while using just those 2 classes?
Upvotes: 0
Views: 1550
Reputation: 1116
Your problem is basically an example for the Java Factory Design Pattern. Assumed you have a project, respectively a class hierarchy with multiple Interfaces and different classes, what would be the easiest way to create any class? This is where a Factory comes in place to handle all operations regarding class instance creation.
Now to your case, the convenient way would be to change your Class Food
to an interface eg:
public interface Food {
String getType();
}
Now you need your Cake
and Bread
classes, which implement the interface Food
public class Cake implements Food{
@Override
public String getType() {
return "Cake";
}
}
public class Bread implements Food{
@Override
public String getType() {
return "Bread";
}
}
Now you need to define your FoodFactory
class which has a static get
method, that returns a Food
depending on the criteria that has been supplied.
public class FoodFactory {
public static Food get(String classifier){
if(classifier.equals("Cake")) return new Cake();
if(classifier.equals("Bread")) return new Bread();
//no matching Food to create
throw new IllegalArgumentException("The " + classifier + " is not a valid classifier");
}
}
Once you have your Factory you can use it for any creation operation.
If you want to print out Bread
from a Food instance, you can achieve this like this:
//food is now an instanceof Bread
Food food = FoodFactory.get("Bread");
System.out.println(food.getType());
Which simply just prints
Bread
Further:
To make sure every creation is handled only by the FoodFactory
you should make every constructor of your Food classes protected
Upvotes: 0
Reputation: 1014
I think that the real question the interviewer was asking was if you understand the pattern and polymorphism. As noted in one of the comments getClass().getName()
won't return 'Bread' unless there really is a Bread class. What you could have done was to the suggest the interviewer that Food
is the base class which in this case should be extended by Cake
and Bread
classes, or even propose to change it to abstract class or interface. Then you could have proposed a simple factory class which would create the required implementation 'hidden' behind the base class interface.
Upvotes: 0
Reputation: 2377
Ideally, Food
should turn into an interface or an abstract class at best. Then you have classes Bread
and Cake
implement/extend Food
. Your FoodFactory
has a static method get
that accepts the food as a String. Depending on the value, you instantiate and return one of the concrete classes which will give you what you need when you print class name.
Upvotes: 0
Reputation: 1578
So one way to do it would be to make a class Bread
which extends class Food
and have the FoodFactory.get()
return the appropriate object based on the string passed.
class Food {};
class Bread extends Food {};
class FoodFactory {
public static Food get(String type){
switch(type){
case "bread" : return new Bread();
default : return new Food();
}
}
}
Another way to do it would be to use reflection.
Upvotes: 2
Reputation: 25950
Unless you compile a new class at runtime (which is possible, but inappropriate here), you will of course need to add a class if you want to return a Bread
instance.
Upvotes: 0