SlideShare a Scribd company logo
1 of 46
Download to read offline
Refactoring Conditional
  Dispatcher with Command
(based on Refactoring to Patterns)

        Sreenivas Ananthakrishna
let’s start with an example...
http://www.flickr.com/photos/fastlanedaily/509830016/
http://www.flickr.com/photos/martineian/485029758/




                                                    The ATM!
so what can the ATM do?
so what can the ATM do?

➡   Display the login screen when card is inserted
so what can the ATM do?

➡   Display the login screen when card is inserted

➡   Authenticate the user
so what can the ATM do?

➡   Display the login screen when card is inserted

➡   Authenticate the user

➡   Allow
 authenticated user to withdraw $$$
ATM Overview
Services



                    Authentication

View     ATM
       Controller
                       Account
View
  ➡    renders the screen
Services
  ➡    authenticates the user
  ➡    transfer/ debit money from account
Controller
  ➡    handles requests from view
let’s focus on building the ATMController...
and in TDD fashion, the test come first!
describe quot;an instance of quot;, ATMController do
  it quot;should render login when card is insertedquot; do
    view = mock(View)
    view.should_receive(:render).
          with(:login, {:account_id => 1234})

    controller = ATMController.new view
    controller.handle :card_inserted, {:account_id => 1234}
  end
end
now, the implementation
class ATMController
  def initialize view
    @view = view
  end

  def handle event, params
      @view.render :login, {:account_id => params[:account_id]}
  end
end
second test
it quot;should raise error for unknown eventquot; do
  view = mock(View)
  view.should_not_receive(:render)

  controller = ATMController.new view
  lambda {controller.handle(:foo, {})}.
             should raise_error(RuntimeError,
                   quot;cannot handle event fooquot;)
end
implementation
class ATMController
  def initialize view
    @view = view
  end

  def handle event, params
    if event == :card_inserted
        @view.render :login, {:account_id => params[:account_id]}
    else
         raise quot;cannot handle event #{event}quot;
    end
  end
end
third test
it quot;should display withdraw menu when user has authenticatedquot; do
  view = mock(View)
  view.should_receive(:render).with(:withdraw_menu)

 authentication_service = mock(AuthenticationService)
 authentication_service.should_receive(:authenticate).
                        with(1234, 5678).
                        and_return(true)

  controller = ATMController.new view, authentication_service
  controller.handle :authenticate,
                     {:account_id => 1234, :pin => 5678}
end
implementation
class ATMController
  def initialize view, authentication_service
    @authentication_service = authentication_service
    @view = view
  end

  def handle event, params
     case event
       when :card_inserted
         @view.render :login, {:account_id => params[:account_id]}
       when :authenticate
         if @authentication_service.
                      authenticate(params[:account_id], params[:pin])
           @view.render :withdraw_menu
         end
       else
            raise quot;cannot handle event #{event}quot;
     end
  en
addition of new dependencies has broken
              other tests!
so let’s fix it!
it quot;should render login when card is insertedquot; do
    view = mock(View)
    view.should_receive(:render).with(:login, {:account_id =>
1234})

  authentication_service = mock(AuthenticationService)
      authentication_service.should_not_receive(:authenticate)


    controller = ATMController.new view , authentication_service
controller.handle :card_inserted, {:account_id => 1234}
  end
so, as the controller keeps handling new
                 events...
so, as the controller keeps handling new
                 events...

๏   handle method keeps getting bloated
so, as the controller keeps handling new
                 events...

๏   handle method keeps getting bloated
    ๏   which means higher complexity
so, as the controller keeps handling new
                 events...

๏   handle method keeps getting bloated
    ๏   which means higher complexity
๏   adding new events requires changing the
    controller implementation
so, as the controller keeps handling new
                 events...

๏   handle method keeps getting bloated
    ๏   which means higher complexity
๏   adding new events requires changing the
    controller implementation
๏   addition of new receivers also affects
    existing test cases
let’s see how we can simplify
by refactoring to the Command
refactoring mechanics
step 1: compose method
Before
def handle event, params
  case event
    when :card_inserted
      @view.render :login, {:account_id => params[:account_id]}
    when :authenticate
      if @authentication_service.
                   authenticate(params[:account_id], params[:pin])
        @view.render :withdraw_menu
      end
    else
         raise quot;cannot handle event #{event}quot;
  end
