Design Mode (17) state mode state (object behavior type)

Source: Internet
Author: User

Design Mode (17) State mode State (object behavior type)

1. Overview

During the software development process, the application may make different processing based on different situations. The most direct solution is to consider all possible situations. Then, use the if... ellse statement to determine the status for processing in different situations. However, the judgment on the complex status seems to be "Powerless ". When a new State or
The increase or modification of else (or switch case) statements may cause great changes, and the readability and scalability of the program may also become weak. Maintenance is also very troublesome. Then I will consider only modifying the mode of my own status.

Example 1: A button is used to control the status of an elevator. An elevator is opened, closed, stopped, and running. Each status change may be updated based on other statuses. For example, you cannot open the door when running, but you can only open the door after the elevator is set.

Example 2: When we call a mobile phone, the following situations may occur: User Startup, user shutdown, user suspension due to overdue payment, and user elimination. So when we call this number: The system determines whether the user is in the starting and not busy status, or shut down or in arrears. However, no matter the status, we should provide corresponding processing operations.

2. Problem

How do objects behave differently in each state?

3. Solution

State mode: allows an object to change its behavior when its internal state changes. The object seems to have modified its class.

In many cases, the behavior of an object depends on one or more dynamically changing attributes. Such attributes are called states, and such objects are called stateful objects, such an object state is obtained from a series of defined values. When such an object interacts with an external event, its internal status changes, and the behavior of the system also changes.

4. Applicability

The State mode can be used in the following two cases:
1 )•
The behavior of an object depends on its state, and it must change its behavior according to its state at runtime.
2) • The Code contains a large number of condition statements related to the object state: An operation contains a large multi-branch condition (if else (or switch case) statement, and these branches depend on the state of the object. This state is usually represented by one or more enumerated constants. Usually
Multiple operations contain the same condition structure. In State mode, each condition branch is placed in an independent class. This allows you to take the object state as an object based on the object's own situation. This object can be independent of other objects.

5. Structure

6. Composition of the Mode

Context: defines the interface that the customer is interested in. Maintain an instance of the ConcreteState subclass, which defines the current status.
Abstract State class: defines an interface to encapsulate a behavior related to a specific State of Context.
ConcreteState: each subclass implements a state-related behavior related to the Context.

7. Effect

The State mode has the following effects:
Advantages of status mode:
1) It will localize the behavior related to a specific State and separate the behavior of different States: State mode puts all the behavior related to a specific State into an object. Because all status-related code exists in a State subclass, it is easy to add new States and transformations by defining a new subclass. Another way is to use the data value to define the internal status and let the Context operation explicitly check the data. However, this will make the implementation of the entire Context spread across seemingly similar conditions such as if else statements or switch case statements. To add a new status, you may need to change several operations,
This makes maintenance complicated. The State mode avoids this problem, but may introduce another problem because it distributes the behavior of different States in multiple State subclasses. This increases the number of child classes, which is less compact than the implementation of a single class. However, if there are many States, such distribution is actually better. Otherwise, a huge conditional statement is required. As with a long process, large conditional statements are undesirable. They form a large block and make the code unclear, which makes it difficult to modify and expand them. The State mode provides a better way to organize Code related to a specific State. The logic for determining State transfer is not in the I f or s w I t c h Statement of a single block,
It is distributed among the State subclass. Encapsulate each state transition and action into a class, and the focus is raised from the execution state to the state of the entire object. This makes the code structured and clearer.

2) It makes the State Transition explicit: when an object only defines the current state with internal data values, its state only shows assigning values to some variables, which is not clear enough. Introducing independent objects for different States makes the conversion clearer. In addition, the State object ensures that the Context does not have inconsistent internal states, because from the Context perspective, state conversion is atomic-you only need to re-bind a variable (that is, the State object variable of Context), instead of assigning values to multiple variables.

3) State objects can be shared. If the State objects do not have instance variables-that is, the States they represent are fully encoded in their types-then each Context object can share a State object. When States are shared in this way, they must be lightweight objects with no internal status and only behavior.

