Design Patterns (7 Blogs)

Design Pattern Exposed: Factory Pattern

Last updated on May 22,2019 9.4K Views


Welcome to the second post of Design Patterns exposed series. In this post we’ll uncover Factory Pattern. Factory pattern comes under Creational Pattern category.

What is a Creational Pattern?

Creational Patterns are concerned with object creation problems faced during software design. Many a time object creation results in design problems, creational patterns solve this problem by controlling the object creation.

Let`s understand the problem first then we will solve the problem using Factory Pattern.

Consider the below UML diagram , where we have cake abstract class and concrete sub-classes BlackForest, LitchiGateaux, BlueBerry, Pineapple.

Class Diagram

Let’s see what goes inside these classes. Cake is the abstract class, all different cake classes inherit from this class. Cake class has three properties; name of the cake, type of the cake (whether cake contains egg or it is egg less) and the last one is price.

Cake.Java

package co.edureka;

public abstract class Cake {

	String name;
	String type;
	int price;

	public String getName(){
		return name;
	}
	public String getType(){
		return type;
	}
	public int getPrice(){
		return price;
	}
	public void setName(String name){
		this.name=name;
	}
	public void setPrice(int price){
		this.price=price;
	}
	public void setType(String type){
		this.type=type;
	}

	public abstract void recipe();
	public abstract void myFans();
	public void aboutCake(){
		System.out.println("I am "+name+" Cake");
		System.out.print("My Fans  : ");
		myFans();
		System.out.println("You can get a "+name+" Cake at "+price);
	}
}

Let’s see some of the sub-classes of cake

BlackForest.Java

package co.edureka;

public class BlackForest extends Cake {

	public BlackForest(){
		setName("Black Forest");
		setType("Eggless");
		setPrice(800);
	}

	public void recipe() {
	    System.out.println("---BlackForest Recipe---");
	    System.out.println("Sieve together Maida and Cocoa powder");
	    System.out.println("Add Milk and Vanilla essence");
	    System.out.println("Top with Whipped Cream and Cherries");
	    System.out.println("Chill and Serve");

	}

	public void myFans() {
		System.out.println("Both adults and Kids love me");

	}

}

BlueBerry.Java

package co.edureka;

public class BlueBerry extends Cake {

	BlueBerry(){
		setName("Blue Berry");
		setType("Egg");
		setPrice(700);
	}

	public void recipe() {
	System.out.println("---BlueBerry Recipe---");
	System.out.println("First prepare Flour and Baking powder mixture");
	System.out.println("Add Milk and Egg yolks");
	System.out.println("Coat Berries");
	System.out.println("Bake for 50 minutes");

	}

	public void myFans() {
		 System.out.println("Moms love me");

	}

}

LitchiGateaux.Java

package co.edureka;

public class LitchiGateaux extends Cake {

	LitchiGateaux(){
		setName("Litchi Gateaux");
		setType("Eggless");
		setPrice(750);
	}

	public void recipe() {
		System.out.println("---LitchiGateaux Recipe---");
		System.out.println("Take some fresh Litchies");
		System.out.println("Wash them and Grind for 5 minutes");
		System.out.println("Put some groundnuts and bake for 45 minutes");
	}

	public void myFans() {
       System.out.println("Litchi lovers love me");
	}

}

Now we are all set to create different types of cakes.

CakeTest.Java

package co.edureka;

import java.util.Scanner;

public class CakeTest {

	public static void main(String args[]) {

		Cake cake = null;

		System.out.println("Which Cake you would like to eat ");
		Scanner scanner = new Scanner(System.in);
		String choice = scanner.nextLine();
		scanner.close();

		if (choice.equals("BlackForest")) {
			cake = new BlackForest();
		} 
		else if (choice.equals("BlueBerry")) {
			cake = new BlueBerry();
		} 
		else if (choice.equals("LitchiGateaux")) {
			cake = new LitchiGateaux();
		} 
		else if(choice.equals("Pineapple")){
			cake=new Pineapple();
		}

		cake.aboutCake();

	}

}

Notice the code in CakeTest class, we have got several concrete classes BlackForest, BlueBerry, LitchiGateaux, Pineapple being instantiated, and the decision of which class to instantiate is made at run-time depending on the user’s choice.

When you see code like the above and when the time comes for changes or extension, you will have to reopen the code and examine what needs to be added or deleted. Suppose I don’t want to offer pineapple cake, I have to reopen the code and delete some codes. Similarly, if later I decide to add 10 new cake types, I have to reopen the code and type 10 more “else if” statements. Which means your code is not “closed for modifications”.

Note : Your design should always be “open for extension” but “closed for modifications”.

Separate the code that vary

The code in the CakeTest will certainly vary as we decide to delete some cake type or add new cake types.

                if (choice.equals("BlackForest")) {
			cake = new BlackForest();
		} 
		else if (choice.equals("BlueBerry")) {
			cake = new BlueBerry();
		} 
		else if (choice.equals("LitchiGateaux")) {
			cake = new LitchiGateaux();
		} 
		else if(choice.equals("Pineapple")){
			cake=new Pineapple();
		}

There are three big problems with our current design

  • CakeTest class is tightly coupled to cake subclasses, as in the main method we are instantiating one concrete cake class depending on the user’s selection. Which means CakeTest class have knowledge of all sub-classes of cake, which are bad.
  • If we add or delete some cake types we have to modify the code in the main method.
  • There is no code reusability if some other classes also require a particular cake depending on some condition. We have to duplicate the code, which is bad. Wouldn’t it be great if we separate the cake creation code to a separate factory class ?

So, anyone that needs a cake object can directly call factory class.

Now that we have understood the problem in our design, let’s separate the code that vary.

Encapsulating Object Creation

We are going to define a factory interface and a concrete factory class (CakeFactory) that implements factory interface which will encapsulate the object creation code for different types of cakes.

Factory.Java

package co.edureka;

public interface Factory {

	Cake createCake(String cakeName);

}

CakeFactory.Java

package co.edureka;

public class CakeFactory implements Factory{

	public Cake createCake(String cakeName){

		Cake cake=null;

		if (cakeName.equals("BlackForest")) {
			cake = new BlackForest();
		} 
		else if (cakeName.equals("BlueBerry")) {
			cake = new BlueBerry();
		} 
		else if (cakeName.equals("LitchiGateaux")) {
			cake = new LitchiGateaux();
		} 
		else if(cakeName.equals("Pineapple")){
			cake=new Pineapple();
		}
		return cake;
	}

}

Now, let’s see how our CakeTest class is going to change.

CakeTest.Java

package co.edureka;

import java.util.Scanner;

public class CakeTest {

	public static void main(String args[]) {

		Cake cake = null;

		System.out.println("Which Cake you would like to eat BlackForest/BlueBerry/LitchiGateaux/Pineapple : ");
		Scanner scanner = new Scanner(System.in);
		String choice = scanner.nextLine();
		scanner.close();

		CakeFactory cakeFactory=new CakeFactory();
		cake=cakeFactory.createCake(choice);

		cake.aboutCake();

	}

}

By separating the cake creation code in a separate factory class, we get following benefits:

  • Our object creation code is at one place and any class that requires a particular cake type can use factory class. We need not duplicate object creation code at all the places.
  • The classes that requires particular cake object do not require to have knowledge of all cake types. All they need to do is call the method in the factory class passing the argument.
  • Now, our code is dynamic because we can swap in and out different factory implementations. Let’s see how to do that.

Consider this scenario, there is a CakeStore that gets the cake from a cake factory. Using Factory Pattern we can dynamically change the factory from where the CakeStore that gets its cakes.

So let’s do it.

CakeStore.Java

package co.edureka;

public class CakeStore {
	Factory factory;

	CakeStore(Factory factory){
		this.factory=factory;
	}

	public Cake newCakeOrder(String cakeName,String customerName){
		Cake cake;

		cake=factory.createCake(cakeName);

		cake.decorate(customerName);
		cake.packCake();

		return cake;
	}

}

Let’s create a cake factory that is specialized in creating Christmas cakes.

ChristmasCakeFactory.Java

package co.edureka;

public class ChristmasCakeFactory implements Factory {

	public Cake createCake(String cakeName){

		Cake cake=null;

		if(cakeName.equals("Christmas Special Cake")){
			cake =new ChristmasSpecialCake();
		}
		else if(cakeName.equals("Santa Cake")){
			cake =new SantaCake();
		}
		else if(cakeName.equals("Christmas Ice Cake")){
			cake =new ChristmasIceCake();
		}
		else if(cakeName.equals("Merry Christmas Cake")){
			cake =new MerryChristmasCake();
		}

		return cake;
	}

}

Now it’s time to test our code:

ChristmasCakeFactory christmasCakeFactory=new ChristmasCakeFactory();

CakeStore cakeStore=new CakeStore(christmasCakeFactory);

Cake cake=cakeStore.newCakeOrder("Special Christmas Cake", "Alex");

Notice that in above code how we have set the ChristmasCakeFactory for the CakeStore class.

We can dynamically choose the factory from which we want to get Cakes. You can create many different factories like BirthdayCakeFactory, WeddingCakeFactory, CupCakeFactory etc. 

Where Can I See Factory Pattern Implemented?

Factory pattern is used more than a hundred times in Java API. One example is javax.swing.BorderFactory class which has many methods that return a particular border depending on the argument you pass.

AbstractBorder is an abstract class having concrete classes as LineBorder, StrokeBorder, TitledBorder, EmptyBorder, CompoundBorder, BevelBorder,EtchedBorder  etc.

Now, whenever I need to get a particular type of border I will just call one of the several methods available in BorderFactory class. Say, I want to get a TitledBorder object.

There are two ways to get a TitledBorder, one way is to directly instantiate TitledBorder class and the other way is to use the BorderFactory class.

Border border=new TitledBorder("This is the Border Title");

Or

Border border=BorderFactory.createTitledBorder("This is the Border Title");

This is similar to our CakeFactory example. Say If I want to get BlackForestCake, I can do it in two ways.

Cake cake=new BlackForest();

Or

Cake cake=CakeFactory.createCake("BlackForest");

I hope you understood the Factory Pattern and when and how to use it.

As always you can download the code and play with it to make sure you really cement the Factory Pattern in your head. In the next post we’ll uncover Factory Method Pattern, which is also a type of Factory Pattern but offers more flexibility.

In case you have any query regarding Factory Pattern or any other pattern leave your comments below.

Got a question for us? Mention them in the comments section and we will get back to you. 

Related Posts:

Get started with Design patterns

Design Pattern Exposed: Strategy Pattern

Comments
0 Comments

Join the discussion

Browse Categories

webinar REGISTER FOR FREE WEBINAR
REGISTER NOW
webinar_success Thank you for registering Join Edureka Meetup community for 100+ Free Webinars each month JOIN MEETUP GROUP

Subscribe to our Newsletter, and get personalized recommendations.

image not found!
image not found!

Design Pattern Exposed: Factory Pattern

edureka.co