end
After
def handle event, params
    case event
      when :card_inserted
        handle_card_inserted params
      when :authenticate
        handle_authenticate params
      else
           raise quot;cannot handle event #{event}quot;
    end
  end
step 2: extract class
Before

def handle_authenticate params
    if @authentication_service.
                authenticate(params[:account_id], params[:pin])
      @view.render :withdraw_menu
    end
end
After

def handle_authenticate params
    action = AuthenticateAction.new @view, @authentication_service
    action.execute params
end
extract superclass
class Action
  def execute params
    raise quot;not implemented!quot;
  end
end



class AuthenticateAction < Action
  def initialize view, authentication_service
    @view = view
    @authentication_service = authentication_service
  end
  def execute params
    if @authentication_service.
                authenticate(params[:account_id], params[:pin])
      @view.render :withdraw_menu
    end
  end
end
configure the controller
  with map of actions
class ATMController
  def initialize map
    @actions = map
  end

  def handle event, params
      if @actions.include? event
        @actions[event].execute params
      else
           raise quot;cannot handle event #{event}quot;
    end
  end
end
now, even the tests are simpler!
describe quot;an instance of quot;, ATMController do
  it quot;should execute the action for the eventquot; do
      params = {'foo' => 'bar'}
      action = mock(Action)
      action.should_receive(:execute).with(params)

        controller = ATMController.new({:foo_event => action})
        controller.handle(:foo_event, params)
  end

  it quot;should raise error for unknown eventquot; do
    controller = ATMController.new({})
    lambda {controller.handle(:foo, {})}.
                should raise_error quot;cannot handle event fooquot;
  end

end
some points for discussion


•   Do we need a command pattern in
    dynamic languages ?
    •   can we get away with using a block/
        closure
•   What are the different ways in which these
    commands could be configured?

More Related Content

More from melbournepatterns (20)

Iterator Pattern
Iterator PatternIterator Pattern
Iterator Pattern
 
Iterator
IteratorIterator
Iterator
 
Concurrency Patterns
Concurrency PatternsConcurrency Patterns
Concurrency Patterns
 
Continuous Integration, Fast Builds and Flot
Continuous Integration, Fast Builds and FlotContinuous Integration, Fast Builds and Flot
Continuous Integration, Fast Builds and Flot
 
Command Pattern
Command PatternCommand Pattern
Command Pattern
 
Code Contracts API In .Net
Code Contracts API In .NetCode Contracts API In .Net
Code Contracts API In .Net
 
LINQ/PLINQ
LINQ/PLINQLINQ/PLINQ
LINQ/PLINQ
 
Gpu Cuda
Gpu CudaGpu Cuda
Gpu Cuda
 
Facade Pattern
Facade PatternFacade Pattern
Facade Pattern
 
Phani Kumar - Decorator Pattern
Phani Kumar - Decorator PatternPhani Kumar - Decorator Pattern
Phani Kumar - Decorator Pattern
 
Composite Pattern
Composite PatternComposite Pattern
Composite Pattern
 
Adapter Design Pattern
Adapter Design PatternAdapter Design Pattern
Adapter Design Pattern
 
Prototype Design Pattern
Prototype Design PatternPrototype Design Pattern
Prototype Design Pattern
 
Factory Method Design Pattern
Factory Method Design PatternFactory Method Design Pattern
Factory Method Design Pattern
 
Abstract Factory Design Pattern
Abstract Factory Design PatternAbstract Factory Design Pattern
Abstract Factory Design Pattern
 
A Little Lisp
A Little LispA Little Lisp
A Little Lisp
 
State Pattern in Flex
State Pattern in FlexState Pattern in Flex
State Pattern in Flex
 
Active Object
Active ObjectActive Object
Active Object
 
Extract Composite Talk Andy
Extract Composite Talk AndyExtract Composite Talk Andy
Extract Composite Talk Andy
 
Selenium Interpreter
Selenium InterpreterSelenium Interpreter
Selenium Interpreter
 

Recently uploaded

