Home > DeveloperSection > Articles > JAVA - AbstractFactory Pattern

JAVA - AbstractFactory Pattern


Java Java 
Ratings:
0 Comment(s)
 848  View(s)
Rate this:

Abstract Factory Pattern  


Previously we learn JAVA - Factory Pattern

 

The Abstract Factory is known as a creational pattern - it's used to construct objects such that they can be decoupled from the implementing system.



The pattern is best utilized when your system has to create multiple families of products or you want to provide a library of products without exposing the implementation details. As you'll have noticed, a key characteristic is that the pattern will decouple the concrete classes from the client.

 

Provides an interface for creating families of related or dependent objects without specifying their concrete classes.



The AbstractFactory class is the one that determines the actual type of the concrete object and creates it, but it returns an abstract pointer to the concrete object just created. 

 

One of the main benefits of this pattern is that the client is totally decoupled from the concrete products. Also, new product families can be easily added into the system, by just adding in a new type of ConcreteFactory that implements AbstractFactory, and creating the specific Product implementations.

 

Implementing an Example:

We are going to create a Shape and Color interfaces and concrete classes implementing these interfaces. We create an abstract factory class AbstractFactory. Factory classes ShapeFactory and ColorFactory are defined where each factory extends AbstractFactory. A factory creator/generator class FactoryProducer is created.



Our demo class uses FactoryProducer to get a AbstractFactory object. It will pass information (CIRCLE / RECTANGLE / SQUARE for Shape) to AbstractFactory to get the type of object it needs. It also passes information (RED / GREEN / BLUE for Color) to AbstractFactory to get the type of object it needs.

 

 

          Create an interface for Shapes.

      // Shape.java

       public interface Shape{

   void draw();

}

         

Create concrete classes implementing the same interface.

// Circle.java

public class Circle implements Shape{

   @Override

   public void draw(){

         // TODO Auto-generated method stub

         System.out.println("Inside Circle: draw() method.");

   }

}

// Square.java

public class Square implements Shape{

   @Override

   public void draw(){

         // TODO Auto-generated method stub

         System.out.println("Inside Square: draw() method."); 

   }

}

// Rectangle.java

public class Rectangle implements Shape{

   @Override

   public void draw(){

         // TODO Auto-generated method stub

         System.out.println("Inside Rectangle: draw() method.");

   }    

}

          Create an interface for Colors.

// Color.java

public interface Color{

   void fill();

}

          Create concrete classes implementing the same interface.

// Blue.java

public class Blue implements Color{

   @Override

   public void fill() {

         // TODO Auto-generated method stub

         System.out.println("Inside Blue: fill() method.");

   }

}

// Green.java

public class Green implements Color{

   @Override

   public void fill() {

         // TODO Auto-generated method stub

         System.out.println("Inside Green: fill() method.");

   }

}

// Red.java

public class Red implements Color{

   @Override

   public void fill() {

         // TODO Auto-generated method stub

         System.out.println("Inside Red: fill() method.");

   }

}

          Create an Abstract class to get factories for Color and Shape Objects.

// AbstractFactory

public abstract class AbstractFactory{

   abstract Shape getShape(String shape);

   abstract Color getColor(String color);

} 

          Create Factory classes extending AbstractFactory to generate object of concrete class based on given information.

// ShapeFactory.java

public class ShapeFactory extends AbstractFactory{

   @Override

   Shape getShape(String shapeType) {

         // TODO Auto-generated method stub

         if(shapeType == null){

               return null;

         }        

         if(shapeType.equalsIgnoreCase("CIRCLE")){

               return new Circle();

         }else if(shapeType.equalsIgnoreCase("RECTANGLE")){

               return new Rectangle();

         }else if(shapeType.equalsIgnoreCase("SQUARE")){

               return new Square();

         }       

         return null;

   }      

   @Override

   Color getColor(String color) {

         // TODO Auto-generated method stub

         return null;

   }

}

// ColorFactory.java

public class ColorFactory extends AbstractFactory{

   @Override

   Shape getShape(String shape) {

         // TODO Auto-generated method stub

         return null;

   } 

   @Override

   Color getColor(String color) {

         // TODO Auto-generated method stub     

         if(color == null){

               return null;

         }        

         if(color.equalsIgnoreCase("RED")){

               return new Red();

         }else if(color.equalsIgnoreCase("GREEN")){

               return new Green();

         }else if(color.equalsIgnoreCase("BLUE")){

               return new Blue();

         }        

         return null;

   }

}

          Create a Factory generator/producer class to get factories by passing an information such as Shape or Color

// FactoryProducer

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;

   }

} 

          Use the FactoryProducer to get AbstractFactory in order to get factories of concrete classes by passing an information such as type.

// AbstractFactoryPatternDemo.java

public class AbstractFactoryPatternDemo {

   public static void main(String[] args){    

         //.......get shape factory........

         AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");        

         // get an object of Shape Circle

         Shape shape1 = shapeFactory.getShape("CIRCLE");

         // call draw method of Shape Circle

         shape1.draw();        

         // get an object of Shape Rectangle

         Shape shape2 = shapeFactory.getShape("RECTANGLE");

         // call draw method of Shape Rectangle

         shape2.draw();        

         // get an object of Shape Square

         Shape shape3 = shapeFactory.getShape("SQUARE");

         // call draw method of Shape Square

         shape3.draw();        

         //.........get color factory..........

         AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");        

         //get an object of Color Red

         Color color1 = colorFactory.getColor("RED");

         // call fill method of Red

         color1.fill();        

         //get an object of Color Green

         Color color2 = colorFactory.getColor("GREEN");

         // call fill method of Green

         color2.fill();        

         //get an object of Color Blue

         Color color3 = colorFactory.getColor("BLUE");

         // call fill method of Blue

         color3.fill();

   }

}

          Verify the output. 

 

Watch Out for the Downsides:


While the pattern does a great job of hiding implementation details from the client, there is always a chance that the underlying system will need to change. We may have new attributes to our AbstractProduct, or AbstractFactory, which would mean a change to the interface that the client was relying on, thus breaking the API.


Don't want to miss updates? Please click the below button!

Follow MindStick