Design Pattern: Factory

Design Pattern: Factory

in

The used examples and notions almost come from OOD Design.

Factory

Intent

  • creates objects without exposing the instantiation logic to the caller
  • refers to the newly created object through a common interface

When to use

a framework delegate the creation of objects derived from a common superclass to the factory - we need flexibility in adding new types of objects that must be created by class

code examples and specific problems

Parameterized Factories

public class ProductFactory{
    public Product createProduct(String ProductID) {
        if (id == ID1) return new ProductOne();
        else if (id == ID2) return new ProductTwo();
        // so on for the other IDs
        return null;// If the ID don't have any associated value
    }
}

The most significant problem to this implementation is that it violates open close principle. If we need more new product classes, we need to change the code in ProductFactory.

Class Registration – using reflection

interface Product {

}

public class ProductOne implements Product {
    //registration done inside the product class
    static {
        Factory.instance().registerProduct("ID1",ProductOne.class);
    }
}

public class ProductTwo implements Product {

}

public class ProductFactory{
    private static final Map<String,Class<? extends Product>> registeredProducts = new HashMap<>();

    public void registerProduct(String productID, Class<? extends Product> productClass) {
        registeredProducts.put(productID,productClass);
    }

    public Product createProduct(String productID) {
        Class<?> productClass = registeredProducts.get(productID);
        Constructor productConstructor = productClass.getDeclaredConstructor(new Class[] {});
        return (Product)productConstructor.newInstance(new Object[] {});
    }
}

class Main {
	static {
		try {
			Class.forName("ProductOne");
			Class.forName("ProductTwo");
		} catch (ClassNotFoundException any) {
			any.printStackTrace();
		}
	}
	public static void main(String args[]) throws ProductNotRegisteredException {
		//...
	}
}

The main drawback of reflection implementation is performance. It could cause a up to 10% performance loss comparing to the non reflection implementations.

Class Registration

abstract class Product {
    public abstract Product createProduct();
}

public class ProductOne extends Product {
    
    static {
        ProductFactory.instance().registerProduct("ID1",ProductOne.class);
    }
    public ProductOne createProduct() {
        return new ProductOne();
    }
}

class ProductFactory {
    private static final Map<String,Class<? extends Product>> registeredProducts = new HashMap<>();
    public void registerProduct(String productID, Product p) {
        registeredProducts.put(productID, p);
    }

    public Product createProduct(String productID) {
        registeredProducts.get(productID).createProduct();
    }
}