Islamabad Escorts | Call 03070433345 | Escort Service in Islamabad
Islamabad Escorts | Call 03070433345 | Escort Service in IslamabadIslamabad Escorts | Call 03070433345 | Escort Service in Islamabad
Islamabad Escorts | Call 03070433345 | Escort Service in IslamabadAyesha Khan
 
8447779800, Low rate Call girls in Tughlakabad Delhi NCR
8447779800, Low rate Call girls in Tughlakabad Delhi NCR8447779800, Low rate Call girls in Tughlakabad Delhi NCR
8447779800, Low rate Call girls in Tughlakabad Delhi NCRashishs7044
 
Kenya Coconut Production Presentation by Dr. Lalith Perera
Kenya Coconut Production Presentation by Dr. Lalith PereraKenya Coconut Production Presentation by Dr. Lalith Perera
Kenya Coconut Production Presentation by Dr. Lalith Pereraictsugar
 
Future Of Sample Report 2024 | Redacted Version
Future Of Sample Report 2024 | Redacted VersionFuture Of Sample Report 2024 | Redacted Version
Future Of Sample Report 2024 | Redacted VersionMintel Group
 
8447779800, Low rate Call girls in Kotla Mubarakpur Delhi NCR
8447779800, Low rate Call girls in Kotla Mubarakpur Delhi NCR8447779800, Low rate Call girls in Kotla Mubarakpur Delhi NCR
8447779800, Low rate Call girls in Kotla Mubarakpur Delhi NCRashishs7044
 
2024 Numerator Consumer Study of Cannabis Usage
2024 Numerator Consumer Study of Cannabis Usage2024 Numerator Consumer Study of Cannabis Usage
2024 Numerator Consumer Study of Cannabis UsageNeil Kimberley
 
Buy gmail accounts.pdf Buy Old Gmail Accounts
Buy gmail accounts.pdf Buy Old Gmail AccountsBuy gmail accounts.pdf Buy Old Gmail Accounts
Buy gmail accounts.pdf Buy Old Gmail AccountsBuy Verified Accounts
 
Memorándum de Entendimiento (MoU) entre Codelco y SQM
Memorándum de Entendimiento (MoU) entre Codelco y SQMMemorándum de Entendimiento (MoU) entre Codelco y SQM
Memorándum de Entendimiento (MoU) entre Codelco y SQMVoces Mineras
 
8447779800, Low rate Call girls in Uttam Nagar Delhi NCR
8447779800, Low rate Call girls in Uttam Nagar Delhi NCR8447779800, Low rate Call girls in Uttam Nagar Delhi NCR
8447779800, Low rate Call girls in Uttam Nagar Delhi NCRashishs7044
 
Independent Call Girls Andheri Nightlaila 9967584737
Independent Call Girls Andheri Nightlaila 9967584737Independent Call Girls Andheri Nightlaila 9967584737
Independent Call Girls Andheri Nightlaila 9967584737Riya Pathan
 
APRIL2024_UKRAINE_xml_0000000000000 .pdf
APRIL2024_UKRAINE_xml_0000000000000 .pdfAPRIL2024_UKRAINE_xml_0000000000000 .pdf
APRIL2024_UKRAINE_xml_0000000000000 .pdfRbc Rbcua
 
Call Girls in DELHI Cantt, ( Call Me )-8377877756-Female Escort- In Delhi / Ncr
Call Girls in DELHI Cantt, ( Call Me )-8377877756-Female Escort- In Delhi / NcrCall Girls in DELHI Cantt, ( Call Me )-8377877756-Female Escort- In Delhi / Ncr
Call Girls in DELHI Cantt, ( Call Me )-8377877756-Female Escort- In Delhi / Ncrdollysharma2066
 
PSCC - Capability Statement Presentation
PSCC - Capability Statement PresentationPSCC - Capability Statement Presentation
PSCC - Capability Statement PresentationAnamaria Contreras
 
Cybersecurity Awareness Training Presentation v2024.03
Cybersecurity Awareness Training Presentation v2024.03Cybersecurity Awareness Training Presentation v2024.03
Cybersecurity Awareness Training Presentation v2024.03DallasHaselhorst
 
