SlideShare une entreprise Scribd logo
1  sur  27
Télécharger pour lire hors ligne
Refactoring to the
State Design Pattern
    Jim Roepcke <jr@uvic.ca>
       CSC 578D Fall 2009
Motivation

• Improve the design of the GameStats
  application
 • Make it easier to understand at a glance
 • Make it easier to make improvements
Backup              Backup
Replica             Replica


          Primary
          Replica

Backup              Backup
Replica             Replica
Primary-Backup
• Bonjour can guarantee no more than one
  Primary replica can publish its service
• Multiple Backup replicas communicate with
  the Primary to keep all replicas synchronized
• Writes are made to the Primary and
  propagated back to the Backup replicas
• If the Primary fails, a Backup can take over.
  The remaining backups sync to the new
  Primary
failed to
     initial                                                                        become
                                                                                    primary


     start                        primary failed to start


    trying to                                                                       trying to
    become                                                                         connect to
    primary                                                                         primary


                                                                                 backup did start
primary did start                                       backup failed to start


                                          failed to
    primary                              connect to                                  backup
                                          primary


      stop                                                                            stop



    stopping                                                                        stopping
                                            error
    primary                                                                          backup



                    primary did stop                        backup did stop



                                           stopped
Context                             State

Request()                        Handle()




    state->Handle()
                      ConcreteStateA        ConcreteStateB

                      Handle()              Handle()
State
      Context
                             TransitionTo(Context c, State s)
                             Enter(Context c)
SetState(State s)
                             Leave(Context c)
Foo()
Bar()
                             Foo(StateContext c)
Baz()
                             Bar(StateContext c)
....
                             Baz(StateContext c)
                             ...

  state->Foo()
                                          BaseState
                                                                          this->Leave(c)
                             TransitionTo(Context c, State s)             c->SetState(s)
                             Enter(Context c)                             s->Enter(c)
                             Leave(Context c)

                             Foo(StateContext c)
                             Bar(StateContext c)
                             Baz(StateContext c)
                             ...


                        ConcreteStateA                ConcreteStateB
                                                                                   TransitionTo
                    Enter(Context c)                Foo(StateContext c)
                                                                               (c, ConcreteStateA)
                    Baz(StateContext c)             Bar(StateContext c)
primary



  stop



stopping
                               error
primary



           primary did stop



                              stopped
