1 / 36

SYNERGY 2007

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

asis
Download Presentation

SYNERGY 2007

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


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

  2. 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

  3. 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)

  4. Typical Clients (Background) • Healthcare • Education • Arts • Community Social Services • Overseas Aid • Disability Services • Political Reform • Religious Organisations • Service Veterans • Sport

  5. Design Patterns and the Object Factory

  6. The Story Begins… • January 17th 2007

  7. Design Patterns & the Object Factory

  8. 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?

  9. Design Patterns & the Object Factory • I am not a Design Pattern Expert • ..at all! • Knowledge limited to ‘what I do’

  10. Design Patterns & the Object Factory Creational Design Patterns and the Object Factory …in donorflex

  11. Design Patterns & the Object Factory • Our Design Need: • One Application (donorflex) • Different backends (Dataflex, MSSQL, ?) • Intelligent code optimisation/execution

  12. Design Patterns & the Object Factory • The need: • Call a process (e.g. a ‘search’) and execute code appropriate for the backend. • Possible design solutions: • If, Else or Case Statements • Deferred creation of ‘Process’ Objects

  13. 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

  14. 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

  15. Design Patterns & the Object Factory View Object (i.e. Enquiry) Procedure DoRunEnquiry Send DoProcess of (Instance(oFactory(self))) End_Procedure Factory Object (oFactory) Responsible for creating appropriate Process Object

  16. 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”:

  17. 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

  18. So how does it all hang together? • An instance of the factory is then added to a view Object oPowerSearchEnq Is A cPowerSearchEnq_Factory End_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

  19. Factory Controller Class Enum_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 types End_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_Function End_Class

  20. Factory Controller Object Global_Variable Handle ghFactoryController Get Create of Desktop U_cFactoryController to ghFactoryController

  21. The Factory Class Class 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

  22. The Factory Class… // Returns the class associated by a previous call to RegisterType: Function TypeClass Integer iType ReturnsInteger 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

  23. The Factory Class… // Returns or creates the correct instance of a type for this factory: Function Instance ReturnsHandle 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 ReturnsBoolean Function_Return (phInstance(self) <> 0) End_Function End_Class

  24. 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…

  25. 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

  26. 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

  27. 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

  28. 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

  29. 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_Factory End_object

  30. 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

  31. Another Example:

  32. How it works… Use dnTreeView.pkg Use 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 DelegateSet PopupMenu_ID toSelf End_Object end_procedure

  33. How it works…

  34. 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.

  35. SYNERGY 2007 Thank You Miami l Thursday, May 17th

More Related