Use C ++ to implement a simple state machine model-instance

Source: Internet
Author: User

Use C ++ to implement a simple state machine model-instance

Generally, a state machine is a method to express the logic of state transition. Someone once discussed with me why I should not use ifelse directly, but use the "State Machine" to implement some logic. I think using the "State Machine" is a brilliant performance. However, the use of ifelse for changes and redirection of large and complex logic brings disadvantages such as difficulty in reading code. In fact, ifelse is also a method of state machine implementation.

Previously, we had a strong relationship between the business and the operating system, and we wanted to clearly describe the process of each sub-business in the entire business, so we introduced the state machine description method. However, the state machine at that time was described using the if else method. It seems that the entire process is bloated and not clear enough to read. So I tried to introduce a third-party State Library to restructure this business-such as the State Library in boost. However, I felt a lot of inconvenience during the use process. Simply implement a clear and elegant state machine model. (For details, refer to the csdn blog for breaksoftware)

Before writing a model, we need to know what a state machine is. I found several results on the search engine, but most of them were academic. The realization of a large, comprehensive, all-encompassing, universal state machine model is not my original design intention. The state machine that I designed has the following features: single thread and history. A single thread means that our state machine runs inside a thread and is not disturbed by other threads. In this way, we do not need to consider multi-thread programming during design. History is a concept in a state machine. It records only the final exit state of the highest layer of compound state. If you do not know this feature, you can search for it first. In practice, this feature is very useful.

We will introduce this state machine to a simple and possibly inappropriate example. First, we design an Application Scenario: Install and run software on the user's computer. In this scenario, we can split it into the following logic:

Check whether to install and download the installation package, decompress the installation package, and install and run it.

These four logics are not complex. We define them as the basic State-a State that can last for a period of time and the internal execution logic we don't care about. To make this logic a little more complex, we design the following requirements:

If the software is not installed:

After downloading the installation package from address A fails, download the installation package from address B fails. After downloading the installation package from address C fails, check whether the CPU usage is busy.
If the CPU is busy, check whether the CPU is busy. If the CPU is not busy, decompress the package and try again. If the previous one is downloaded from address A, the current one is downloaded from address B. If the previous one is downloaded from address B, the download will be downloaded again if the download from address C fails to run. If the previous one is downloaded from address A, the current one is downloaded from address B. If the previous one is downloaded from address B, if the download and run from the C address are successful, the execution is considered successful. If the software has been installed, uninstall the software if the run fails, then, if the logic "the software is not installed" runs successfully, the execution is considered successful.

We use the status chart as the representation:


In the figure, "Download compound state" is a compound state with a low history; "post-installation running state" is a state combination set, it compresses a complex set of state transition relationships into a state. In this way, if the combination needs to be reused elsewhere, you only need to introduce the status name of the combination. <喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> VcD4KPHA + kernel + 1xL3HtsjIpb + kernel/kernel vcD4KPHA + PC9wPgo8cHJlIGNsYXNzPQ = "brush: java;">/* CondDefine. h */# pragma once // whether to install # define CONDITION_EXIST "CONDITION_EXIST" # define CONDITION_NOEXIST "CONDITION_NOEXIST" // whether the download is successful # define tuning "success" # define tuning "success "/ /CPU busy or not # define CONDITION_BUSY "CONDITION_BUSY" # define CONDITION_NOBUSY "CONDITION_NOBUSY" // check whether the decompression is successful # define condition "success" # define CONDITION_UNZIP_FAI "success" // run successfully # de condition "CONDITION_RUN_SUC" # define CONDITION_RUN_FAI "success" // whether the installation is successful # define CONDITION_INSTALL_SUC "CONDITION_INSTALL_SUC" # define CONDITION_INSTALL_FAI "CONDITION_INSTALL_FAI"

The entire status jump has the following basic status:

Basic status Class
Check for Installation CSimpleState_CheckExist
Download from address CSimpleState_Download_From_A
Download from address B CSimpleState_Download_From_ B
Download from C Address CSimpleState_Download_From_C
Detect CPU usage CSimpleState_CheckCPU
Extract CSimpleState_Unzip
Install CSimpleState_Install
Uninstall CSimpleState_Uninstall
Execution successful CSimpleState_Success
Execution failed CSimpleState_Failed
Run CSimpleState_Run
Let's take "Download from address A" as an example to view the basic code for this status

# Pragma once # include "AutoStateChart. h "# include" StoreMachine. h "// introduce the output macro # include" CondDefine. h "// introduce the business base class # include" Business_Random.h "class CMachine_Download_Run_App; // class CSimpleState_Download_From_A: public AutoStateChart: CAutoStateChartBase
 
  
{Public: CSimpleState_Download_From_A (void ){};~ CSimpleState_Download_From_A (void) {}; public: void Entry () {}; std: string Exit () {return CONDITION_DOWNLOAD_SUC ;};};
 