Digital Transformation in the PLM domain - distrib.pdf
Digital Transformation in the PLM domain - distrib.pdfDigital Transformation in the PLM domain - distrib.pdf
Digital Transformation in the PLM domain - distrib.pdfJos Voskuil
 
FULL ENJOY Call girls in Paharganj Delhi | 8377087607
FULL ENJOY Call girls in Paharganj Delhi | 8377087607FULL ENJOY Call girls in Paharganj Delhi | 8377087607
FULL ENJOY Call girls in Paharganj Delhi | 8377087607dollysharma2066
 
Case study on tata clothing brand zudio in detail
Case study on tata clothing brand zudio in detailCase study on tata clothing brand zudio in detail
Case study on tata clothing brand zudio in detailAriel592675
 
MAHA Global and IPR: Do Actions Speak Louder Than Words?
MAHA Global and IPR: Do Actions Speak Louder Than Words?MAHA Global and IPR: Do Actions Speak Louder Than Words?
MAHA Global and IPR: Do Actions Speak Louder Than Words?Olivia Kresic
 
Marketplace and Quality Assurance Presentation - Vincent Chirchir
Marketplace and Quality Assurance Presentation - Vincent ChirchirMarketplace and Quality Assurance Presentation - Vincent Chirchir
Marketplace and Quality Assurance Presentation - Vincent Chirchirictsugar
 
8447779800, Low rate Call girls in New Ashok Nagar Delhi NCR
8447779800, Low rate Call girls in New Ashok Nagar Delhi NCR8447779800, Low rate Call girls in New Ashok Nagar Delhi NCR
8447779800, Low rate Call girls in New Ashok Nagar Delhi NCRashishs7044
 

Recently uploaded (20)

Islamabad Escorts | Call 03070433345 | Escort Service in Islamabad
Islamabad Escorts | Call 03070433345 | Escort Service in IslamabadIslamabad Escorts | Call 03070433345 | Escort Service in Islamabad
Islamabad Escorts | Call 03070433345 | Escort Service in Islamabad
 
8447779800, Low rate Call girls in Tughlakabad Delhi NCR
8447779800, Low rate Call girls in Tughlakabad Delhi NCR8447779800, Low rate Call girls in Tughlakabad Delhi NCR
8447779800, Low rate Call girls in Tughlakabad Delhi NCR
 
Kenya Coconut Production Presentation by Dr. Lalith Perera
Kenya Coconut Production Presentation by Dr. Lalith PereraKenya Coconut Production Presentation by Dr. Lalith Perera
Kenya Coconut Production Presentation by Dr. Lalith Perera
 
Future Of Sample Report 2024 | Redacted Version
Future Of Sample Report 2024 | Redacted VersionFuture Of Sample Report 2024 | Redacted Version
Future Of Sample Report 2024 | Redacted Version
 
8447779800, Low rate Call girls in Kotla Mubarakpur Delhi NCR
8447779800, Low rate Call girls in Kotla Mubarakpur Delhi NCR8447779800, Low rate Call girls in Kotla Mubarakpur Delhi NCR
8447779800, Low rate Call girls in Kotla Mubarakpur Delhi NCR
 
2024 Numerator Consumer Study of Cannabis Usage
2024 Numerator Consumer Study of Cannabis Usage2024 Numerator Consumer Study of Cannabis Usage
2024 Numerator Consumer Study of Cannabis Usage
 
Buy gmail accounts.pdf Buy Old Gmail Accounts
Buy gmail accounts.pdf Buy Old Gmail AccountsBuy gmail accounts.pdf Buy Old Gmail Accounts
Buy gmail accounts.pdf Buy Old Gmail Accounts
 
Memorándum de Entendimiento (MoU) entre Codelco y SQM
Memorándum de Entendimiento (MoU) entre Codelco y SQMMemorándum de Entendimiento (MoU) entre Codelco y SQM
Memorándum de Entendimiento (MoU) entre Codelco y SQM
 
8447779800, Low rate Call girls in Uttam Nagar Delhi NCR
8447779800, Low rate Call girls in Uttam Nagar Delhi NCR8447779800, Low rate Call girls in Uttam Nagar Delhi NCR
8447779800, Low rate Call girls in Uttam Nagar Delhi NCR
 
