yakov fain - design patterns a deep dive
DESCRIPTION
Design patterns suggest approach to common problems that arise during software development regardless of what programming language. But implementation of these patterns is specific to the language. The main goal of this presentation is to highlight selected patterns as they may be implemented taking advantages of Flex framework.You'll see a not so obvious implementation of a Singleton, how a Proxy can dramatically change the behavior of an object, why a Mediator is a must-have in each Flex application. Do you know how to write Data Transfer Objects that are so important in Flex remoting? If time permits, we'll review the Class Factory pattern too.TRANSCRIPT
DesignPa*erns,aDeepDive
ByYakovFainFarataSystems
(c)FarataSystems
2
Farata Systems: What do we wo
Consulting and training
Software development (for free) (open source project Clear Toolkit on Sourceforge.net)
Writing tech. books and articles on Java and Adobe Flex (making from $0 to $1 per hour)
www.faratasystems.com
($$$$$$$$$$$$$$$$$$)
Whatisthisabout?
Designpa*ernssuggestanapproachtocommonproblemsthatariseduringsoCwaredevelopmentregardlessofwhatprogramminglanguageyouuse.
ButthegoalofthispresentaGonistohighlightselectedpa*ernsasyoumayimplementthemtakingadvantageoftheFlexframework.
(c)FarataSystems
We’lltalkaboutthesepa*erns
• Singleton• Proxy• Mediator
• DataTransferObject• AsynchronousToken
(c)FarataSystems
SingletonYoucancreateonlyoneinstanceofsuchaclassThere’snoprivateconstructorsinAcGonScript
ConsiderasamplefileMySingleton.as
packagesomePackage{publicclassMySingleton{
privatestaGcconst_instance:MySingleton=newMySingleton(Lock);publicstaGcfuncGongetinstance():MySingleton{return_instance;}publicfuncGonMySingleton(lock:Class){if(lock!=Lock){thrownewError("IllegalinstanGaGon.");}}}//EndofpackageclassLock{}
(c)FarataSystems
Haveyoueverseenthis?
varmodel:AppModelLocator=AppModelLocator.getInstance();
andthis?service=ServiceLocator.getInstance().getHTTPService('loadEmployeesService');
(c)FarataSystems
EnhancingtheApplicaGonobjectpublicdynamicclassDynamicApplica5onextendsApplica5onimplementsIApplicaGonFacade{publicfuncGonDynamicApplicaGon(){
super();}
publicstaGcvarservices:DicGonary=newDicGonary();
publicfuncGongetService(name:String):Object{ returnservices[name];}publicfuncGonaddService(name:String,value:Object):void{ services[name]=value;}publicfuncGonremoveService(name:String):void{ deleteservices[name];}publicfuncGongetServices():DicGonary{ returnservices;}
}
TheIApplicaGonFacadejustdeclaresthesefourmethodstoenableFlexBuilder’sintellisensehelpwhencasGng.var myApp:IApplicationFacade = …
(c)FarataSystems
AddinganyproperGestomyModel
(c)FarataSystems
SampledynamicapplicaGon(beginning)<?xmlversion="1.0"encoding="uc‐8"?><fx:DynamicApplicaGonxmlns:mx="h*p://www.adobe.com/2006/mxml"layout="absolute"xmlns:fx="h*p://www.faratasystems.com/2009/components"creaGonComplete="addAllServices();"><mx:Script>
<![CDATA[importcom.farata.core.DynamicApplicaGon;importmx.core.ApplicaGon;
//AddrequiredservicestotheApplica3onobject,i.e.myModelandmyServicesprivatefunc5onaddAllServices():void{
DynamicApplicaGon.services["myModel"]=newObject(); DynamicApplicaGon.services["myServices"]=newObject(); }
privatefunc5ongetData(serviceName:String,key:Object):Object{
returnDynamicApplicaGon.services[serviceName][key];}
privatefunc5onsetData(serviceName:String,key:Object,value:String):void{
DynamicApplicaGon.services[serviceName][key]=newString(value);}
]]></mx:Script> (c)FarataSystems
<!‐‐AddingvaluestomyModel‐‐><mx:Bu*onlabel="AddtomyModel"x="193"y="59”click="setData('myModel',key.text,value.text)"/>
<mx:Labelx="14"y="42"text="Key"fontWeight="bold"/><mx:Labelx="14"y="14"fontWeight="bold"fontSize="14"><mx:text>Addoneormorekey/valuepairstotheobjectMyModel</mx:text>
<mx:Labelx="91"y="42"text="Value"fontWeight="bold"/><mx:TextInputx="8"y="59"id="key"width="75"/><mx:TextInputx="89"y="59"id="value"width="96"/>
<!‐‐RetrievingthevaluefromaSingleton.‐‐><mx:Bu*onlabel="Showthevalue"x="8"y="122"click="retrievedValue.text=getData('myModel',key.text)asString"/><mx:Labelx="135"y="121"width="95"id="retrievedValue"fontWeight="bold"fontSize="15"/><mx:Labelx="10"y="94"fontWeight="bold"fontSize="14"><mx:text>RetrieveanddisplaythevaluefromMyModelbykey</mx:text></fx:DynamicApplicaGon>
SampledynamicapplicaGon(ending)
(c)FarataSystems
ProxyAproxyisanobjectthatrepresentsanotherobjectandcontrolsaccesstoit.
Thinkofasecretarythatreceivesapackageforherboss.
InAcGonScriptyoucanwraptheclassXYZinmx.uGl.ObjectProxy,whichwillbeaproxythatcontrolsaccesstotheXYZ’sproperGes.
(c)FarataSystems
How[Bindable]works?[Bindable]varlastName:String;
Flexcompilergeneratesawrapperclasswithase*erthatdispatchespropertyChangeeventoneachmodificaGonoflastName
Youcandoitonyourownbyusingtheclassmx.uGls.ObjectProxy
(c)FarataSystems
packagecom.farata{publicdynamicclassPerson {publicvarlastName:String="Johnson";publicvarsalary:Number=50000;}}
WrappingPersoninObjectProxy
(c)FarataSystems
RunningthePersonproxy
(c)FarataSystems
ExtendingObjectProxy
AddsomeapplicaGonlogictoit.Ifthesalaryofapersonincreasesover$55K,shebecomesenGtledforthepensionintheamountof2%ofthesalary.YouwanttoaddthisfuncGonalitywithouttouchingthecodeoftheclassPerson.
InasubclassofObjectProxy,youcanoverridegetProperty() andsetProperty() fromthenamespaceflash_proxy.
Ifyou’llwriteMyPersonProxy.lastName=”McCartney”,thisobjectwillcallitsownmethodsetProperty(“lastName”, “McCartney”). InterceptthiscallandaddsomeprocessingtototheoverriddenmethodsetProperty().
(c)FarataSystems
TesGngMyPersonProxy
ACer3clicksaddingpension property
(c)FarataSystems
Mediator
Anycomplexscreen,moreorless,ofabusinessapplicaGonconsistsofanumberofcontainersandcomponents.
Wewanttocreateloosely‐coupledcustomcomponentsthatareselfcontained,donotknowaboutexistenceofeachotherandcancommunicatewiththe“outsideworld”bysendingandreceivingevents.
(c)FarataSystems
BeforethetraderclickedonthePricePanel
ACerthetraderclickedonthePricePanel
WallStreet:StockTradingApplicaGon
PricePanelcomponenthasthreevariables:symbol, bid and ask
PricePaneldispatchestheOrderEventdispatchEvent(new OrderEvent( OrderEvent.PREPARE_ORDER_EVENT, symbol, bid,ask,buy));
OrderPanellistenstoOrderEventaddEventListener(OrderEvent.PLACE_ORDER_EVENT,orderEventHandler)
func5onorderEventHandler(evt:OrderEvent){sym.text=evt.symbol;operaGon.text=evt.buy?"Buy":"Sell";price.text=(oper.text=="Buy"?evt.bid:evt.ask);}
(c)FarataSystems
PricePanelComponent.Take1
OrderEventcarries4variables
(c)FarataSystems
CustomEventOrderEvent
TheMediatorreceivesthiseventfromPricePanelanddispatchesittoOrderPanel
Toomanyuservariables.ItwouldbeagoodideatoencapsulatetheminoneDTO–DataTransferObjecta.k.a.ValueObject
(c)FarataSystems
TheMediatorapplicaGonListentotheOrderEventfromPricingPanel
…andsendittoOrderPanel
(c)FarataSystems
DataTransferObject
DataTransferObjects(DTO)a.k.a.ValueObjects(VO)areusedfordataexchangebetweenvariousapplicaGoncomponents,whichcanbeeitherco‐locatedinthesameprocessoronremotecomputers.
TheseDTO’scanevenbewri*enindifferentprogramminglanguages,forexampleJavaandAcGonScript.
(c)FarataSystems
IntroducingDTOinStockTradingApp.
Insteadofpassingseveralvariablesbetweenpricingandorderpanels,we’llencapsulateorderdetailsintheOrderDTO classandsenditinsidetheeventobjecttothemediator.
(c)FarataSystems
PricePanelComponent.Take2
startDataFeed() emulatesexternaldatafeed
PackagingaDTOinsidetheeventOrderEvent2
UIcomponentsareboundtoDTOproperGes
(c)FarataSystems
NowPricePanelDispatchesOrderEvent2
Theapplica5on(mediator)willgetthiseventanddispatvhittotheOrderPanel:
varorderEvt:OrderEvent2=newOrderEvent2(OrderEvent2.PLACE_ORDER_EVENT,evt.orderInfo);
ordPanel.dispatchEvent(orderEvt); (c)FarataSystems
OrderPanelreceivestheevent…
…extractstheDTOfromtheevent
…andpopulatesUIcomponentsofOrderPanel
(c)FarataSystems
AdvancedDTOs
Ifyouenvisiondynamicupdatestothedataontheclient,declaretheseclassesas[Bindable].
UseanArrayCollecGonofsuchbindableDTO’sasadataProviderinyourDataGrid,List,andsimilarcomponents.
Makesurethatbothserver‐sideandclient‐sideDTOsprovideuniquepropertyuuid.FlexusesthispropertytouniquelyidenGfythedataelementsoftheList‐basedcontrols.
ConsiderreplacingeachpublicproperGeswiththege*erandse*ertohavemorecontroloverthemodificaGonsoftheseproperGes.
Youcanandaddthecodetothesese*ers/ge*ersthatwillintercepttheacGonofdatamodificaGonandperformaddiGonalprocessingbasedonwhat’sbeingchanged.Then,these*ercandispatchtheeventPropertyChangeeventasshownonthenextslide
(c)FarataSystems
SampleDTOwithbidproperty
FarataSystemshascreatedDTOgeneratorforJavaprogrammerscalledDto2FxthatcreatesAcGonScriptDTOsfromtheirJavacounterparts.It’safreeware,andyoucangetitath*p://flexblog.faratasystems.com/?p=357
(c)FarataSystems
AsynchronousToken
TheusermakesseveralRemoteObjectrequestsandresultscomebackasynchronouslyinarbitraryorder.
EachrequestcallsaresulthandlerfuncGonprovidingtheresultevent.
HowtheapplicaGoncodecanmaparrivingresultobjectsbacktotheiniGalrequestors?
(c)FarataSystems
AsyncTokenClassThegoaloftheAsynchronousTokenpa*ernistoproperlyroutetheprocessingontheclientinresponsetothedataarrivingasynchronouslyformtheserver
AsyncTokenisadynamicclass,youcanaddanyproperGestothisclassduringrunGme<mx:RemoteObjectid=”ord”desGnaGon=”Orders”/>…
privatefuncGonsendOrder(/*argumentsgohere*/):void{
vartoken:AsyncToken=ord.placeOrder({item:”SonyTV”});token.orderNumber=”12345”;
token.responder=newResponder(processOrderPlaced,processOrderFault);token.addResponder(newResponder(createShipment,processOrderFault));}
(c)FarataSystems
Whentheresultcomesback
AsyncTokenisalocalobject.ItisidenGfiedbyamessageId thatispassedwiththerequesttoserver.
Whentheserverresponds,itincludesacorrelationId propertyinthemessageheader,andFlexautomaGcallycallstheappropriateAsyncTokenrespondersintheordertheyweredefined.
privatefuncGonprocessOrderPlaced(event:ResultEvent):void{
myOrderNumber:Object=event.token.orderNumber;
//ifmyOrderNumberis12345,processitaccordingly}
(c)FarataSystems
ContactInfo&LinksEmail:[email protected]
Website:h*p://www.faratasystems.com
ClearToolkit:h*p://sourceforge.net/projects/cleartoolkit/
O’ReillyBook“EnterpriseDevelopmentwithFlex”:h*p://my.safaribooksonline.com/9780596801465
(c)FarataSystems