How it Works

  1. We have JSON file with Location and Name of Factory Class
  2. Using Configuration.java we read the JSON File and read the Configuration
  3. We run TasteFoodFromMenu.java by supplying the JSON file Location as Input
  4. Now by the above method the JAR’s could be built independently and by changing the JSON file we could make changes and deploy the code without restarting the Server

For more detail refer here

Configuration.java

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;

import com.fasterxml.jackson.databind.ObjectMapper;

public class Configuration {

    public static Configuration loadConfiguration(String fileName) throws IOException {    	
    	//Read Name of File
        Path path = FileSystems.getDefault().getPath(fileName);
        
        //Read Contents of File
        String contents = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
        
        ObjectMapper mapper = new ObjectMapper();
        
        //Map Location and FactoryType
        Configuration config = mapper.readValue(contents, Configuration.class);
        return config;
    }

    private String factoryType;
    private String location;


    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public String getFactoryType() {
        return factoryType;
    }

    public void setFactoryType(String factoryType) {
        this.factoryType = factoryType;
    }
}

TasteFoodFromMenu.java

public class TasteFoodFromMenu {
	  public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
	        Configuration configuration = Configuration.loadConfiguration(args[0]);
	        String location = configuration.getLocation();
	        URL url = new URL(location);
	        URLClassLoader ucl = new URLClassLoader(new URL[]{url});
	        Class<IFoodFactory> cls = (Class<IFoodFactory>) Class.forName(configuration.getFactoryType(), true, ucl);
	        IFoodFactory cameraFactory = cls.newInstance();
	        IFood camera = cameraFactory.prepareFood(); 
	        camera.serveFood();
	    }
}

config.json

{
  "factoryType": "com.mugil.food.ChineseFoodFactory",
  "location": "file:///D:/java/ReadConfFromJSON/lib/FoodMenu.jar"
}

Abstract Factory Pattern
The Abstract Factory Pattern consists of an AbstractFactory, ConcreteFactory, AbstractProduct, ConcreteProduct and Client. We code against AbstractFactory and AbstractProduct and let the implementation to others to define ConcreteFactory and ConcreteProduct

IFoodFactory.java(AbstractFactory)

public interface IFoodFactory {
	public IFood prepareFood();
}

IFood.java(AbstractProduct)

public interface IFood {
	public void serveFood();
}

ItalianFoodFactory.java(ConcreteFactory)

public class ItalianFoodFactory implements IFoodFactory{
	@Override
	public IFood prepareFood() {
		return new ItalianFood();
	}
}

ChineseFoodFactory.java(ConcreteFactory)

public class ChineseFoodFactory implements IFoodFactory{
	@Override
	public IFood prepareFood() {
		return new ChineseFood();
	}
}

ItalianFood.java(ConcreteProduct )

public class ItalianFood implements IFood{
	@Override
	public void serveFood() {
	  System.out.println("Pepperoni Pizza by Sam");		
	}
}

ChineseFood.java(ConcreteProduct )

public class ChineseFood implements IFood{
	@Override
	public void serveFood() {
		System.out.println("Snake Soup by Bruce");;
	}		
}

TasteFood.java(Client)

public class TasteFood {
	public static void main(String[] args) {
		IFoodFactory objFoodFactory = new ChineseFoodFactory();
		IFood objFood = objFoodFactory.prepareFood();		
		objFood.serveFood();
	}
}

Output

Snake Soup by Bruce

With the Factory pattern, you produce instances of implementations (ChineseFood, ItalianFood, ThaiFood, etc.) of a particular interface — say, IFood.
With the Abstract Factory pattern, you provide a way for anyone to provide their own factory. This allows your warehouse to be either an IFoodFactory or an IJuiceFactory, without requiring your warehouse to know anything about Food or Juices.Abstract Factory pattern, a class delegates the responsibility of object instantiation to another object via composition whereas the Factory Method pattern uses inheritance and relies on a subclass to handle the desired object instantiation.

Factory Pattern Abstract Factory pattern
Factory Method creates objects through inheritance Abstract Factory creates objects through composition
Factory Method pattern is responsible for creating products that belong to one family Abstract Factory pattern deals with multiple families of products i.e. Food, Juice, Dessert
Factory Method uses interfaces and abstract classes to decouple the client from the generator class and the resulting products Abstract Factory has a generator that is a container for several factory methods, along with interfaces decoupling the client from the generator and the products

Download example of Abstract Factory pattern from here

Define an interface or abstract class for creating an object but let the Sub class decide which class to instantiate.

Required

  1. Interface under which the object can be mocked
  2. Different class that should instantiated using Interface Reference
  3. Class with main() method which starts the whole process

Interface
AccountFactory.java

package com.mugil.factory;
public interface AccountFactory 
{	
  void calculateInterest();
}

Different classes
CurrentAccount.java

public class CurrentAccount implements AccountFactory 
{
  @Override
  public void calculateInterest() 
  {
    System.out.println("Interest Calculation for Current Account");
  }
}

RecurringDepositAccount.java

public class RecurringDepositAccount implements AccountFactory 
{
  @Override
  public void calculateInterest() 
  {
    System.out.println("Interest Calculation for Recurring Deposit");
  }
}

SavingsAccount.java

public class SavingsAccount implements AccountFactory 
{
  @Override
  public void calculateInterest() 
  {
    System.out.println("Interest Calculation for Savings Account");
  }
}

Class with main() method
CalculateInterest.java

public class CalculateInterest 
{	
  public static void main(String[] args) 
  {	
    //Received at Runtime
    String accountType = "SAV";
		
    AccountFactory objAccountFactory =  null;
		
    if(accountType.equals("SAV"))
    {
	objAccountFactory = new SavingsAccount();
    }
    else if(accountType.equals("REC"))
    {
	objAccountFactory = new RecurringDepositAccount();
    }
    else if(accountType.equals("CUR"))
    {
	objAccountFactory = new CurrentAccount();
    }
		
	objAccountFactory.calculateInterest();
   }
}

When to use factory methods?