Factory pattern of Java 23 design pattern series (common)

Posted by nabeelkhan on Tue, 08 Feb 2022 13:30:01 +0100

1, Overview

Factory Pattern is one of the most commonly used design patterns in Java. This type of design pattern is a creation pattern, which provides the best way to create objects.

In factory mode, when creating objects, we do not expose the creation logic to the client, and point to the newly created objects by using a common interface.

As the name suggests, factory is to create products. According to whether the products are specific products or specific factories, it can be divided into simple factory mode and factory method mode. According to the degree of abstraction of factories, it can be divided into factory method mode and abstract factory mode. This pattern is used to encapsulate and manage the creation of objects.

Core essence:

Replace the factory method with new.

The implementation class will be selected to create objects for unified management and control. This decouples the caller from our implementation class.

effect:

It realizes the separation of creator and caller

Classification:

Simple factory mode: used to produce any product with the same level structure (for adding new products, the existing code needs to be overwritten)

Factory method mode: it is used to produce fixed products in the same hierarchical structure (any product can be added)

Abstract factory pattern: create other factories around one super factory. The super factory is also known as the factory of other factories.

Meet three of the seven principles of OOP:

Opening and closing principle: open to expansion and close to modification (reduce new risks caused by maintenance)

Dependency Inversion Principle: the high level should not rely on the low level, but should be interface oriented programming (which is more conducive to the upgrading and expansion of code structure)

Dimitri's Law: don't know what you shouldn't know. A class should keep the least understanding of other objects and reduce the degree of coupling

(only communicate with friends and don't talk to strangers to reduce code bloat)

The overview is not easy to understand, so we can more intuitively understand the differences between these modes through the code

1. Simple factory mode (static factory mode)

Abstractcar abstract class

public interface Car {
    void name();
}

Make cars

 public class Wuling implements Car {
    @Override
    public void name() {
        System.out.println("Wuling Hongguang");
    }
}
 public class Tesla implements Car {
    @Override
    public void name() {
        System.out.println("Tesla");
    }
}

CarFactory: Automobile OEM

public class CarFactory {
    public static getCar(String car) {
        if(car.equals("Wuling")){
            return new Wuling();
        }
        else if(Tesla.equals("Tesla")) {
            return new Tesla();
        }
        return null;
    }
}

Demo:

public class Demo {
    public static void main(String[] arg) {
        Car car=CarFatory.getCar("Wuling");
        Car car2=CarFatory.getCar("Tesla");
        car.name();
        car2.name();
    }
}

2. Factory method mode

Abstractcar abstract class

public interface Car {
    void name();
}
//Factory method model
public interface CarFactory {
    Car getCar();
}

Make cars

 public class Wuling implements Car {
    @Override
    public void name() {
        System.out.println("Wuling Hongguang");
    }
}
 public class Tesla implements Car {
    @Override
    public void name() {
        System.out.println("Tesla");
    }
}

CarFactory: Automobile OEM

public class TeslaFactory implements CarFactory {
    @Override
    public Car getCar(){
        return new Tesla();
    }
}
public class TeslaFactory implements CarFactory {
    @Override
    public Car getCar(){
        return new Wuling();
    }
}

 

Demo:

public class Demo {
    public static void main(String[] arg) {
        Car car=new WulingFatory.getCar();
        Car car2=new TeslaFatory.getCar();
        car.name();
        car2.name();
    }
}

Comparison between simple factory mode and factory method mode (summary)

The complexity of structure, code, programming and management is simple, and the factory mode is better.

Simple factory mode: although it does not conform to the design principles to some extent, it is actually used most

Factory method mode: extend by adding new factory classes without modifying existing classes

3. Abstract factory mode

We will create the # Shape # and # Color # interfaces and entity classes that implement these interfaces. The next step is to create the abstract factory class {AbstractFactory. Then define the factory classes , ShapeFactory , and , ColorFactory, both of which extend , AbstractFactory. Then create a factory creator / generator class, FactoryProducer.

The AbstractFactoryPatternDemo # class uses # FactoryProducer # to obtain # AbstractFactory # objects. It will pass the Shape information to # AbstractFactory # Shape (CIRCLE / RECTANGLE / SQUARE) to get the type of object it needs. At the same time, it also passes the Color information # Color (RED / GREEN / BLUE) to # AbstractFactory # in order to obtain the type of object it needs.

 

Step 1

Create an interface for the shape

public interface Shape {
   void draw();
}

Create an entity class that implements the interface.

Rectangle.java

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.");
   }
}

Step 3

Create an interface for the color.

public interface Color {
   void fill();
}

Step 4

Create an entity class that implements the interface.

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.");
   }
}

Step 5

Create abstract classes for Color and Shape objects to get factories.

public abstract class AbstractFactory {
   public abstract Color getColor(String color);
   public abstract Shape getShape(String shape);
}

Step 6

Create a factory class that extends AbstractFactory and generate the object of entity class based on the given information.

public class ShapeFactory extends AbstractFactory {
    
   @Override
   public Shape getShape(String shapeType){
      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
   public Color getColor(String color) {
      return null;
   }
}
public class ColorFactory extends AbstractFactory {
    
   @Override
   public Shape getShape(String shapeType){
      return null;
   }
   
   @Override
   public Color getColor(String color) {
      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;
   }
}

Step 7

Create a factory creator / generator class to get the factory by passing shape or color information.

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;
   }
}

Step 8

Use FactoryProducer to obtain AbstractFactory and obtain the object of entity class by passing type information.

public class AbstractFactoryPatternDemo {
   public static void main(String[] args) {
 
      //Get shape factory
      AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
 
      //Gets an object with the shape Circle
      Shape shape1 = shapeFactory.getShape("CIRCLE");
 
      //Call Circle's draw method
      shape1.draw();
 
      //Gets an object with a rectangular shape
      Shape shape2 = shapeFactory.getShape("RECTANGLE");
 
      //Call the draw method of Rectangle
      shape2.draw();
      
      //Gets an object with the shape Square
      Shape shape3 = shapeFactory.getShape("SQUARE");
 
      //Call Square's draw method
      shape3.draw();
 
      //Get color factory
      AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
 
      //Get the object with Red color
      Color color1 = colorFactory.getColor("RED");
 
      //Call Red's fill method
      color1.fill();
 
      //Gets the object with the color Green
      Color color2 = colorFactory.getColor("Green");
 
      //Call Green's fill method
      color2.fill();
 
      //Gets an object with Blue color
      Color color3 = colorFactory.getColor("BLUE");
 
      //Call Blue's fill method
      color3.fill();
   }
}

Step 9

Execute the program and output the results:

Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.
Inside Red::fill() method.
Inside Green::fill() method.
Inside Blue::fill() method.

Topics: Java Singleton pattern