Design Pattern factory_pattern

Let’s first look at how java use the factory method.

At beginning, in order to unify all the manipulations on different SQL type databases (i.e MySQL, SQL Server) in java, An unified interface need to be created, this is the reason why JDBC APIs had been created. Our manipulation is based on abstraction, without considering things like how different drivers for distinct SQL server have been implements. Both our client And JDBC API will not consider the details of how a driver would be created. The Driver class is the abstract factory which defines a set of roles how to create a connection. For different SQL server companies. they must implements the driver interface in order to create connections.

This is driver interface.

package java.sql;

import java.util.logging.Logger;

/**
 * The interface that every driver class must implement.
 * <P>The Java SQL framework allows for multiple database drivers.
 *
 * <P>Each driver should supply a class that implements
 * the Driver interface.
 *
 * <P>The DriverManager will try to load as many drivers as it can
 * find and then for any given connection request, it will ask each
 * driver in turn to try to connect to the target URL.
 *
 * <P>It is strongly recommended that each Driver class should be
 * small and standalone so that the Driver class can be loaded and
 * queried without bringing in vast quantities of supporting code.
 *
 * <P>When a Driver class is loaded, it should create an instance of
 * itself and register it with the DriverManager. This means that a
 * user can load and register a driver by calling:
 * <p>
 * {@code Class.forName("foo.bah.Driver")}
 * <p>
 * A JDBC driver may create a {@linkplain DriverAction} implementation in order
 * to receive notifications when {@linkplain DriverManager#deregisterDriver} has
 * been called.
 * @see DriverManager
 * @see Connection
 * @see DriverAction
 */
public interface Driver {

    /**
     * Attempts to make a database connection to the given URL.
     * The driver should return "null" if it realizes it is the wrong kind
     * of driver to connect to the given URL.  This will be common, as when
     * the JDBC driver manager is asked to connect to a given URL it passes
     * the URL to each loaded driver in turn.
     *
     * <P>The driver should throw an <code>SQLException</code> if it is the right
     * driver to connect to the given URL but has trouble connecting to
     * the database.
     *
     * <P>The {@code Properties} argument can be used to pass
     * arbitrary string tag/value pairs as connection arguments.
     * Normally at least "user" and "password" properties should be
     * included in the {@code Properties} object.
     * <p>
     * <B>Note:</B> If a property is specified as part of the {@code url} and
     * is also specified in the {@code Properties} object, it is
     * implementation-defined as to which value will take precedence. For
     * maximum portability, an application should only specify a property once.
     * @param url the URL of the database to which to connect
     * @param info a list of arbitrary string tag/value pairs as
     * connection arguments. Normally at least a "user" and
     * "password" property should be included.
     * @return a <code>Connection</code> object that represents a
     *         connection to the URL
     * @exception SQLException if a database access error occurs or the url is
     * {@code null}
     */
    Connection connect(String url, java.util.Properties info)
        throws SQLException;

    //Other methods.

}

It has very detailed illustration, connect() method is to create a database connection. It is the create method that every abstract factory interface must have. It return A Connection. Connection is abstract product which is created by Driver. As long as clients pass the correct parameters to the Dirver.connect() method, it will give us a object of type connection

How about the connection ? Let us look at the source code of Connection.

package java.sql;

import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * <P>A connection (session) with a specific
 * database. SQL statements are executed and results are returned
 * within the context of a connection.
 * <P>
 */
public interface Connection  extends Wrapper {

    Statement createStatement() throws SQLException;

    PreparedStatement prepareStatement(String sql) throws SQLException;

}

Connection itself is also a abstract factory, it could create prepared statement which can be executed later. That is really convenient for users. they don’t need to consider _concrete_ drivers and _concrete_ connections. As user, we only depends on abstract factories and abstract products. Since we don’t need to consider the concrete products and factories. so that our codes may apply to all subclasses of our abstract products. This can make the client written code reusable. Platform independence is a good example, here, operation system is the abstract class or interface while Linux, Windows, Mac are concrete products.

Java also have many other classes or interfaces use the factory design pattern. (i.e. Thread Pools).

Let’s try to write some small demos to have a deeper understanding of factory method and abstract method.

Understanding factory method and abstract factory by small demos.

If you want to design a UI Container, it has two components, let’s say, alert messages and button. Different component has different event. We want to create both. How can we do that ? what if we want to add a new component to the container ?

Well, we could have a abstract factory called Component Factory, it create abstract component.

Component Factory interface.

package component;

/**
 * Abstract factory: it has the responsibility for creating component
 */
public interface ComponentFactory {
    Component createComponent();
}

Component

package component;

/**
 * Abstract Product: Component
 */
public interface Component {
    void event();
}

Concrete Components. Basically, we have two types of component. One is Button Component and the other one would be AlertMessageComponent. They have their corresponding factory for charge of creation.

ButtonComponent

package component;

/**
 * Concrete product: Confirm Button
 */
public class ConfirmButton implements Component {
    @Override
    public void event() {
        System.out.println("I am a confirm Button, you can click me");
    }
}

ConfirmButtonFactory

package component;

/**
 * Concrete factory for creating confirm button component
 */
public class ConfirmButtonFactory implements  ComponentFactory {
    @Override
    public  Component createComponent() {
        return new ConfirmButton();
    }
}
package component;

/**
 * Concrete factory for creating confirm button component
 */
public class ConfirmButtonFactory implements  ComponentFactory {
    @Override
    public  Component createComponent() {
        return new ConfirmButton();
    }
}

The same for AlertMessageComponent

package component;
/**
 * Concrete product: AlertMessage
 */