Original Code
    - (void) stop
{
!   if (self.state == GSGameControllerStatePrimary) {
!   ! self.state = GSGameControllerStateStopping;
!   ! [self uninstallServerTargets];
!   ! [_server stop];
!   ! self.state = GSGameControllerStateStopped;
!   } else if (self.state == GSGameControllerStateBackup) {
!   ! self.state = GSGameControllerStateStopping;
!   ! [_memberManager stopMonitoring:_primaryService];
!   ! [_clientToPrimary stop];
!   ! self.state = GSGameControllerStateStopped;
!   } else if (self.state != GSGameControllerStateStopped) {
!   ! self.state = GSGameControllerStateError;
!   }
}
First Refactoring
    - (oneway void) stop
{
     self.state = GSGameControllerStateStopping;
}
The Devil   (is in the details)

     - (void) setState: (GSGameControllerState)newState
{
!   GSGameControllerState oldState = _state;
!   _state = newState;
!   if (       _state == GSGameControllerStateTryingToFindPrimary) {
!   !     // [self findPrimary];
!   !     self.state = GSGameControllerStateTryingToBecomePrimary; // TODO: remove the findprimary state
!   } else if (_state == GSGameControllerStateTryingToBecomePrimary) {
!   !     [self startPrimaryServer];
!   } else if (_state == GSGameControllerStateFailedToBecomePrimary) {
!   !     [self tearDownPrimary];
!   !     // FIXME: this could be an endless loop of failing to become primary, put in a limit or something
!   !     self.state = GSGameControllerStateTryingToBecomePrimary;
!   } else if (_state == GSGameControllerStateTryingToConnectToPrimary) {
!   !     [self connectToPrimary];
!   } else if (_state == GSGameControllerStateFailedToConnectToPrimary) {
!   !     [self tearDownBackup];
!   !     self.state = GSGameControllerStateTryingToBecomePrimary;
!   } else if (_state == GSGameControllerStatePrimary) {
!   !     [self installServerTargets];
!   !     [self tellDelegate:_delegate performSelectorWithSelf:@selector(gameControllerDidBecomePrimary:)];
!   } else if (_state == GSGameControllerStateBackup) {
!   !     [self tellPrimaryWhoIAm];
!   !     [self monitorPrimary];
!   !     [self synchronizeWithPrimaryFromVersion:_game.version];
!   !     [self tellDelegate:_delegate performSelectorWithSelf:@selector(gameControllerDidBecomeBackup:)];
!   } else if (_state == GSGameControllerStateStopping) {
!   !     if (oldState == GSGameControllerStatePrimary) {
!   !     !    self.state = GSGameControllerStateStoppingPrimary;
!   !     } else if (oldState == GSGameControllerStateBackup) {
!   !     !    self.state = GSGameControllerStateStoppingBackup;
The Devil   (is in the details)

        !   !    } else if (oldState != GSGameControllerStateError) {
!   !       !    self.state = GSGameControllerStateStopped;
!   !       }
!   }   else if (_state == GSGameControllerStateStoppingPrimary) {
!   !       [self stopServicingBackups];
!   !       [_server stop];
!   !       // TODO: actually monitor the stop instead of just setting state to GSGameControllerStateStopped
!   !       self.state = GSGameControllerStateStopped;
!   }   else if (_state == GSGameControllerStateStoppingBackup) {
!   !       [self stopMonitoringPrimary];
!   !       [_clientToPrimary stop];
!   !       // TODO: actually monitor the stop instead of just setting state to GSGameControllerStateStopped
!   !       self.state = GSGameControllerStateStopped;
!   }   else if (_state == GSGameControllerStateStopped) {
!   !       if (oldState == GSGameControllerStatePrimary) {
!   !       !    [self tearDownPrimary];
!   !       } else ! if (oldState == GSGameControllerStateStoppingPrimary) {
!   !       !    [self tearDownPrimary];
!   !       } else if (oldState == GSGameControllerStateBackup) {
!   !       !    [self tearDownBackup];
!   !       } else if (oldState == GSGameControllerStateStoppingBackup) {
!   !       !    [self tearDownBackup];
!   !       }
!   !       [self tellDelegate:_delegate performSelectorWithSelf:@selector(gameControllerDidStop:)];
!   }   else if (_state == GSGameControllerStateError) {
!   !       if (oldState == GSGameControllerStateTryingToFindPrimary) {
!   !       !    [self tearDownPrimary];
!   !       } else if (oldState == GSGameControllerStateTryingToBecomePrimary) {
!   !       !    [self tearDownPrimary];
!   !       !    [self tellDelegate:_delegate performSelectorWithSelf:@selector(gameControllerFailedToStart:)];
!   !       } else if (oldState == GSGameControllerStateTryingToConnectToPrimary) {
The Devil   (is in the details)

      !   !    !    [self tearDownBackup];
!   !     !    [self tellDelegate:_delegate performSelectorWithSelf:@selector(gameControllerFailedToStart:)];
!   !     } else if (oldState == GSGameControllerStatePrimary) {
!   !     !    [self tearDownPrimary];
!   !     !    // TODO: should this tellDelegate gameControllerDidStop: ?
!   !     } else if (oldState == GSGameControllerStateBackup) {
!   !     !    [self tearDownBackup];
!   !     !    // TODO: should this tellDelegate gameControllerDidStop: ?
!   !     } else if (oldState == GSGameControllerStateStopping) {
!   !     !    [self tellDelegate:_delegate performSelectorWithSelf:@selector(gameControllerFailedToStop:)];
!   !     !    // TODO: should this tellDelegate gameControllerDidStop: ?
!   !     } else if (oldState == GSGameControllerStateStoppingPrimary) {
!   !     !    [self tearDownPrimary];
!   !     !    // TODO: should this tellDelegate gameControllerDidStop: ?
!   !     } else if (oldState == GSGameControllerStateStoppingBackup) {
!   !     !    [self tearDownBackup];
!   !     !    // TODO: should this tellDelegate gameControllerDidStop: ?
!   !     }
!   !     /* else ??? */ [self tellDelegate:_delegate
performSelectorWithSelf:@selector(gameControllerErrorOccurred:)];
!   }
}
First Refactoring
           - (oneway void) stop
           {
                self.state = GSGameControllerStateStopping;
           }




