SYNERGY 2007

36
SYNERGY 2007 Design Patterns and the Object Factory Miami Thursday, May 17th Peter Bragg, Care Data Systems

description

SYNERGY 2007. Design Patterns and the Object Factory. Peter Bragg, Care Data Systems. Miami l Thursday, May 17th. The Company (Background). Care Data Systems Limited Based in Birmingham, UK Dataflex users since 1985 - PowerPoint PPT Presentation

Transcript of SYNERGY 2007

Page 1: SYNERGY 2007

SYNERGY 2007

Design Patterns and the Object Factory

Miami Thursday, May 17th

Peter Bragg, Care Data Systems

Page 2: SYNERGY 2007

The Company (Background)

• Care Data Systems Limited

• Based in Birmingham, UK

• Dataflex users since 1985

• Employed that handsome, young fellow

Peter Bragg on September 18th 2001

• Senior Product Developer

Page 3: SYNERGY 2007

The Product (Background)

• Donorflex

• Comprehensive system designed to support the ‘Not for Profit’

sector

– donations management (financial control, gift aid, gifts in kind,

merchandise sales)

– fundraising and strategic development (campaign management

& control)

– relationship management (profiling, segmentation, targeting)

– operational support (acknowledgements, communications, action

plans)

– events management (charity events and third party fundraising

and sponsorship)

Page 4: SYNERGY 2007

Typical Clients (Background)

• Healthcare

• Education

• Arts

• Community Social Services

• Overseas Aid

• Disability Services

• Political Reform

• Religious Organisations

• Service Veterans

• Sport

Page 5: SYNERGY 2007
Page 6: SYNERGY 2007

Design Patterns and the Object Factory

Page 7: SYNERGY 2007

The Story Begins…

• January 17th 2007

Page 8: SYNERGY 2007

Design Patterns & the Object Factory

Page 9: SYNERGY 2007

Design Patterns & the Object Factory

• I answered the question so precisely

that no further comments were

required! (Erm…)

• No one is interested in Factories

• No one is using Factories

• Might make an interesting topic?

Page 10: SYNERGY 2007

Design Patterns & the Object Factory

• I am not a Design Pattern Expert

• ..at all!

• Knowledge limited to ‘what I do’

Page 11: SYNERGY 2007

Design Patterns & the Object Factory

Creational Design Patterns and the Object

Factory

…in donorflex

Page 12: SYNERGY 2007

Design Patterns & the Object Factory

• Our Design Need:

One Application (donorflex)

Different backends (Dataflex, MSSQL, ?)

Intelligent code optimisation/execution

Page 13: SYNERGY 2007

Design Patterns & the Object Factory

• Possible design solutions:

If, Else or Case Statements

Deferred creation of ‘Process’ Objects

• The need:

Call a process (e.g. a ‘search’) and

execute code appropriate for the backend.

Page 14: SYNERGY 2007

Design Patterns & the Object Factory

View Object (i.e. Enquiry)

Process Object (i.e. Enquiry Engine)

Procedure OnProcess

If (Backend=Dataflex) …

end

else if (Backend=MSSQL)…

end etc.

End_Procedure

Page 15: SYNERGY 2007

Design Patterns & the Object Factory

View Object (i.e. Enquiry)

Procedure DoRunEnquiry

Handle hoEnquiryEngine

If (Backend=Dataflex) Get Create U_ … to hoEnquiryEngine

else if (Backend=MSSQL) Get Create U_ …….

Send DoProcess of hoEnquiryEngine

send Destroy of hoEnquiryEngine

End_Procedure

Page 16: SYNERGY 2007

Design Patterns & the Object Factory

View Object (i.e. Enquiry)

Factory Object (oFactory)Responsible for creating appropriate Process Object

Procedure DoRunEnquiry

Send DoProcess of (Instance(oFactory(self)))

End_Procedure

Page 17: SYNERGY 2007

So how does it all hang together?

• Write different versions of a (business) process as classes:

cAbstractPowerSearch (defines interface)

cPowerSearch_df is a cAbstractPowerSearch

cPowerSearch_mssql is a cAbstractPowerSearch

• Classes are then registered with a “Factory”:

Page 18: SYNERGY 2007

Design Patterns & the Object Factory

Class cPowerSearchEnq_Factory is a cFactory

Procedure Construct_Object Forward Send Construct_Object

Send RegisterType Factory_Type_Dataflex U_cPowerSearch_DF Send RegisterType Factory_Type_MSSQL U_cPowerSearch_MSSQL End_Procedure

End_Class

Page 19: SYNERGY 2007

So how does it all hang together?

• An instance of the factory is then added to a view

Object oPowerSearchEnq Is A cPowerSearchEnq_FactoryEnd_Object

• A call is then made to an ‘Instance’ of this Factory