Independent Call Girls Andheri Nightlaila 9967584737
Independent Call Girls Andheri Nightlaila 9967584737Independent Call Girls Andheri Nightlaila 9967584737
Independent Call Girls Andheri Nightlaila 9967584737
 
APRIL2024_UKRAINE_xml_0000000000000 .pdf
APRIL2024_UKRAINE_xml_0000000000000 .pdfAPRIL2024_UKRAINE_xml_0000000000000 .pdf
APRIL2024_UKRAINE_xml_0000000000000 .pdf
 
Call Girls in DELHI Cantt, ( Call Me )-8377877756-Female Escort- In Delhi / Ncr
Call Girls in DELHI Cantt, ( Call Me )-8377877756-Female Escort- In Delhi / NcrCall Girls in DELHI Cantt, ( Call Me )-8377877756-Female Escort- In Delhi / Ncr
Call Girls in DELHI Cantt, ( Call Me )-8377877756-Female Escort- In Delhi / Ncr
 
PSCC - Capability Statement Presentation
PSCC - Capability Statement PresentationPSCC - Capability Statement Presentation
PSCC - Capability Statement Presentation
 
Cybersecurity Awareness Training Presentation v2024.03
Cybersecurity Awareness Training Presentation v2024.03Cybersecurity Awareness Training Presentation v2024.03
Cybersecurity Awareness Training Presentation v2024.03
 
Digital Transformation in the PLM domain - distrib.pdf
Digital Transformation in the PLM domain - distrib.pdfDigital Transformation in the PLM domain - distrib.pdf
Digital Transformation in the PLM domain - distrib.pdf
 
FULL ENJOY Call girls in Paharganj Delhi | 8377087607
FULL ENJOY Call girls in Paharganj Delhi | 8377087607FULL ENJOY Call girls in Paharganj Delhi | 8377087607
FULL ENJOY Call girls in Paharganj Delhi | 8377087607
 
Case study on tata clothing brand zudio in detail
Case study on tata clothing brand zudio in detailCase study on tata clothing brand zudio in detail
Case study on tata clothing brand zudio in detail
 
MAHA Global and IPR: Do Actions Speak Louder Than Words?
MAHA Global and IPR: Do Actions Speak Louder Than Words?MAHA Global and IPR: Do Actions Speak Louder Than Words?
MAHA Global and IPR: Do Actions Speak Louder Than Words?
 
Marketplace and Quality Assurance Presentation - Vincent Chirchir
Marketplace and Quality Assurance Presentation - Vincent ChirchirMarketplace and Quality Assurance Presentation - Vincent Chirchir
Marketplace and Quality Assurance Presentation - Vincent Chirchir
 
8447779800, Low rate Call girls in New Ashok Nagar Delhi NCR
8447779800, Low rate Call girls in New Ashok Nagar Delhi NCR8447779800, Low rate Call girls in New Ashok Nagar Delhi NCR
8447779800, Low rate Call girls in New Ashok Nagar Delhi NCR
 