- (void) setState: (GSGameControllerState)newState
{
! GSGameControllerState oldState = _state;
! _state = newState;
} else if (_state == GSGameControllerStateStopping) {
     if (oldState == GSGameControllerStatePrimary) {
         self.state = GSGameControllerStateStoppingPrimary;
     } else if (oldState == GSGameControllerStateBackup) {
         self.state = GSGameControllerStateStoppingBackup;
     } else if (oldState != GSGameControllerStateError) {
         self.state = GSGameControllerStateStopped;
     }
}
} else if (_state == GSGameControllerStateStoppingPrimary) {
    [self stopServicingBackups];
    [_server stop];
    self.state = GSGameControllerStateStopped;
}
} else if (_state == GSGameControllerStateStopped) {
    if (oldState == GSGameControllerStatePrimary) {
        [self tearDownPrimary];
    } else if (oldState == GSGameControllerStateStoppingPrimary) {
        [self tearDownPrimary];
    } else if (oldState == GSGameControllerStateBackup) {
        [self tearDownBackup];
    } else if (oldState == GSGameControllerStateStoppingBackup) {
        [self tearDownBackup];
    }
    [self tellDelegate:_delegate
        performSelectorWithSelf:
            @selector(gameControllerDidStop:)];
}
State Refactoring

    - (oneway void) stop
{
      [self.state stop: self];
}
Stopping a primary
@implementation GSGameControllerStatePrimary

- (void) enter: (GSGameController *)gc
{
! [gc installServerTargets];
}

- (void) error: (GSGameController *)gc
{
! [gc tearDownPrimary];
! [super error: gc];
}

- (void) incrementIntegerForKey: (id)aKey context: (GSGameController *)gc
{
! [gc primaryIncrementIntegerForKey: aKey];
}

- (void) stop: (GSGameController *)gc
{
! [self transition: gc to: [GSGameControllerStateStoppingPrimary state]];
}

@end
Only I know how
@implementation GSGameControllerStateStoppingPrimary

- (void) enter: (GSGameController *)gc
{
! [gc stopServicingBackups];
}

- (void) error: (GSGameController *)gc
{
! [gc tearDownPrimary];
! [super error: gc];
}

- (void) primaryDidStop: (GSGameController *)gc
{
! [gc tearDownPrimary];
! [self transition: gc to: [GSGameControllerStateStopped state]];
}

@end
Transition to stopped
@implementation GSGameControllerStateStoppingPrimary

- (void) enter: (GSGameController *)gc
{
! [gc stopServicingBackups];
}

- (void) error: (GSGameController *)gc
{
! [gc tearDownPrimary];
! [super error: gc];
}

- (void) primaryDidStop: (GSGameController *)gc
{
! [gc tearDownPrimary];
! [self transition: gc to: [GSGameControllerStateStopped state]];
}

@end
Done
@implementation GSGameControllerStateStopped

- (void) enter: (GSGameController *)gc
{
    [gc tellDelegate:gc.delegate
        performSelectorWithSelf:
            @selector(gameControllerDidStop:)];
}

@end
Same result on stop
} else if (_state == GSGameControllerStateStopped) {
    if (oldState == GSGameControllerStatePrimary) {
        [self tearDownPrimary];
    } else if (oldState == GSGameControllerStateStoppingPrimary) {
        [self tearDownPrimary];
    } else if (oldState == GSGameControllerStateBackup) {
        [self tearDownBackup];
    } else if (oldState == GSGameControllerStateStoppingBackup) {
        [self tearDownBackup];
    }
    [self tellDelegate:_delegate
        performSelectorWithSelf:
            @selector(gameControllerDidStop:)];
}
Result
• GSGameController only knows its own
  operations
 • Not states or transitions
 • Separation of concerns
• Each state is a black box
 • Doesn’t know details of other states
Motivation

• Improve the design of the GameStats
  application
 • Make it easier to understand at a glance
 • Make it easier to make improvements
Conclusion

The State Design Pattern
made complex code easier
to understand and modify
Questions?

