jDataLab

4 minute read

One of the goals in object-oriented design is to delegate responsibility among different objects. This kind of distribution is good as it reflects two important features in object oriented methodology, encapsulation and delegation.

Often, we find ourselves in one of the following situations that needs a solution.

  • An application (or framework) at runtime, is incapable of anticipating the class of object/instance. The application may know that it has to instantiate classes, but it only knows about abstract classes (or interfaces) that cannot instantiate.

    PROBLEM: The Application class only knows when it has to instantiate a new Object of an abstract class, but not the specific type of subclass.

  • A superclass may require its subclasses to specify the Objects to be created at the creation time.

  • A class may delegate responsibility to one of several assisting subclasses so that services can be distributed locally to specific subclasses.

The solution to the previous problem is a creational pattern, namely Factory Method.

A design pattern is a description or template for how to solve a problem that can be used in many different situations.

The Factory Method contains an interface which lets the subclasses decide at creation time which subclass to instantiate.

This pattern is named as a factory as it is responsible for manufacturing an Object. A factory does not make an Object. To make a new Object, we make a simple call to new. (Read [“Java Review: Instantiation w/ the Keyword New”]( {{site.url}}{{site.baseurl}}{% post_url 2017-01-10-java-instantiation-new %} ).

However, the Factory pattern promotes loose coupling by eliminating the need to bind application-specific classes into the code. The use of factories in the code facilitates delegation of specific attributes of an object into specific subclasses. Therefore, the Factory pattern helps make a system independent of how objects are created.

“The Factory Method lets a class defer instantiation to subclasses.”

Diagram credit: Object-oriented systems analysis and design by Noushin Ashrafi

The example is based on Java. In this example, upon receiving the user choice of geometric shape, either Circle or Rectangle, the factory interface will defer the instantiation to the associated subclass.

Class Diagram

The following class diagram shows the structure of the classes and interface.

Their signatures are displayed in the following.

The Factory interface ShapeProcessor

ShapeProcessor is a factory interface, only containing a group of related methods with empty bodies.

1	public interface ShapeProcessor 

The superclass Shape

Shape contains the common properties and operations that are shared among its subclasses, Circle and Rectangle.

1	public class Shape

The subclass Circle that implements ShapeProcessor and extends Shape

Circle extends Shape to inherit all the members from Shape, and implements ShapeProcessor for its abstract methods.

1	public class Circle extends Shape implements ShapeProcessor

The subclass Rectangle that implements ShapeProcessor and extends Shape

Rectangle extends Shape to inherit all the members from Shape, and implements ShapeProcessor for its abstract methods.

1	public class Rectangle extends Shape implements ShapeProcessor

A factory interface only contains a group of related methods with empty bodies. An interface method is separate from its implementation. The subclasses will be responsible for implementing the interfaces.

Both classes and interfaces can be organized into a package (a namespace).

The following is an implementation of the Factory interface ShapeProcessor by using the keyword interface. Noticeably, the interface class can also contain the constants.

 1package interfaces;
 2
 3public interface ShapeProcessor {
 4
 5    static final double PI = 3.14159;
 6
 7    public void setFillColor(int redVal, int greenVal, int blueVal);
 8
 9    public double calcArea();
10
11    public double calcCircumference();
12
13}

With the class structure in the example, we can declare new objects and instantiate them in an Application class (Main Class) in the main method.

  • Declare a new object of the Factory Interface type.

  • Instantiate the new object by calling the constructor of the required subclass.

An example is given below for a sample main method.

 1    public static void main(String[] args) {
 2
 3        ShapeProcessor myshape = null; // Declare a ShapeProcessor object
 4
 5        String input = JOptionPane.showInputDialog(null, "Enter either circle or rectangle:", "Select a shape", 0);
 6
 7        switch (input) {
 8            case "circle": // delegate instantiation to subclass Circle                
 9                myshape = new Circle(5.6);
10                break;
11            case "rectangle": // defer instantiation to subclass Rectangle
12                myshape = new Rectangle(3.2, 5.1);
13                break;
14            default:
15        }
16
17        if (myshape != null) {
18            double area = myshape.calcArea();
19            JOptionPane.showMessageDialog(null, "Your " + input + " has an area of " + area + ".", "The area of your shape", 0);
20        } else {
21            JOptionPane.showConfirmDialog(null, input + "Sorry. Your choice doesn't exist in the system. Contact us.", null, 0);
22        }
23       
24
25    }// End of Main method

The sample code is provided to help you understand the Factory method, in the following five class files.

  • Factory Interface: ShapeProcessor

You can view the sample code: ShapeProcessor.java

  • Superclass: Shape

You can view the sample code: Shape.java

  • Subclass 1: Circle

You can view the sample code: Circle.java

  • Subclass 2: Rectangle

You can view the sample code: Rectangle.java

  • Application Class: Draw

You can view the sample code: Draw.java