April 26, 2016

Part 3: Java Design Pattern Interview Questions & Answers (Factory and Abstract Factory)

In Part 1 of Java Design Pattern Interview Questions & Answers, we discussed the basics. In Part 2, we implemented the Singleton design pattern. In Part 3, we will understand Factory and Abstract Factory design patterns. 

What is a static factory or factory method Design Pattern?

It is one of the most used design patterns in Java. This type of design pattern comes under creational pattern as this pattern provides one of the best ways to create an object. In the Factory pattern, we create an object without exposing the creation logic to the client and refer to a newly created object using a common interface.

Factory pattern can be used:
  • When a class does not know which class of objects needs to create
  • When class specifies its sub-classes to specify which objects to create
  • In a programming language, you can use a factory pattern where you have to create an object of any one of the sub-classes depending on the given data.
Example of static factory method in JDK
valueOf(), which is there in String and wrapper classes like Integer and Boolean and used for type conversation. It returns an object created by the factory equivalent to the value of the parameter passed.

What is the benefit of the Factory pattern?

The factory pattern encapsulates the implementation details and underlying implementation can be changed without any impact on caller API.

Example of Factory Design Pattern


Let's create a Shape interface, which has a draw() method. Rectangle, Square, and Circle implements this interface. 

public interface Shape {
void draw();
}
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("**Inside Rectangle draw() method.");
}
}
public class Square implements Shape {
@Override
public void draw() {
System.out.println("**Inside Square draw() method.");
}
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("**Inside Circle draw() method.");
}
}

Now we will create a ShapeFactory class, which has the getShape() method. This getShape() takes a String argument based on which it creates and returns a different shape.

In the FactoryPatternDemo class, we are calling getShape() by passing different shape types and then calling the draw method.

public class ShapeFactory {
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
else if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
} else
{
return null;
}
}
}
public class FactoryPatternDemo {
public static void main(String[] args) {
ShapeFactory shapeFactory = new ShapeFactory();
Shape shape1 = shapeFactory.getShape("CIRCLE");
shape1.draw();
Shape shape2 = shapeFactory.getShape("RECTANGLE");
shape2.draw();
Shape shape3 = shapeFactory.getShape("SQUARE");
shape3.draw();
}
}

What is an Abstract Factory pattern?

  • Abstract Factory patterns work around a super-factory which creates other factories. 
  • This factory is also called a factory of factories. 
  • It comes under a creational pattern as this pattern provides one of the best ways to create an object. 
  • In the Abstract Factory pattern, an interface is responsible for creating a factory of related objects without explicitly specifying their classes. Each generated factory can give the objects as per the Factory pattern.
  • Abstract factory pattern provides abstraction one level higher than factory pattern. It encapsulates a group of individual factories.
  • Do not use Abstract Factory pattern, when the underlying object factories are not logically connected or underlying object factories are meant to serve objects with a different purpose.
Example of Abstract Factory Design Pattern

In the Factory Design Pattern, we created a Shape interface, which has a draw() method, and Rectangle, Square, and Circle implemented this interface.

In Abstract Factory, let's create another interface Color, which has a fill() method. Assume, after creating the Shape we need to fill it with some color, this fills () method of the Color interface does this.

public interface Color {
void fill();
}
public class Red implements Color {
@Override
public void fill() {
System.out.println("**Inside Red fill() method.");
}
}
public class Green implements Color {
@Override
public void fill() {
System.out.println("**Inside Green fill() method.");
}
}
public class Blue implements Color {
@Override
public void fill() {
System.out.println("**Inside Blue fill() method.");
}
}

Now we will create an abstract class AbstractFactory, which has two methods. From these methods, we get the Shape and Color.

We will create ShapeFactory and ColorFactory, these classes extend AbstractFactory. FactoryProducer returns either ShapeFactory or ColorFactory depending on the choice. 
public abstract class AbstractFactory {
abstract Color getColor(String color);
abstract Shape getShape(String shape) ;
}
public class ShapeFactory extends AbstractFactory{
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
else if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
} else
{
return null;
}
}
@Override
Color getColor(String color) {
return null;
}
}
public class ColorFactory extends AbstractFactory {
@Override
public Shape getShape(String shapeType){
return null;
}
@Override
Color getColor(String color) {
if(color == null){
return null;
}
else if(color.equalsIgnoreCase("RED")){
return new Red();
}else if(color.equalsIgnoreCase("GREEN")){
return new Green();
}else if(color.equalsIgnoreCase("BLUE")){
return new Blue();
} else
{
return null;
}
}
}
public class FactoryProducer {
public static AbstractFactory getFactory(String choice){
if(choice.equalsIgnoreCase("SHAPE")){
return new ShapeFactory();
}else if(choice.equalsIgnoreCase("COLOR")){
return new ColorFactory();
}
return null;
}
}


public class AbstractFactoryPatternDemo {
   public static void main(String[] args) {
      AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
      Shape shape1 = shapeFactory.getShape("CIRCLE");
      shape1.draw();

      Shape shape2 = shapeFactory.getShape("RECTANGLE");
      shape2.draw();
      Shape shape3 = shapeFactory.getShape("SQUARE");
      shape3.draw();

      AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
      Color color1 = colorFactory.getColor("RED");
      color1.fill();
      Color color2 = colorFactory.getColor("Green");
      color2.fill();
      Color color3 = colorFactory.getColor("BLUE");
      color3.fill();
   }
}

What is the difference between factory design patterns and abstract factory design patterns?
Both are creational design patterns. Factory pattern is said to be there if there is a method in a class that is used to create class instances. Any class can have factory methods. Using abstract factory patterns, an instance of a class is created that has only factory methods.

I will soon upload Part 4 of Java Design Pattern Interview Questions & Answers in which we will try to implement other popular design patterns.

If you enjoy our content and want to support us, please consider donating via gpay, phonepay or paytm on +91 9920600280. Also, I’d appreciate it if you’d buy me a coffee☕ 

https://www.buymeacoffee.com/greekykhs


Keep learning and growing!
-K Himaanshu Shuklaa..

No comments:

Post a Comment