The State Design Pattern
made complex code easier
to understand and modify

Contenu connexe

Dernier

Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Bhuvaneswari Subramani
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Victor Rentea
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusZilliz
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...Zilliz
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfOrbitshub
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxRemote DBA Services
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxRustici Software
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWERMadyBayot
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Jeffrey Haguewood
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsNanddeep Nachan
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024The Digital Insurer
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityWSO2
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...apidays
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistandanishmna97
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Victor Rentea
 

Dernier (20)

Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 

En vedette

How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthThinkNow
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfmarketingartwork
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024Neil Kimberley
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Applitools
 
12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at WorkGetSmarter
 

En vedette (20)

How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
 
12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work
 
ChatGPT webinar slides
ChatGPT webinar slidesChatGPT webinar slides
ChatGPT webinar slides
 

Refactoring to the State Design Pattern

  • 1. Refactoring to the State Design Pattern Jim Roepcke <jr@uvic.ca> CSC 578D Fall 2009
  • 2. Motivation • Improve the design of the GameStats application • Make it easier to understand at a glance • Make it easier to make improvements
  • 3. Backup Backup Replica Replica Primary Replica Backup Backup Replica Replica
  • 4. Primary-Backup • Bonjour can guarantee no more than one Primary replica can publish its service • Multiple Backup replicas communicate with the Primary to keep all replicas synchronized • Writes are made to the Primary and propagated back to the Backup replicas • If the Primary fails, a Backup can take over. The remaining backups sync to the new Primary
  • 5. failed to initial become primary start primary failed to start trying to trying to become connect to primary primary backup did start primary did start backup failed to start failed to primary connect to backup primary stop stop stopping stopping error primary backup primary did stop backup did stop stopped
  • 6. Context State Request() Handle() state->Handle() ConcreteStateA ConcreteStateB Handle() Handle()
  • 7. State Context TransitionTo(Context c, State s) Enter(Context c) SetState(State s) Leave(Context c) Foo() Bar() Foo(StateContext c) Baz() Bar(StateContext c) .... Baz(StateContext c) ... state->Foo() BaseState this->Leave(c) TransitionTo(Context c, State s) c->SetState(s) Enter(Context c) s->Enter(c) Leave(Context c) Foo(StateContext c) Bar(StateContext c) Baz(StateContext c) ... ConcreteStateA ConcreteStateB TransitionTo Enter(Context c) Foo(StateContext c) (c, ConcreteStateA) Baz(StateContext c) Bar(StateContext c)
  • 8. primary stop stopping error primary primary did stop stopped
  • 9. Original Code - (void) stop { ! if (self.state == GSGameControllerStatePrimary) { ! ! self.state = GSGameControllerStateStopping; ! ! [self uninstallServerTargets]; ! ! [_server stop]; ! ! self.state = GSGameControllerStateStopped; ! } else if (self.state == GSGameControllerStateBackup) { ! ! self.state = GSGameControllerStateStopping; ! ! [_memberManager stopMonitoring:_primaryService]; ! ! [_clientToPrimary stop]; ! ! self.state = GSGameControllerStateStopped; ! } else if (self.state != GSGameControllerStateStopped) { ! ! self.state = GSGameControllerStateError; ! } }
  • 10. First Refactoring - (oneway void) stop { self.state = GSGameControllerStateStopping; }
  • 11. The Devil (is in the details) - (void) setState: (GSGameControllerState)newState { ! GSGameControllerState oldState = _state; ! _state = newState; ! if ( _state == GSGameControllerStateTryingToFindPrimary) { ! ! // [self findPrimary]; ! ! self.state = GSGameControllerStateTryingToBecomePrimary; // TODO: remove the findprimary state ! } else if (_state == GSGameControllerStateTryingToBecomePrimary) { ! ! [self startPrimaryServer]; ! } else if (_state == GSGameControllerStateFailedToBecomePrimary) { ! ! [self tearDownPrimary]; ! ! // FIXME: this could be an endless loop of failing to become primary, put in a limit or something ! ! self.state = GSGameControllerStateTryingToBecomePrimary; ! } else if (_state == GSGameControllerStateTryingToConnectToPrimary) { ! ! [self connectToPrimary]; ! } else if (_state == GSGameControllerStateFailedToConnectToPrimary) { ! ! [self tearDownBackup]; ! ! self.state = GSGameControllerStateTryingToBecomePrimary; ! } else if (_state == GSGameControllerStatePrimary) { ! ! [self installServerTargets]; ! ! [self tellDelegate:_delegate performSelectorWithSelf:@selector(gameControllerDidBecomePrimary:)]; ! } else if (_state == GSGameControllerStateBackup) { ! ! [self tellPrimaryWhoIAm]; ! ! [self monitorPrimary]; ! ! [self synchronizeWithPrimaryFromVersion:_game.version]; ! ! [self tellDelegate:_delegate performSelectorWithSelf:@selector(gameControllerDidBecomeBackup:)]; ! } else if (_state == GSGameControllerStateStopping) { ! ! if (oldState == GSGameControllerStatePrimary) { ! ! ! self.state = GSGameControllerStateStoppingPrimary; ! ! } else if (oldState == GSGameControllerStateBackup) { ! ! ! self.state = GSGameControllerStateStoppingBackup;
  • 12. The Devil (is in the details) ! ! } else if (oldState != GSGameControllerStateError) { ! ! ! self.state = GSGameControllerStateStopped; ! ! } ! } else if (_state == GSGameControllerStateStoppingPrimary) { ! ! [self stopServicingBackups]; ! ! [_server stop]; ! ! // TODO: actually monitor the stop instead of just setting state to GSGameControllerStateStopped ! ! self.state = GSGameControllerStateStopped; ! } else if (_state == GSGameControllerStateStoppingBackup) { ! ! [self stopMonitoringPrimary]; ! ! [_clientToPrimary stop]; ! ! // TODO: actually monitor the stop instead of just setting state to GSGameControllerStateStopped ! ! self.state = GSGameControllerStateStopped; ! } else if (_state == GSGameControllerStateStopped) { ! ! if (oldState == GSGameControllerStatePrimary) { ! ! ! [self tearDownPrimary]; ! ! } else ! if (oldState == GSGameControllerStateStoppingPrimary) { ! ! ! [self tearDownPrimary]; ! ! } else if (oldState == GSGameControllerStateBackup) { ! ! ! [self tearDownBackup]; ! ! } else if (oldState == GSGameControllerStateStoppingBackup) { ! ! ! [self tearDownBackup]; ! ! } ! ! [self tellDelegate:_delegate performSelectorWithSelf:@selector(gameControllerDidStop:)]; ! } else if (_state == GSGameControllerStateError) { ! ! if (oldState == GSGameControllerStateTryingToFindPrimary) { ! ! ! [self tearDownPrimary]; ! ! } else if (oldState == GSGameControllerStateTryingToBecomePrimary) { ! ! ! [self tearDownPrimary]; ! ! ! [self tellDelegate:_delegate performSelectorWithSelf:@selector(gameControllerFailedToStart:)]; ! ! } else if (oldState == GSGameControllerStateTryingToConnectToPrimary) {
  • 13. The Devil (is in the details) ! ! ! [self tearDownBackup]; ! ! ! [self tellDelegate:_delegate performSelectorWithSelf:@selector(gameControllerFailedToStart:)]; ! ! } else if (oldState == GSGameControllerStatePrimary) { ! ! ! [self tearDownPrimary]; ! ! ! // TODO: should this tellDelegate gameControllerDidStop: ? ! ! } else if (oldState == GSGameControllerStateBackup) { ! ! ! [self tearDownBackup]; ! ! ! // TODO: should this tellDelegate gameControllerDidStop: ? ! ! } else if (oldState == GSGameControllerStateStopping) { ! ! ! [self tellDelegate:_delegate performSelectorWithSelf:@selector(gameControllerFailedToStop:)]; ! ! ! // TODO: should this tellDelegate gameControllerDidStop: ? ! ! } else if (oldState == GSGameControllerStateStoppingPrimary) { ! ! ! [self tearDownPrimary]; ! ! ! // TODO: should this tellDelegate gameControllerDidStop: ? ! ! } else if (oldState == GSGameControllerStateStoppingBackup) { ! ! ! [self tearDownBackup]; ! ! ! // TODO: should this tellDelegate gameControllerDidStop: ? ! ! } ! ! /* else ??? */ [self tellDelegate:_delegate performSelectorWithSelf:@selector(gameControllerErrorOccurred:)]; ! } }
  • 14. First Refactoring - (oneway void) stop { self.state = GSGameControllerStateStopping; } - (void) setState: (GSGameControllerState)newState { ! GSGameControllerState oldState = _state; ! _state = newState;
  • 15. } else if (_state == GSGameControllerStateStopping) { if (oldState == GSGameControllerStatePrimary) { self.state = GSGameControllerStateStoppingPrimary; } else if (oldState == GSGameControllerStateBackup) { self.state = GSGameControllerStateStoppingBackup; } else if (oldState != GSGameControllerStateError) { self.state = GSGameControllerStateStopped; } }
  • 16. } else if (_state == GSGameControllerStateStoppingPrimary) { [self stopServicingBackups]; [_server stop]; self.state = GSGameControllerStateStopped; }
  • 17. } else if (_state == GSGameControllerStateStopped) { if (oldState == GSGameControllerStatePrimary) { [self tearDownPrimary]; } else if (oldState == GSGameControllerStateStoppingPrimary) { [self tearDownPrimary]; } else if (oldState == GSGameControllerStateBackup) { [self tearDownBackup]; } else if (oldState == GSGameControllerStateStoppingBackup) { [self tearDownBackup]; } [self tellDelegate:_delegate performSelectorWithSelf: @selector(gameControllerDidStop:)]; }
  • 18. State Refactoring - (oneway void) stop { [self.state stop: self]; }
  • 19. Stopping a primary @implementation GSGameControllerStatePrimary - (void) enter: (GSGameController *)gc { ! [gc installServerTargets]; } - (void) error: (GSGameController *)gc { ! [gc tearDownPrimary]; ! [super error: gc]; } - (void) incrementIntegerForKey: (id)aKey context: (GSGameController *)gc { ! [gc primaryIncrementIntegerForKey: aKey]; } - (void) stop: (GSGameController *)gc { ! [self transition: gc to: [GSGameControllerStateStoppingPrimary state]]; } @end
  • 20. Only I know how @implementation GSGameControllerStateStoppingPrimary - (void) enter: (GSGameController *)gc { ! [gc stopServicingBackups]; } - (void) error: (GSGameController *)gc { ! [gc tearDownPrimary]; ! [super error: gc]; } - (void) primaryDidStop: (GSGameController *)gc { ! [gc tearDownPrimary]; ! [self transition: gc to: [GSGameControllerStateStopped state]]; } @end
  • 21. Transition to stopped @implementation GSGameControllerStateStoppingPrimary - (void) enter: (GSGameController *)gc { ! [gc stopServicingBackups]; } - (void) error: (GSGameController *)gc { ! [gc tearDownPrimary]; ! [super error: gc]; } - (void) primaryDidStop: (GSGameController *)gc { ! [gc tearDownPrimary]; ! [self transition: gc to: [GSGameControllerStateStopped state]]; } @end
  • 22. Done @implementation GSGameControllerStateStopped - (void) enter: (GSGameController *)gc { [gc tellDelegate:gc.delegate performSelectorWithSelf: @selector(gameControllerDidStop:)]; } @end
  • 23. Same result on stop } else if (_state == GSGameControllerStateStopped) { if (oldState == GSGameControllerStatePrimary) { [self tearDownPrimary]; } else if (oldState == GSGameControllerStateStoppingPrimary) { [self tearDownPrimary]; } else if (oldState == GSGameControllerStateBackup) { [self tearDownBackup]; } else if (oldState == GSGameControllerStateStoppingBackup) { [self tearDownBackup]; } [self tellDelegate:_delegate performSelectorWithSelf: @selector(gameControllerDidStop:)]; }
  • 24. Result • GSGameController only knows its own operations • Not states or transitions • Separation of concerns • Each state is a black box • Doesn’t know details of other states
  • 25. Motivation • Improve the design of the GameStats application • Make it easier to understand at a glance • Make it easier to make improvements
  • 26. Conclusion The State Design Pattern made complex code easier to understand and modify
  • 27. Questions? The State Design Pattern made complex code easier to understand and modify