public class AlertMessage implements  Component {
    @Override
    public void event() {
        System.out.println("i am a alert Message");
    }
}
/**
 * Concrete Factory for Alert message component
 */
public class AlertMessageFactory implements ComponentFactory {
    @Override
    public Component createComponent() {
        return new AlertMessage();
    }
}

Client-usage code

import component.AlertMessageFactory;
import component.Component;
import component.ConfirmButtonFactory;
import component.ComponentFactory;


public class Main {
    public static void main(String[] args) {
        //Create factory
        ComponentFactory comfirmButtonFactory = new ConfirmButtonFactory();
        ComponentFactory alertMessageFactory = new AlertMessageFactory();

        // create component by the factory
        Component alermsg = alertMessageFactory.createComponent();
        // invoke the method.
        alermsg.event();

        Component button = comfirmButtonFactory.createComponent();
        button.event();

    }
}

Output

I am a confirm Button, you can click me
I am a alert Message

Process finished with exit code 0

We can see that factory method follows the Open-close design principle.If we have new products, in our case, new component, we just need to write two more classes, which are concrete component and concrete factory. And the usage by the client will also follows the same pattern. At the same time, we don’t need to invade other concrete components and other concrete Factory. It makes our code much more scalable and reusable.

What if Each Component has two version. One is displaying for ios , the other one is for android.

First, we need two components to extends those concert components.

IosAlertMessage, MdAlertMessage.

IosConfirmButton, MdConfirmButton.

We will have two more factory. One is called AndroidComponent Factory, the other one is called AlertMessage Factory. They are responsible for creating ios/andriod component.

Now, let us write the code.

In the first place, we could change the factory.

/**
 * Abstract factory: it has the responsibility for creating component
 */
public interface ComponentFactory {
    Component createConfirmButtonComponent();
    Component createAlertMessageComponent();
}

Android Component Factory && IOS component Factory

package component;

public class AndroidComponentFactory implements ComponentFactory {

    @Override
    public Component createConfirmButtonComponent() {
        return new MdConfirmButton();
    }

    @Override
    public Component createAlertMessageComponent() {
        return new MdAlertMessage();
    }
}
package component;
/**
 * Concrete component factory for creating component for Ios system.
 *
 */
public class IosComponentFactory implements  ComponentFactory{

    @Override
    public Component createConfirmButtonComponent() {
        return new IosConfirmButton();
    }

    @Override
    public Component createAlertMessageComponent() {
        return new IosAlertMessage();
    }
}

Concrete components for two operating systems

IosAlertMessage

package component;

public class IosAlertMessage extends AlertMessage {
    @Override
    public void event() {
        super.event();
        System.out.println("I am for Ios");
    }
}

IosConfirmButton


package component;

public class IosConfirmButton extends  ConfirmButton {
    @Override
    public void event() {
        super.event();
        System.out.println("i am a confirm button for ios");
    }
}

IosAlertMessage

package component;

public class IosAlertMessage extends AlertMessage {
    @Override
    public void event() {
        super.event();
        System.out.println("I am for Ios");
    }
}

The test function

public class Main {
    public static void main(String[] args) {
        //Create factory
        ComponentFactory isoComponentFactory = new IosComponentFactory();
        ComponentFactory mdCompnentFactory = new AndroidComponentFactory();

        // create two component for Ios
        isoComponentFactory.createAlertMessageComponent().event();
        isoComponentFactory.createConfirmButtonComponent().event();


        System.out.println("------------------------------");
        // create two component for Android
        mdCompnentFactory.createAlertMessageComponent().event();
        mdCompnentFactory.createConfirmButtonComponent().event();


    }
}

Result

i am a alert Message
I am for Ios
I am a confirm Button, you can click me
i am a confirm button for ios

------------------------------
i am a alert Message
i am for ios alert message for andriod
I am a confirm Button, you can click me
i am the confirm button for andriod

Now, we may have some intuition about the difference between abstract factory and factory method. abstract factory pattern is designed for a set of related or dependent products which have some common features. Concrete Products have different levels. In our example , IOS button component is one level lower than ConfirmButtonComponent. And Concrete Factories are For creating a set of related component with the same level.

For client usage, if we want to create an app in IOs system. We would use the Ios Component Factory to create all the components that we want. If the opreating system has been changed. the only thing need to be changed is to switch the concrete factory. Since we use generic interface of the factory to create the concrete objects, other codes will not be changed.

Now, looking at the definition would be much clearer.

Definition from Wikipedia is:

Factory method

It is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creaing objects by callying a factory method - either specified in an in interface and implemented by child classes, or implemented in a base class and optionally overridden by derived classes - rather than by calling a constructor.

Abstract Factory

The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes.[1] In normal usage, the client software creates a concrete implementation of the abstract factory and then uses the generic interface of the factory to create the concrete objects that are part of the theme. The client doesn't know (or care) which concrete objects it gets from each of these internal factories, since it uses only the generic interfaces of their products. This pattern separates the details of implementation of a set of objects from their general usage and relies on object composition, as object creation is implemented in methods exposed in the factory interface.

Reference:

  1. Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison Wesley. pp. 107ff. ISBN 0-201-63361-2.

  2. Freeman, Eric; Robson, Elisabeth; Sierra, Kathy; Bates, Bert (2004). Hendrickson, Mike; Loukides, Mike (eds.). “Head First Design Patterns” (paperback). 1. O’REILLY: 156. ISBN 978-0-596-00712-6. Retrieved 2012-09-12.


Author: Liang Tan
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source Liang Tan !
  TOC