So instead of:

Send DoProcess of oPowerSearchEnq

We would code:

Send DoProcess of (Instance(oPowerSearchEnq(self)))

• A ‘singleton’ Factory Controller instructs the Factory which

version of the process to create

Page 20: SYNERGY 2007

Factory Controller ClassEnum_List Define Factory_Type_Dataflex Define Factory_Type_MSSQL Define Factory_Type_Pervasive Define Factory_Type_MySQL Define All_Factory_Types //need to be last – gives number of defined typesEnd_Enum_List

Class cFactoryController is a cObject Procedure Construct_Object String sEngine Forward Send Construct_Object Property Integer piCurrentType Factory_Type_Dataflex // Default type. // Check the application object: Get psFactoryEngine of ghoApplication to sEngine //set during OnCreate of Application object Case Begin Case (sEngine = "mssql") Set piCurrentType to Factory_Type_MSSQL Case Break Case End End_Procedure // Construct_Object

Function CurrentType Returns Integer Function_Return (piCurrentType(Self)) End_FunctionEnd_Class

Page 21: SYNERGY 2007

Factory Controller Object

Global_Variable Handle ghFactoryControllerGet Create of Desktop U_cFactoryController to ghFactoryController

Page 22: SYNERGY 2007

The Factory ClassClass cFactory is a cObject Procedure Construct_Object integer[] iTypeMappings

Forward Send Construct_Object

// Holds the type of the current factory object: Property Integer piInstanceType (CurrentType(ghFactoryController)) // Holds the object instance that this factory object represents: Property Handle phInstance 0 // Initially zero. // Array that holds class identifiers to be constructed dependant on the required type: Property Integer[] piTypeMappings

//initialise piTypeMappings Array to avoid index out of range errors move 0 to iTypeMappings[All_Factory_Types] Set piTypeMappings to iTypeMappings End_Procedure // Construct_Object // Provides a means by which to 'register' what class should be used against a particular type of connection: Procedure RegisterType Integer iType Integer iClass integer[] iTypeMappings Get piTypeMappings to iTypeMappings move iClass to iTypeMappings[iType] Set piTypeMappings to iTypeMappings

End_Procedure

Page 23: SYNERGY 2007

The Factory Class… // Returns the class associated by a previous call to RegisterType: Function TypeClass Integer iType Returns Integer Integer iClass integer[] iTypeMappings Get piTypeMappings to iTypeMappings move iTypeMappings[iType] to iClass // if we don't find a registered class of the type we are looking for, look for and return the native dataflex // factory type.. if (iClass = 0) move iTypeMappings[Factory_Type_Dataflex] to iClass // Support drop through the default // type. // if we still have no registered class, we must give an error if (iClass = 0) Error 4113 ("Programmatic Error - No registered type for factory "+name(self)) Function_Return iClass End_Function // Returns the current 'type' associated with this factory: Function InstanceType Returns Integer Function_Return (piInstanceType(Self)) End_Function // Allows a new type to be set against this object: Procedure Set InstanceType Integer iType Set piInstanceType to iType End_Procedure

Page 24: SYNERGY 2007

The Factory Class… // Returns or creates the correct instance of a type for this factory: Function Instance Returns Handle Handle hObj Integer iType iNewType Get phInstance to hObj Get InstanceType to iType Get CurrentType of ghFactoryController to iNewType // If the type doesn't match what we are currently using then destroy the object and create a new one: If ((iType <> iNewType) And (hObj <> 0)) Begin Send Destroy of hObj Move 0 to hObj End

If (Not(hObj)) Begin Get Create (TypeClass(Self, iNewType)) to hObj Set phInstance to hObj Set InstanceType to iNewType End Function_Return hObj End_Function // Boolean function that tells the caller if the factory instance has been created yet: Function IsCreated Returns Boolean Function_Return (phInstance(self) <> 0) End_Function End_Class

Page 25: SYNERGY 2007

A Simple Example

• User logs in and we look to see if they have any communications to make.• Code we execute will depend on the backend• So we will use a factory for this…

Page 26: SYNERGY 2007

A Simple Example

Use cFactory.pkg

Define the interface:

class cAbstractLoginPrompts is a cObject Function DoFindLoginPrompts string sUser date dDate integer iDays returns integer[] end_function end_class

Or sometimes..

class cAbstractLoginPrompts is a cObject Function DoFindLoginPrompts string sUser date dDate integer iDays returns integer[] Error DFErr_Program “Method not defined for concrete class” end_function end_class

Page 27: SYNERGY 2007

A Simple Example

Write the classes:

class cLoginPrompts_df is a cAbstractLoginPrompts Function DoFindLoginPrompts string sUser date dDate integer iDays returns integer[] integer[3] iRetVal //outstanding/today/future integer iOverdue iToday iFuture open doncomms For_All DONCOMMS BY Index.3 Constrain Doncomms.On_behalf_of EQ sUser Constrain Doncomms.Login_prompt EQ "Y" DO if (doncomms.date < dDate) increment iOverdue else if (doncomms.date = dDate) increment iToday else if (doncomms.date <= (dDate+iDays-1)) increment iFuture End_For_All move iOverdue to iRetVal[0] move iToday to iRetVal[1] move iFuture to iRetVal[2] function_return iRetVal end_function end_class

Page 28: SYNERGY 2007

A Simple Example class cLoginPrompts_sql is a cAbstractLoginPrompts Function DoFindLoginPrompts string sUser date dDate integer iDays returns integer[] integer[3] iRetVal //outstanding/today/future integer iFetchResult iCount iData handle hSQLInstance hConn hSQL string sSQL sDate sDateFuture sBase boolean bNoMoreResultSets move (Instance(ghSQLConnectionFactory)) to hSQLInstance

move ("Select count(*) from doncomms where doncomms.On_behalf_of = '"+sUser+"' and doncomms.Entity = 'R' and doncomms.Login_prompt = 'Y' and ") to sBase

Get DateToSQL of hSQLInstance dDate to sDate move (sSQL+sBase+"doncomms.Date < '"+sDate+"';") to sSQL move (sSQL+sBase+"doncomms.Date = '"+sDate+"';") to sSQL Get DateToSQL of hSQLInstance (dDate+1) to sDate Get DateToSQL of hSQLInstance (dDate+iDays-1) to sDateFuture move (sSQL+sBase+"doncomms.date between '"+sDate+"' and '"+sDateFuture+"';") to sSQL // Open Connection Get Connection of hSQLInstance to hConn Get SQLOpen of hConn to hSQL // Send the Statement .. Send SQLExecDirect of hSQL sSQL move False to bNoMoreResultSets

Page 29: SYNERGY 2007

A Simple Example Repeat Get SQLFetch Of hSQL To iFetchResult If (iFetchResult <> 0) begin move (trim(SQLColumnValue(hSQL,1))) to iData increment iCount move iData to iRetVal[iCount-1] end Get SQLNextResultSet of hSQL to iFetchResult if (not(iFetchResult)) move True to bNoMoreResultSets Until (bNoMoreResultSets) // Release the Statement: Send SQLClose of hSQL function_return iRetVal end_function end_class

Page 30: SYNERGY 2007

A Simple Example

Write a factory class and register both classes:

class cLoginPrompts_Factory is a cFactory

Procedure Construct_Object Forward Send Construct_Object

// Register the default class that will be used as a drop through if other types aren't // registered: Send RegisterType Factory_Type_Dataflex U_cLoginPrompts_df Send RegisterType Factory_Type_MSSQL U_cLoginPrompts_sql End_Procedure end_Class

Create an Object instance of the Factory

Object oLoginPromptsFactory is a cLoginPrompts_FactoryEnd_object

Page 31: SYNERGY 2007

A Simple Example

Then call the function and let the factory do the rest

Integer[] iRetVal

Get DoFindLoginPrompts of (instance(oLoginPromptsFactory(Self))) sUser dDate iDays to iRetVal

Under the hood:

• The function “Instance” asks “have I already created an object for you?”• If so, it simply returns a handle to the object it created earlier• If not:

It looks to see what the “Factory Controller” says it should be creating It creates an object of the required class It sets a property with the handle of the object It returns a handle to the object “DoFindLoginPrompts” is then executed

Page 32: SYNERGY 2007

Another Example:

Page 33: SYNERGY 2007

How it works…

Use dnTreeView.pkgUse cProfileFactory.pkg

class cProfileTree is a dnTreeView

Import_Class_Protocol Server_Mixin Procedure Construct_Object forward send Construct_Object Property Integer piPrivate.CurrentProfile 0 Property Integer piPrivate.HelpArray_ID 0 Property Handle phProfileTreeFactory (Create(self,U_cProfileTree_Factory)) Send Define_Server // Set tree properties: Set TreeLinesState to False Set TreeRootLinesState to False Object PopupMenu is a cProfilePopUpMenu Delegate Set PopupMenu_ID to Self End_Object end_procedure

Page 34: SYNERGY 2007

How it works…

Page 35: SYNERGY 2007

Design Patterns & the Object Factory

• Using this ‘Factory’ approach as a model:

“The need to know” - objects only get involved

with what they need to. Views simply make a call

to a common interface and don’t care about what

lies behind this.

Scalability – new classes can be written and

registered with a Factory very easily.

Easy to code and implement new factory

instances.

Page 36: SYNERGY 2007

SYNERGY 2007

Thank You

Miami Thursday, May 17th