Observer'/'Observable'COMP'401'Spring'2013'Lecture'19'3/26/2013'Observer'/'Observable'• Official'Gang'of'Four'descripDon:'– Define'a'oneHtoHmany'dependency'between'objects'so'that'when'one'object'changes'state,'all'its'dependents'are'noDfied'and'updated'automaDcally.'• Observable'– The'object'of'“interest”'• Represents'data'or'state'that'may'change'in'the'future.'• Observer'– The'“interested”'objects'• Represents'parts'of'system'that'need'to'be'updated'or'may'need'to'take'acDon'if/when'observable'object'changes.'COMP'401'::'Spring'2012' 2'Use'Cases'• User'Interfaces'– User'interface'elements'like'buWons,'scrollbars,'etc.'are'“observable”'• State'changes'correspond'to'clicks,'drags,'etc.'– ApplicaDon'objects'that'must'respond'to'user’s'interacDons'with'the'UI'are'“observers”'• Asynchronous'Programming'– Also'known'as'“eventHbased”'programming'– May'have'wellHdefined'acDons'corresponding'to'events'that'may'occur,'but'can’t'know'in'advance'which'event'will'occur'or'when'it'will'occur.'COMP'401'::'Spring'2012' 3'Basic'Observer/Observable'• Defining'Observer'as'an'interface'allows'any'class'to'act'as'an'observer'for'the'Observable'class.'• NoDce'that'Observable'can'have'more'than'one'observer.'– And'that'they'don’t'know'about'each'other'or'the'order'of'update.'COMP'401'::'Spring'2012' 4'interface'Observer'{'''void'update();'}'class'Observable'{''''List<Observer>'observers;''''void'addObserver(Observer'o)'{'''''//'Adds'o'to'list'of'observers'''''observers.add(o);'''}''''void'deleteObserver(Observer'o)'{'''''//'Takes'o'off'list'of'observers'''''observers.remove(o);'''}''''void'noDfyObservers()'{'''''//'Trigger'update'method'on'''''//'all'observers'''''for'(Observer'o':'observers)'{'''''''''o.update();'''''}'''}'}'lec19.v1'• Game'acts'as'Observable'class'• GameObserver'acts'as'Observer'interface'• Discussion'– How'many'games'can'one'fan'watch?'– What'if'we'wanted'to'have'fan'objects'that'could'watch'more'than'one'game'simultaneously?'Observer/Observable'Refined'• Passing'reference'to'observable'as'a'parameter'to'update'method'allows'Observer'to'register'with'more'than'one'Observable'and'then'detect'which'one'changed.'COMP'401'::'Spring'2012' 6'interface'Observer'{'''void'update(Observable'o);'}'class'Observable'{'''List<Observer>'observers;''''void'register(Observer'o)'{'''''//'Adds'o'to'list'of'observers'''''observers.add(o);'''}''''void'unregister(Observer'o)'{'''''//'Takes'o'off'list'of'observers'''''observers.remove(o);'''}''''void'noDfyObservers()'{'''''//'Trigger'update'method'on'''''//'all'observers'''''for'(Observer'o':'observers)'{'''''''''o.update(this);'''''}'''}'}'lec19.v2'• Same'observers'watching'mulDple'games'– Game'object'passed'to'fan'as'parameter'to'update'method.'– So'far,'fans'are'reacDng'to'current'state'of'game.'But'in'real'life,'what'do'we'react'to?'COMP'401'::'Spring'2012' 7'Observer/Observable'Refined'More'• In'addiDon'to'passing'reference'to'Observable'that'changed,'we'can'encapsulate'what'changed'as'addiDonal'informaDon'for'the'update'method'of'the'Observer.'COMP'401'::'Spring'2012' 8'interface'Observer'{'''void'update(Observable'o,'Info'i);'}'class'Observable'{''''List<Observer>'observers;''''void'register(Observer'o)'{'''''//'Adds'o'to'list'of'observers'''''observers.add(o);'''}''''void'unregister(Observer'o)'{'''''//'Takes'o'off'list'of'observers'''''observers.remove(o);'''}''''void'noDfyObservers(Info'i)'{'''''//'Trigger'update'method'on'''''//'all'observers'''''for'(Observer'o':'observers)'{'''''''''o.update(this,'i);'''''}'''}'}'lec19.v3'• GameObserver'update'method'now'takes'second'argument'– String'who_scored'• This'is'the'“info”'about'the'change'in'the'game'that'is'being'passed'to'the'fans'Observer/Observable'in'java.uDl'• Java'provides'skeleton'Observer'/'Observable'that'you'can'extend'in'java.uDl'– Don’t'have'to'use'them.'• Our'examples'so'far'haven’t'– The'paWern'is'defined'by'relaDonship'between'objects'and'their'interacDon.'• Not'the'specific'method'names'and/or'implementaDon.'• Should'be'able'to'recognize'Observer/Observable'by'these'characterisDcs:'– Observer'object'some'how'registers'with'observable.'– Observable'invokes'a'method'on'observers'in'order'to'signal'state'changes.'COMP'401'::'Spring'2012' 10'lec19.v4'• Game'extends'java.uDl.Observable'– No'longer'have'to'manage'our'own'list'since'we'inherit'that'from'Observable'• UNCFan'and'DukeFan'implement'java.uDl.Observer'– Parameters'to'update'are'no'longer'context'specific.'• update(Observable'o,'Object'arg)'– Need'contravariant'cast'to'make'them'useful'• Observable'parent'class'requires'state'change'to'be'signaled'by'call'to'setChanged()'before'calling'noDfyObservers.'– Otherwise,'won’t'do'anything.'DelegaDng'java.uDl.Observable'• Using'Observable'is'convenient'– Inherits'basic'Observable'funcDonality'without'having'to'worry'about'doing'it'yourself.'• Must'subclass'observable.'– Suppose'your'class'already'has'a'parent'due'to'design'or'circumstance.'• Don’t'have'development'control'over'class'hierarchy.'• Parent'class'is'part'of'third'party'library.'• SoluDon'lies'with'delegaDon.'COMP'401'::'Spring'2012' 12'DelegaDng'Observable'• Outline'of'soluDon:'– Create'a'helper'class'that'does'subclass'Observable'• Implements'same'interface'as'original'class'via'delegaDon.'• Override'noDfyObservers'to'call'setChanged()'first.'– Create'an'instance'of'this'helper'class'as'part'of'your'object.'– Provide'methods'from'Observable'via'delegaDon'to'this'instance.'• DelegaDon'is'being'used'both'ways'here.'– Allows'Observer'to'use'“hidden”'observable'instance'as'if'it'were'the'original'object.'– Allows'outside'code'to'interact'with'original'object'as'if'it'were'Observable.'• lec19.v5'COMP'401'::'Spring'2012' 13'MulDple'Observer'Lists'• Same'delegaDon'trick'can'be'used'to'support'mulDple'lists'of'observers.'– Useful'if'you'want'to'support'more'than'one'type'of'observable'changes/events.'– Requires'providing'a'way'to'specify'what'is'being'observed.'• One'approach:'separate'registraDon'methods'for'each'observable'change/event.'• Another'approach:'addiDonal'argument'to'registraDon'method.'–
View Full Document