Kevin
Kevin

Reputation: 3379

Java factory pattern, creating specific classes

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

Answers (5)

Mad Matts
Mad Matts

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 getmethod, 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

ttarczynski
ttarczynski

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

mohsenmadi
mohsenmadi

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

Pawan
Pawan

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

Dici
Dici

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

Related Questions