Tips_tutorials   >   Studio105   >   Studio 105 (All Contents)
Welcome to the
tutorial.This tutorial is provided to www.studiotips.net and click the link provided for becoming a StudioTips Member. The cost of membership is minimal and helps to cover the time and expense of creating these tutorials and maintaining the studiotips.net website.
only. If you are not currently a please go toThis tutorial delves into the advances object-oriented programming topic of observers based on the
.This tutorial continues from where we left off in the
tutorial. In this tutorial we will:In the object-oriented programming world you will run across the terms loose coupling vs. tight coupling.
Loose coupling is the best design for good object-oriented programming.
In the wHeadedList subwindow was tightly coupled to the wCountryStateprovContainer parent window.
tutorial theThe parent window was required to register with the child window using $setParentRef and to have an $event_HeadedListObj method if it wanted to received forwarded events from the subwindow. This is tight coupling.
A problem that became evident with this tight coupling was that a Switch/Case had to be put into the $event_HeadedListObj parent window method to figure out which subwindow the event message was coming from. Was it the countries list, or was it the states/provs list?
If you see Switch/Case or If/Else if being used in a method it may be a red flag that tight coupling is being used.
Loose coupling can be attained in the above situation by implementing observers based on the .The
works much like an email mailing list.A person wanting to receive messages from a particular list adds themself as a subscriber to the mailing list. When they subscribe to the list, they provide their email address. A copy of each email posted to the list is then automatically sent to the email address specified by the subscriber.
An enhancement to the above mailing list illustration would be to allow subscribers to specify a category of messages they wish to receive.
Applying the above mailing list illustration to a parent/child window relationship in Omnis Studio:
We first need to prepare the observers list variable and methods in the wHeadedList window class.
; Define the observers list if it hasn't yet been defined.
If iObserversList.$colcount=0
Do iObserversList.$cols.$add('observerid',kCharacter,kSimplechar,10000)
Do iObserversList.$cols.$add('observerref',kItemref)
Do iObserversList.$cols.$add('callbackmethodname',kCharacter,kSimplechar,100)
Do iObserversList.$cols.$add('eventcode',kInteger,kLongint)
End If
; Create a unique ID for the observer.
Calculate ObserverID as con(prObserver().$class().$name,'__',prObserver().$name,'__',prObserver.$ident)
; Parse the pEventCodes CSV string, adding a line to the observers list for each event code specified.
While len(pEventCodesCSV)
Calculate EventCode as strtok('pEventCodesCSV',',')
; Check to make sure the observer/callback/eventcode hasn't already been added to avoid double messages.
If not(iObserversList.$search($ref.observer=ObserverID&$ref.callbackmethodname=pCallbackMethodName&$ref.eventcode=eval(EventCode),1,0,0,0))
Do iObserversList.$add(ObserverID,prObserver,pCallbackMethodName,eval(EventCode))
End If
End For
Quit method kTrue
Calculate FlagOK as kTrue ;; Preset flag to true.
; Loop through the observers list.
For iObserversList.$line from 1 to iObserversList.$linecount step 1
; Check to make sure the event code matches the event code specified by the observer.
If iObserversList.eventcode=pkEventCode
Set reference rObserver to iObserversList.observerref
; Test to make sure the observer has a recipient methdo.
If not(rObserver.[iObserversList.callbackmethodname].$cando)
; Log an error. The observer is missing the specified recipient method.
Calculate Mssg as con("The headed list observer '",rObserver.$cinst().$class().$name,"' is missing the call back method '",iObserversList.callbackmethodname,"'.")
Calculate Dtls as ''
Do errhndlr.$logError($cmethod,Mssg,Dtls)
Calculate FlagOK as kFalse
Break to end of loop
Else
; Send a message to the observer.
Do rObserver.[iObserversList.callbackmethodname](prcobj,pkEventCode) Returns FlagOK
If not(FlagOK)
Break to end of loop
End If
End If
End If
End For
Quit method FlagOK
; Notify the headed list observers.
Do $cinst.$notifyHeadedListObservers($cobj,pEventCode) Returns FlagOK
If not(FlagOK)
Do errhndlr.$promptonceLastError()
End If
Quit method FlagOK
Next we need to modify wCountryStateprovContainer so that it attaches itself as an observer of the countries headed list subwindow.
; Attach the parent window as an observer of the headed list.
Calculate CallBackMethod as '$event_HeadedListCountries'
Do irswCountries.$attachHeadedListObserver($cinst,CallBackMethod,evClick) Returns FlagOK
If FlagOK
; Set the reference to the data list variable.
Do irswCountries.$setDataListRef(iCountriesList) Returns FlagOK
If FlagOK
; Get a reference to the list object.
Do irswCountries.$:ListObjRef() Returns rListObj
; Set the list object properties.
Do rListObj.$name.$assign('CountriesList')
Do rListObj.$colcount.$assign(1)
Do rListObj.$columnnames.$assign('Country')
Do rListObj.$calculation.$assign('irDataList.CountryName')
End If
End If
Quit method FlagOK
Calculate FlagOK as kTrue ;; Preset flag to true
If pkEventCode=evClick
Do method buildStateprovsListForCurrCountry Returns FlagOK
End If
Quit method FlagOK
To test the observer design pattern which we have created:
We can move the observers design pattern variable and methods into an object class which can then be reused over an over in different classes, and can even be instantiated multiple times within the same class instance to create more than one observers list.
; Remove the observer from the observers list.
Calculate ObserverID as con(prObserver().$class().$name,'__',prObserver().$name,'__',prObserver.$ident)
Do iObserversList.$search($ref.observerid=ObserverID)
Do iObserversList.$remove(kListDeleteSelected)
Quit method kTrue
We can now implement the oObservers object class in wHeadedList.
; Forward the message to the instance of oObservers.
Do ioHeadedListObservers(prObserver,pCallbackMethodName,pEventCodesCSV) Returns FlagOK
Quit method FlagOK
; Forward the message to the instance of oObservers.
Do ioHeadedListObservers.$notifyObservers(prcobj,pkEventCode) Returns FlagOK
Quit method FlagOK
; Forward the message to the instance of oObservers.
Do ioHeadedListObservers.$removeObserver(prObserver)
As you can see, the oObservers object class makes it very easy to add an observers list to any window class or for that matter any class instance. I use the observers list when adding menus lines on-the-fly to a context menu instance. Each menu line can have a different observer and callback method.
Open the window and test the countries list to make sure the oObservers object class is working successfully.Well that wraps up the
tutorial.I hope that this tutorial has helped you to:
Go ahead and copy the oObservers object class into your own application and make use of it where ever it makes sense to do so.
If this tutorial has been helpful please send an emai to doug@vencor.ca. It's always encouraging to hear from developers who have benefited from these tutorials. Be sure to include any suggestions for improvements or additional topics you would like to see covered.
Visit www.studiotips.net to find out more and to become a . Your support is greatly appreciated!
Happy coding!
Doug Kuyvenhoven