Clicky

Fortran Wiki
Factory Pattern

Factory Pattern

A Factory Pattern is a creational design pattern which provides a uniform interface for creating objects related to each other.

Here is a simple example. Let us say that you want to connect to a database. There are so many ways of connecting: Oracle, MySQL, SQL Server,etc. We wish to provide a uniform interface for creating connections to these databases. The class which encapsulates this object creation is a “Factory”.

type CFactory
    private
        character(len=20) :: factory_type               !! Descriptive name for database
        class(Connection), pointer :: connection_type   !! Which type of database ?
    contains                                            !! Note 'class' not 'type' !
        procedure :: init                               !! Constructor
        procedure :: create_connection                  !! Connect to database
        procedure :: final                              !! Destructor
end type CFactory

Since there are different types of database connections, let us create an abstract class to encapsulate all sorts of connections. For simplicity, each connection has only one procedure, description, which prints out what type of connection it itself is. Every derived type must implement this subroutine (hence, deferred).

type, abstract :: Connection
    contains
    procedure(generic_desc), deferred, pass(self) :: description
end type Connection

abstract interface
    subroutine generic_desc(self)
        import :: Connection
        class(Connection), intent(in) :: self
    end subroutine generic_desc
end interface

We are now ready to create concrete connections derived from the above type. Let’s create two of them, Oracle and MySQL .

!! An Oracle connection
type, extends(Connection) :: OracleConnection
    contains
        procedure, pass(self) :: description => oracle_desc
end type OracleConnection

!! A MySQL connection
type, extends(Connection) :: MySQLConnection
    contains
        procedure, pass(self) :: description => mysql_desc
end type MySQLConnection

The type-bound procedures are simple. They just print out who they are:

    subroutine oracle_desc(self)
        class(OracleConnection), intent(in) :: self
        write(*,'(A)') "You are now connected with Oracle"
    end subroutine oracle_desc

    subroutine mysql_desc(self)
        class(MySQLConnection), intent(in) :: self
        write(*,'(A)')  "You are now connected with MySQL"
    end subroutine mysql_desc

Now comes the crucial part. How do we implement our factory ? The constructor simply initializes the private variables, including pointers. We’ll be allocating memory to our polymorphic ‘class’ pointer, so the destructor has to free the memory.

    subroutine init(self, string)
        class(CFactory), intent(inout) :: self
        character(len=*), intent(in) :: string
        self%factory_type = trim(string)
        self%connection_type => null()            !! pointer is nullified
    end subroutine init

    subroutine final(self)
        class(CFactory), intent(inout) :: self
        deallocate(self%connection_type)          !! Free the memory
        nullify(self%connection_type)
    end subroutine final

To create a connection, we simply search through (“if-else”) all the possible list of connections which our factory must be able to produce. This is the core part. A factory hides away how different objects are created.

    function create_connection(self)  result(ptr)
        class(CFactory) :: self
        class(Connection), pointer :: ptr

        if(self%factory_type == "Oracle") then
            if(associated(self%connection_type))   deallocate(self%connection_type)
            allocate(OracleConnection :: self%connection_type)
            ptr => self%connection_type
        elseif(self%factory_type == "MySQL") then
            if(associated(self%connection_type))   deallocate(self%connection_type)
            allocate(MySQLConnection :: self%connection_type)
            ptr => self%connection_type
        end if
    end function create_connection

So there you are. A pointer to the created object is returned. If the connection already exists and a new connection is being requested, we do so. We remove (_deallocate_) the old connection and freshly allocate a new connection.

The client program could be like this:

program main
use factory_pattern
implicit none

    type(CFactory) :: factory
    class(Connection), pointer :: db_connect => null()

    call factory%init("Oracle")
    db_connect => factory%create_connection()   !! Create Oracle DB
    call db_connect%description()

    !! The same factory can be used to create different connections
    call factory%init("MySQL")                  !! Create MySQL DB

    !! 'connect' is a 'class' pointer. So can be used for either Oracle or MySQL
    db_connect => factory%create_connection()
    call db_connect%description()

    call factory%final()        ! Destroy the object

end program main

The same factory can be used to manufacture different objects as requested. Using polymorphism (“class pointers”) we can switch between different connections at runtime. The output of the above program is:

You are now connected with Oracle
You are now connected with MySQL

PS: The above program compiles with GFortran 4.6.0 (experimental , built 19.June.2010)