It can be found that this class is very simple. We only need to declare the class with the template (the template parameter: yourself, the state machine class, and the storage class), and implement the Entry and Exit functions.. Let's take a look at the downloaded compound status class.

# Pragma once # include "AutoStateChart. h "# include" StoreMachine. h "// introduce the output macro # include" CondDefine. h "// introduce sub-States # include" SimpleState_Download_From_A.h "# include" SimpleState_Download_From_ B .h "# include" SimpleState_Download_From_C.h "class CMachine_Download_Run_App; // The pre-declaration state machine class // this class will generate two types of output: CONDITION_DONWLOAD_SUC and CONDITION_DONWLOAD_FAIclass CCompositeState_Download: public AutoStateChart: CCompositeStates
 
  
{Public: CCompositeState_Download (void ){};~ CCompositeState_Download (void) {}; public: region (region) REGISTERSTATECONVERT (Region, region, region) REGISTERSTATECONVERT (Region, CONDITION_DOWNLOAD_FAI, region) REGISTERSTATECONVERTEND ()};
 
This class is also very simple, it corresponds to


WhereThe REGISTERSTATECONVERTBEGIN macro specifies the starting State (State class) of the compound state, and the REGISTERSTATECONVERT specifies the state turning logic (former state class, condition, and post state class).

Let's look at the class in the combined state of "running status after installation ".

# Pragma once # include "AutoStateChart. h "# include" StoreMachine. h "// introduce the output macro # include" CondDefine. h "// introduce sub-States # include" example "# include" SimpleState_Failed.h "# include" SimpleState_CheckCPU.h "# include" SimpleState_Unzip.h "# include" SimpleState_Install.h "# include" SimpleState_Run.h "# include" simpleState_Uninstall.h "# include" SimpleState_Success.h "class CMachine_Download_Run_App; // class CCollectionState_Install_Run: public AutoStateChart: CCollectionStates
 
  
{Public: CCollectionState_Install_Run (void ){};~ Callback (void) {}; public: callback (optional) REGISTERSTATECONVERT (optional, optional, CSimpleState_CheckCPU) reset (optional, optional, optional) REGISTERSTATECONVERT (CSimpleState_CheckCPU, CONDITION_BUSY, CSimpleState_CheckCPU) average (CSimpleState_CheckCPU, average, minimum) percent (average, minimum, CSimpleState_Install) percent (CSimpleState_Unzip, minimum, minimum) percent (CSimpleState_Install, minimum, CSimpleState_Run) percent (CSimpleState_Install, minimum, minimum) REGISTERSTATECONVERT (CSimpleState_Run, condition, condition) REGISTERSTATECONVERT (CSimpleState_Run, condition, CSimpleState_Uninstall) REGISTERSTATECONVERT (CSimpleState_Uninstall, "", condition) Cancel ()};
 
This class is also written using REGISTERSTATECONVERTBEGIN, REGISTERSTATECONVERT, and REGISTERSTATECONVERTEND macros to form the entire state jump graph.


Finally, let's look at the class of the state machine.

# Pragma once # include "AutoStateChart. h "# include" StoreMachine. h "// introduce the output macro # include" CondDefine. h "// introduce sub-States # include" SimpleState_CheckExist.h "# include" example "# include" SimpleState_Run.h "# include" SimpleState_Uninstall.h "# include" SimpleState_Success.h "class metadata: public AutoStateChart: Example
 
  
{Public: CMachine_Download_Run_App (void ){};~ Revoke (void) {}; public: decrypt (CSimpleState_CheckExist) terminate (condition, CONDITION_NOEXIST, condition) terminate (condition, CONDITION_EXIST, CSimpleState_Run) terminate (CSimpleState_Run, condition, CSimpleState_Uninstall) REGISTERSTATECONVERT (CSimpleState_Run, CONDITION_RUN_SUC, CSimpleState_Success) REGISTERSTATECONVERT (CSimpleState_Uninstall, "", CCollectionState_Install_Run) REGISTERSTATECONVERTEND ()};
 
It also uses three macros to form the entire logical jump.

On the premise that the module is independent, the state machine shows the entire state jump process elegantly and concisely. Of course, many secrets are hidden behind this conciseness. We will introduce its implementation in the next section.

We finally run the entire state machine through the following code:

    boost::shared_ptr
 
   spc = boost::make_shared
  
   ();    spc->StartMachine();
  
 

Related Article

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.