Java Factory Pattern Explained
What is the most usual method of creating an instance of a class in java? Most people will answer this question: “using new keyword“. Well, it is considered old-fashioned now. Let’s see how??
If object creation code is spread in the whole application, and if you need to change the process of object creation then you need to go in each and every place to make necessary changes. After finishing this article, while writing your application, consider using the Java factory pattern.
In my previous post, “Singleton design pattern in java“, we discussed various ways to create an instance of a class such that there can not exist another instance of same class in same JVM.
In this post, I will demonstrate another creational pattern, i.e. Factory pattern, for creating instances for your classes. Factory, as the name suggests, is a place to create some different products which are somehow similar in features yet divided into categories.
In Java, factory pattern is used to create instances of different classes of the same type.
Table of Contents 1. When to implement factory pattern? 2. Factory Pattern Implementation 3. Advantages of factory pattern 4. Final notes
1. When to use factory pattern?
Factory pattern introduces loose coupling between classes which is the most important principle one should consider and apply while designing the application architecture. Loose coupling can be introduced in application architecture by programming against abstract entities rather than concrete implementations. This not only makes our architecture more flexible but also less fragile.
A picture is worth a thousand words. Let’s see how a factory implementation will look like.
Above class-diagram depicts a common scenario using an example of a car factory which is able to build 3 types of cars i.e. small, sedan and luxury. Building a car requires many steps from allocating accessories to final makeup. These steps can be written in programming as methods and should be called while creating an instance of a specific car type.
If we are unfortunate then we will create instances of car types (e.g. SmallCar ) in our application classes and thus we will expose the car building logic to the outside world and this is certainly not good. It also prevents us in making changes to car making process because the code is not centralized, and making changes in all composing classes seems not feasible.
2. Java Factory Pattern Example
So far we have design the classes need to be designed for making a CarFactory. Let’s create them now.
2.1. Object types
CarType will hold the types of car and will provide car types to all other classes.
package designPatterns.creational.factory; public enum CarType
2.2. Object implementations
Car is parent class of all car instances and it will also contain the common logic applicable in car making of all types.
package designPatterns.creational.factory; public abstract class Car < public Car(CarType model) < this.model = model; arrangeParts(); >private void arrangeParts() < // Do one time processing here >// Do subclass level processing in this method protected abstract void construct(); private CarType model = null; public CarType getModel() < return model; >public void setModel(CarType model) < this.model = model; >>
LuxuryCar is concrete implementation of car type LUXURY .
package designPatterns.creational.factory; public class LuxuryCar extends Car < LuxuryCar() < super(CarType.LUXURY); construct(); >@Override protected void construct() < System.out.println("Building luxury car"); // add accessories >>
SmallCar is concrete implementation of car type SMALL .
package designPatterns.creational.factory; public class SmallCar extends Car < SmallCar() < super(CarType.SMALL); construct(); >@Override protected void construct() < System.out.println("Building small car"); // add accessories >>
SedanCar is concrete implementation of car type SEDAN .
package designPatterns.creational.factory; public class SedanCar extends Car < SedanCar() < super(CarType.SEDAN); construct(); >@Override protected void construct() < System.out.println("Building sedan car"); // add accessories >>
2.3. Factory to create objects
CarFactory.java is our main class implemented using factory pattern. It instantiates a car instance only after determining its type.
package designPatterns.creational.factory; public class CarFactory < public static Car buildCar(CarType model) < Car car = null; switch (model) < case SMALL: car = new SmallCar(); break; case SEDAN: car = new SedanCar(); break; case LUXURY: car = new LuxuryCar(); break; default: // throw some exception break; >return car; > >
2.4. Test factory pattern
In TestFactoryPattern , we will test our factory code. Lets run this class.
package designPatterns.creational.factory; public class TestFactoryPattern < public static void main(String[] args) < System.out.println(CarFactory.buildCar(CarType.SMALL)); System.out.println(CarFactory.buildCar(CarType.SEDAN)); System.out.println(CarFactory.buildCar(CarType.LUXURY)); >>
Building small car designPatterns.creational.factory.SmallCar@7c230be4 Building sedan car designPatterns.creational.factory.SedanCar@60e1e567 Building luxury car designPatterns.creational.factory.LuxuryCar@e9bfee2
As you can see, the factory is able to return any type of car instance it is requested for. It will help us in making any kind of changes in car making process without even touching the composing classes i.e. classes using CarFactory .
3. Benefits of factory pattern
By now, you should be able to count the main advantages of using the factory pattern. Let’s note down:
- The creation of an object precludes its reuse without significant duplication of code.
- The creation of an object requires access to information or resources that should not be contained within the composing class.
- The lifetime management of the generated objects must be centralized to ensure a consistent behavior within the application.
Factory pattern is most suitable where there is some complex object creation steps are involved. To ensure that these steps are centralized and not exposed to composing classes, factory pattern should be used. We can see many realtime examples of factory pattern in JDK itself e.g.
I hope, I have included enough information in this Java factory pattern example to make this post informative.
If you still have some doubt on abstract factory design pattern in Java, please leave a comment. I will be happy to discuss with you.
What is an object factory in java
This interface represents a factory for creating an object. The JNDI framework allows for object implementations to be loaded in dynamically via object factories. For example, when looking up a printer bound in the name space, if the print service binds printer names to References, the printer Reference could be used to create a printer object, so that the caller of lookup can directly operate on the printer object after the lookup. An ObjectFactory is responsible for creating objects of a specific type. In the above example, you may have a PrinterObjectFactory for creating Printer objects. An object factory must implement the ObjectFactory interface. In addition, the factory class must be public and must have a public constructor that accepts no parameters. Note that in cases where the factory is in a named module then it must be in a package which is exported by that module to the java.naming module. The getObjectInstance() method of an object factory may be invoked multiple times, possibly using different parameters. The implementation is thread-safe. The mention of URL in the documentation for this class refers to a URL string as defined by RFC 1738 and its related RFCs. It is any string that conforms to the syntax described therein, and may not always have corresponding support in the java.net.URL class or Web browsers.
Method Summary
Method Detail
getObjectInstance
Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception
- If obj is null, create a context for resolving URLs of the scheme associated with this factory. The resulting context is not tied to a specific URL: it is able to handle arbitrary URLs with this factory’s scheme id. For example, invoking getObjectInstance() with obj set to null on an LDAP URL context factory would return a context that can resolve LDAP URLs such as «ldap://ldap.wiz.com/o=wiz,c=us» and «ldap://ldap.umich.edu/o=umich,c=us».
- If obj is a URL string, create an object (typically a context) identified by the URL. For example, suppose this is an LDAP URL context factory. If obj is «ldap://ldap.wiz.com/o=wiz,c=us», getObjectInstance() would return the context named by the distinguished name «o=wiz, c=us» at the LDAP server ldap.wiz.com. This context can then be used to resolve LDAP names (such as «cn=George») relative to that context.
- If obj is an array of URL strings, the assumption is that the URLs are equivalent in terms of the context to which they refer. Verification of whether the URLs are, or need to be, equivalent is up to the context factory. The order of the URLs in the array is not significant. The object returned by getObjectInstance() is like that of the single URL case. It is the object named by the URLs.
- If obj is of any other type, the behavior of getObjectInstance() is determined by the context factory implementation.
The name and environment parameters are owned by the caller. The implementation will not modify these objects or keep references to them, although it may keep references to clones or copies.
Name and Context Parameters. The name and nameCtx parameters may optionally be used to specify the name of the object being created. name is the name of the object, relative to context nameCtx . If there are several possible contexts from which the object could be named — as will often be the case — it is up to the caller to select one. A good rule of thumb is to select the «deepest» context available. If nameCtx is null, name is relative to the default initial context. If no name is being specified, the name parameter should be null. If a factory uses nameCtx it should synchronize its use against concurrent access, since context implementations are not guaranteed to be thread-safe.
Report a bug or suggest an enhancement
For further API reference and developer documentation see the Java SE Documentation, which contains more detailed, developer-targeted descriptions with conceptual overviews, definitions of terms, workarounds, and working code examples.
Java is a trademark or registered trademark of Oracle and/or its affiliates in the US and other countries.
Copyright © 1993, 2023, Oracle and/or its affiliates, 500 Oracle Parkway, Redwood Shores, CA 94065 USA.
All rights reserved. Use is subject to license terms and the documentation redistribution policy.