Clicky

Fortran Wiki
Factory Pattern (changes)

Skip the Navigation Links | Home Page | All Pages | Recently Revised | Authors | Feeds | Export |

Showing changes from revision #1 to #2: (追記) Added (追記ここまで) | (削除) Removed (削除ここまで) | (削除) Chan (削除ここまで)(追記) ged (追記ここまで)

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)

Revised on October 19, 2010 17:21:20 by Fercook? (80.30.165.13) (5725 characters / 2.0 pages)
Edit | Back in time (1 revision) | Hide changes | History | Views: Print | TeX | Source | Linked from: Design patterns, Design Patterns

AltStyle によって変換されたページ (->オリジナル) /