Disadvantages of status mode:
1) The use of the State mode will inevitably increase the number of System Classes and objects.
2) the structure and implementation of the state mode are complicated. Improper use will lead to confusion of the program structure and code.

8. Implementation

We use the elevator example to describe:

Simple implementation code:

<? Phpabstract class ILift {// four states of the elevator const OPENING_STATE = 1; // The open state const CLOSING_STATE = 2; // The closed state const RUNNING_STATE = 3; // running status const STOPPING_STATE = 4; // stop status; // set the elevator status public abstract function setState ($ state ); // first, the elevator door opens public abstract function open (); // when the elevator door is opened, public abstract function close () is also disabled; // The elevator must be able to go up and down, run public abstract function run (); // The elevator must be able to stop. If it cannot be stopped, public abstract function stop ();} /*** elevator implementation class */class Lift extends ILift {private $ state; public function setState ($ state) {$ this-> state = $ state ;} // elevator door closed public function close () {// under which state the elevator can be closed switch ($ this-> state) {case ILift: OPENING_STATE: // If yes, you can close the door and change the elevator Status $ this-> setState (ILift: CLOSING_STATE); break; case ILift: CLOSING_STATE: // if the elevator is closed, then do nothing // do nothing; return; break; case ILift: RUNNING_STATE: // if it is running, the door is closed, it also means that none of them will do // do nothing; return; break; case ILift: STOPPING_STATE: // If the status is stopped, this is also disabled and nothing will be done. // do nothing; return; break;} echo 'lift colse <br> ';} // enable public function open () on the elevator door () {// status in which the elevator can be switched ($ this-> state) {case ILift: OPENING_STATE: // if the elevator is already open, then do nothing // do nothing; return; break; case ILift: CLOSING_STATE: // if the elevator is closed, you can enable $ this-> setState (ILift :: OPENING_STATE); break; case ILift: RUNNING_STATE: // in the running state, you cannot open the door and do nothing. // do nothing; return; break; case ILift: STOPPING_STATE: // The stop status. You have to open the door. $ this-> setState (ILift: OPENING_STATE); break;} echo 'lift open <br> ';} /// when the elevator starts running, the public function run () {switch ($ this-> state) {case ILift: OPENING_STATE: // if the door is already open, if the elevator is not running, do nothing // do nothing; return; break; case ILift: CLOSING_STATE: // if the elevator is closed, you can run $ this-> setState (ILift: RUNNING_STATE); break; case ILift: RUNNING_STATE: // in the running state, so that nothing is done // do nothing; return; break; case ILift: STOPPING_STATE: // stop status. You can run $ this-> setState (ILift: RUNNING_STATE);} echo 'lift run <br> ';} // stop the public function stop () {switch ($ this-> state) {case ILift: OPENING_STATE: // if the door is already open, you must stop first and do nothing. // do nothing; return; break; case ILift: CLOSING_STATE: // if the elevator is closed, of course, you can stop $ this-> setState (ILift: CLOSING_STATE); break; case ILift: RUNNING_STATE: // in the running state, of course, it will stop $ this-> setState (ILift: CLOSING_STATE); break; case ILift: STOPPING_STATE: // stop state, do nothing // do nothing; return; break;} echo 'lift stop <br> ';}}$ Lift = new lift (); // The initial condition of the elevator should be the stop Status $ lift-> setState (ILift: STOPPING_STATE); // the elevator door is opened first, and people enter $ lift-> open (); // close the elevator door $ lift-> close (); // then, run the elevator up or down $ lift-> run (); // The elevator finally reaches the destination, lift down $ lift-> stop ();

Obviously we have completed our basic business operations, but we have used a lot of switches in the program... Such as case (if... The same is true for else). First, the readability of the program is poor, and second, expansion is inconvenient. Once a new status is added, such as power-on and breakpoint status. We are bound to add the corresponding case statement in each business method. That is, the case statements must be modified for the four functions open, close, run, and stop.

State mode: distributes operations in different states to different State objects for completion. Look at the uml class diagram of the Status class:


Code implementation:

<? Php/***** define an elevator interface */abstract class LiftState {// define an environmental role, that is, functional changes caused by changes in the encapsulation status protected $ _ context; public function setContext (Context $ context) {$ this-> _ context = $ context;} // first, the elevator door opens the public abstract function open (); // the elevator door is enabled, of course, public abstract function close () is disabled. // The elevator must be able to go up and down and run public abstract function run (); // The elevator must be able to stop, public abstract function stop ();}/*** environment class: defines the interface that the customer is interested in. Maintain an instance of the ConcreteState subclass, which defines the current status. */Class Context {// define all elevator States static $ openningState = null; static $ closeingState = null; static $ runningState = null; static $ stoppingState = null; public function _ construct () {self ::$ openningState = new OpenningState (); self ::$ closeingState = new ClosingState (); self :: $ runningState = new RunningState (); self: $ stoppingState = new StoppingState () ;}// set the current elevator status private $ _ liftState; public function getLif TState () {return $ this-> _ liftState;} public function setLiftState ($ liftState) {$ this-> _ liftState = $ liftState; // notify the current environment to each implementation class $ this-> _ liftState-> setContext ($ this);} public function open () {$ this-> _ liftState-> open ();} public function close () {$ this-> _ liftState-> close ();} public function run () {$ this-> _ liftState-> run ();} public function stop () {$ this-> _ liftState-> stop ();}} /*** what can I do when the elevator door is open */class Ope NningState extends LiftState {/*** can be disabled if enabled. I just want to test the elevator door switch function **/public function close () {// modify the status $ this-> _ context-> setLiftState (Context: $ closeingState ); // The Action delegate is CloseState to execute $ this-> _ context-> getLiftState ()-> close () ;}// open the elevator door public function open () {echo 'lift open... ',' <br/> ';} // you want to run when the door is in the elevator. This elevator can scare you! Public function run () {// do nothing;} // the door is not stopped yet? Public function stop () {// do nothing ;}/ *** what can the elevator do after the elevator door is closed */class ClosingState extends LiftState {// the elevator door is closed, this is the public function close () {echo 'lift close... ',' <br/> ';} // you can open the elevator door after it is closed () {$ this-> _ context-> setLiftState (Context: $ openningState); // set it to open state $ this-> _ context-> getLiftState () -> open ();} // when the elevator door is closed, it will run normally, but public function run () {$ this-> _ context-> setLiftState (Context: $ runningState); // set it to running state; $ this-> _ context-> getLiftState ()-> run ();} // the elevator door is closed, I will not press the floor public function stop () {$ this-> _ context-> setLiftState (Context: $ stoppingState); // set it to the stop State; $ this-> _ context-> getLiftState ()-> stop ();}} /*** What actions can an elevator perform in the running state */class RunningState extends LiftState {// is the elevator door closed? Are you sure you want to open the elevator door when the public function close () {// do nothing} // is running? You're crazy! The elevator will not open the public function open () {// do nothing} // This is the method to be implemented in the running state public function run () {echo 'lift run... ',' <br/> ';} // This is absolutely reasonable. Who can do this elevator without stopping the light ?! It is estimated that only God has public function stop () {$ this-> _ context-> setLiftState (Context: $ stoppingState); // The environment is set to stop; $ this-> _ context-> getLiftState ()-> stop ();}} /*** what can be done in the stopped state */class StoppingState extends LiftState {// The stopped state is closed? The elevator door was originally closed! Public function close () {// do nothing;} // stop status, open the door, that is required! Public function open () {$ this-> _ context-> setLiftState (Context: $ openningState); $ this-> _ context-> getLiftState () -> open () ;}// stop and run again. Normally, public function run () {$ this-> _ context-> setLiftState (Context: $ runningState ); $ this-> _ context-> getLiftState ()-> run ();} // how does the Stop State occur? Of course, the stop method executes the public function stop () {echo 'lift stop... ',' <br/> '; }}/ *** simulate elevator action */class Client {public static function main () {$ context = new Context (); $ context-> setLiftState (new ClosingState (); $ context-> open (); $ context-> close (); $ context-> run (); $ context-> stop () ;}} Client: main ();

9. Other related models

1) responsibility chain model,
Both the responsibility chain mode and the status mode can solve the problem of too many If branch statements,
From the definition, the state mode is an internal state change of an object (an object is relatively stable, and the processing of the next object after processing is generally determined ),
The responsibility chain mode is a change between multiple objects (if there are multiple objects, a certain object does not exist now, just like the company leave process we took for example, managers may not be in the company.) This also indicates that the two models of managers are different.
The biggest difference between the two design patterns is that the state pattern is to let each State object know who the next processing object is.
In the responsibility chain mode, each object does not specify who the next object to be processed. It is set only on the client.
In our popular programming language
Status mode:
Equivalent to If else if else;
Design path: internal implementation of each State class (equivalent to the conditions in If and else If)
The Context method is called by State during execution.
Responsibility Chain Mode:
Equivalent to swich case
Design route: set by the customer. The parameter of each sub-class (CASE) is the next sub-class (CASE ).
In use, you can pass parameters to the execution method of the first subclass of the chain.
Just like a Summary of the design model, some people adopt the state model. From the very beginning to the end, they must define who the next processing object is, and I use the responsibility chain model, it is possible to adjust the chain order at any time.

2) Policy mode: (http://www.cnblogs.com/Mainz/archive/2007/12/15/996081.html) (State mode is the twin brother of the Policy mode)
The implementation methods of the state mode and the policy mode are very similar. They all use polymorphism to allocate some operations to a group of related simple classes, therefore, many people think that these two models are actually the same.
However, in the real world, Strategy (such as a product promotion strategy) and status (like a button to control the status of an elevator, or a button on the mobile phone interface to control the mobile phone) there are two completely different ideas. When we model the status and policy, this difference will lead to completely different problems. For example, State migration is the core content for state modeling. However, when selecting a policy, migration has nothing to do with this. In addition, the Policy mode allows a customer to select or provide a policy, which is completely absent in the state mode.
A policy is a plan or scheme. By executing this plan or scheme, we can achieve a specific goal under a given input condition. A policy is a set of solutions that can be replaced with each other. Select a policy to obtain the output of the policy. The rule mode is used when different behaviors are taken in different external environments. We can refer to the Strategy implementation method for creating objects in the underlying object builder of the Microsoft Enterprise Library. The State mode is different. For an object with a State that is particularly important, the state machine is used to model the state of an object. The core issue of state mode processing is State migration, in the case of many States of an object, the jump and migration process between States of each business flow is complicated.
For example, if a workflow is used to approve a file, it may be created, submitted, modified, approved by the HR department, approved by the boss, rejected by the HR department, rejected by the boss, or rejected by the boss, it involves multiple role interactions and many events. In this case, it is more appropriate to use state mode (state machine) for modeling; encapsulate various states and corresponding implementation steps into a group of classes that simply inherit from an interface or abstract class, and use another Context to perform automatic state transformation between them, events are used to automatically jump between States. There is a State migration curve throughout the lifecycle, which is transparent to customers. We can refer to Microsoft's latest WWF state machine workflow Implementation ideas.
In the state mode, the state change is determined by the internal conditions of the object. The outside world only needs to care about its interface, and does not need to care about the creation and conversion of its State object;
In the policy mode, the policy is determined by the external condition (C.
Their application scenarios (purposes) are different. The State mode emphasizes the change of the object's internal State to change the object's behavior. The Strategy Mode focuses on the choice of external policies, and the choice of policies is determined by external conditions,
That is to say, the algorithm is dynamically switched. However, because their structure is so similar, we can think that "state mode is a fully encapsulated and self-modified policy mode ". That is, the state mode encapsulates the state inside the object, while the policy mode encapsulates the state of the algorithm family.

10. Summary and Analysis

The main advantage of the State mode is that it encapsulates the conversion rules and enumerates possible states. It puts all actions related to a State into a class and can conveniently add new States, you only need to change the object State to change the object behavior. You can also share multiple environment objects with one State object to reduce the number of objects in the system; its disadvantage is that using the state mode will increase the number of System Classes and objects, and the structure and implementation of the state mode are complicated. Improper use will lead to confusion of program structure and code, the status mode that can be switched does not meet the requirements of the "Open and Close principle.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.