Refactoring Conditional Dispatcher To Command

  • 1. Refactoring Conditional Dispatcher with Command (based on Refactoring to Patterns) Sreenivas Ananthakrishna
  • 2. let’s start with an example...
  • 4. so what can the ATM do?
  • 5. so what can the ATM do? ➡ Display the login screen when card is inserted
  • 6. so what can the ATM do? ➡ Display the login screen when card is inserted ➡ Authenticate the user
  • 7. so what can the ATM do? ➡ Display the login screen when card is inserted ➡ Authenticate the user ➡ Allow authenticated user to withdraw $$$
  • 9. Services Authentication View ATM Controller Account
  • 10. View ➡ renders the screen Services ➡ authenticates the user ➡ transfer/ debit money from account Controller ➡ handles requests from view
  • 11. let’s focus on building the ATMController...
  • 12. and in TDD fashion, the test come first!
  • 13. describe quot;an instance of quot;, ATMController do it quot;should render login when card is insertedquot; do view = mock(View) view.should_receive(:render). with(:login, {:account_id => 1234}) controller = ATMController.new view controller.handle :card_inserted, {:account_id => 1234} end end
  • 15. class ATMController def initialize view @view = view end def handle event, params @view.render :login, {:account_id => params[:account_id]} end end
  • 17. it quot;should raise error for unknown eventquot; do view = mock(View) view.should_not_receive(:render) controller = ATMController.new view lambda {controller.handle(:foo, {})}. should raise_error(RuntimeError, quot;cannot handle event fooquot;) end
  • 19. class ATMController def initialize view @view = view end def handle event, params if event == :card_inserted @view.render :login, {:account_id => params[:account_id]} else raise quot;cannot handle event #{event}quot; end end end
  • 21. it quot;should display withdraw menu when user has authenticatedquot; do view = mock(View) view.should_receive(:render).with(:withdraw_menu) authentication_service = mock(AuthenticationService) authentication_service.should_receive(:authenticate). with(1234, 5678). and_return(true) controller = ATMController.new view, authentication_service controller.handle :authenticate, {:account_id => 1234, :pin => 5678} end
  • 23. class ATMController def initialize view, authentication_service @authentication_service = authentication_service @view = view end def handle event, params case event when :card_inserted @view.render :login, {:account_id => params[:account_id]} when :authenticate if @authentication_service. authenticate(params[:account_id], params[:pin]) @view.render :withdraw_menu end else raise quot;cannot handle event #{event}quot; end en
  • 24. addition of new dependencies has broken other tests!
  • 26. it quot;should render login when card is insertedquot; do view = mock(View) view.should_receive(:render).with(:login, {:account_id => 1234}) authentication_service = mock(AuthenticationService) authentication_service.should_not_receive(:authenticate) controller = ATMController.new view , authentication_service controller.handle :card_inserted, {:account_id => 1234} end
  • 27. so, as the controller keeps handling new events...
  • 28. so, as the controller keeps handling new events... ๏ handle method keeps getting bloated
  • 29. so, as the controller keeps handling new events... ๏ handle method keeps getting bloated ๏ which means higher complexity
  • 30. so, as the controller keeps handling new events... ๏ handle method keeps getting bloated ๏ which means higher complexity ๏ adding new events requires changing the controller implementation
  • 31. so, as the controller keeps handling new events... ๏ handle method keeps getting bloated ๏ which means higher complexity ๏ adding new events requires changing the controller implementation ๏ addition of new receivers also affects existing test cases
  • 32. let’s see how we can simplify by refactoring to the Command
  • 35. Before def handle event, params case event when :card_inserted @view.render :login, {:account_id => params[:account_id]} when :authenticate if @authentication_service. authenticate(params[:account_id], params[:pin]) @view.render :withdraw_menu end else raise quot;cannot handle event #{event}quot; end end
  • 36. After def handle event, params case event when :card_inserted handle_card_inserted params when :authenticate handle_authenticate params else raise quot;cannot handle event #{event}quot; end end
  • 38. Before def handle_authenticate params if @authentication_service. authenticate(params[:account_id], params[:pin]) @view.render :withdraw_menu end end
  • 39. After def handle_authenticate params action = AuthenticateAction.new @view, @authentication_service action.execute params end
  • 41. class Action def execute params raise quot;not implemented!quot; end end class AuthenticateAction < Action def initialize view, authentication_service @view = view @authentication_service = authentication_service end def execute params if @authentication_service. authenticate(params[:account_id], params[:pin]) @view.render :withdraw_menu end end end
  • 42. configure the controller with map of actions
  • 43. class ATMController def initialize map @actions = map end def handle event, params if @actions.include? event @actions[event].execute params else raise quot;cannot handle event #{event}quot; end end end
  • 44. now, even the tests are simpler!
  • 45. describe quot;an instance of quot;, ATMController do it quot;should execute the action for the eventquot; do params = {'foo' => 'bar'} action = mock(Action) action.should_receive(:execute).with(params) controller = ATMController.new({:foo_event => action}) controller.handle(:foo_event, params) end it quot;should raise error for unknown eventquot; do controller = ATMController.new({}) lambda {controller.handle(:foo, {})}. should raise_error quot;cannot handle event fooquot; end end
  • 46. some points for discussion • Do we need a command pattern in dynamic languages ? • can we get away with using a block/ closure • What are the different ways in which these commands could be configured?