Machine à états d'écureuil - de l'exploration des principes aux meilleures pratiques

Auteur : JD Logistics Zheng Penghui

1. Introduction

La machine d'état Squirrel est un outil de modélisation du comportement d'un objet, qui décrit principalement l'état que l'objet éprouve au cours de son cycle de vie et comment réagir à divers événements du monde extérieur. Par exemple, l'état de la création de la commande, du paiement, de la livraison, de la récolte, de l'annulation, etc., le contrôle entre les états et la surveillance des événements déclencheurs peuvent être clairement gérés et réalisés par ce cadre. Les avantages de l'utilisation d'une machine d'état pour gérer le flux de vie des objets se reflètent davantage dans la maintenabilité et la testabilité du code. Des conditions d'état claires, des actions de réponse atomique et des états cibles de migration pilotés par des événements peuvent être utilisés pour des scénarios métier complexes et processus modifiables Réduisez considérablement la difficulté de maintenance et de test.

2 Concepts de base

2.1 Définition de la machine à états Squirrel

La machine à états Squirrel est une machine à états finis. Une machine à états finis signifie qu'un objet a un flux de vie clair et complexe (généralement plus de trois états), et qu'il existe différentes conditions de déclenchement et comportements de traitement dans les transitions d'état.

2.2 Éléments de la machine à états d'écureuil

La machine d'état Squirrel peut être résumée en quatre éléments, à savoir l'état actuel, la condition, l'action et l'état suivant. "L'état actuel" et "la condition" sont la cause, et "l'action" et "l'état suivant" sont l'effet.

  • État actuel : fait référence à l'état actuel.
  • Conditions : également appelées événements. Lorsqu'une condition est remplie, une action sera déclenchée ou une transition d'état sera effectuée.
  • Action : L'action à exécuter une fois la condition remplie. Une fois l'action exécutée, elle peut migrer vers un nouvel état ou rester dans son état d'origine. Aucune action n'est requise. Lorsque les conditions sont remplies, vous pouvez directement migrer vers le nouvel état sans effectuer aucune action.
  • État suivant : le nouvel état vers lequel passer une fois la condition remplie. "L'état secondaire" est relatif à "l'état présent". Une fois que "l'état secondaire" est activé, il se transformera en un nouvel "état présent".

3 Principe de mise en œuvre

3.1 CAS d'audit de magasin

Par exemple, l'ouverture d'une boutique en ligne JD.com doit être examinée avant son lancement officiel. Le statut de la boutique est en attente d'examen, rejeté et examiné. Les opérations correspondantes incluent la soumission pour examen, l'approbation et le rejet de l'examen. Il est maintenant nécessaire de réaliser les exigences d'un processus d'examen de magasin.

3.2 Comparaison des schémas

3.2.1 Implémentation if-else ou switch-case couramment utilisée (mode branche)

Figure 1. Organigramme de la mise en œuvre du mode if-else/switch-case

3.2.2 Implémentation de la machine d'état


 

Figure 2. Organigramme de mise en œuvre du mode machine d'état

3.2.3 Comparaison

En introduisant une machine d'état, un grand nombre de structures de branche if-else if-else ou switch-case peuvent être supprimées, et la table pilotée par le comportement peut être directement interrogée via l'état actuel et la table pilotée par l'état pour trouver des comportements spécifiques et effectuer des opérations, ce qui est propice à la maintenance et à l'expansion du code.

3.3 Principe de mise en œuvre

 

Figure 3. Organigramme de création de la machine d'état

 

  • StateMachine : L'instance StateMachine est créée par StateMachineBuilder et n'est pas partagée. Pour la StateMachine définie par annotation (ou fluent api), l'instance StateMachine est créée selon cette définition, et l'action correspondante est également exécutée par cette instance. L'intégration finale avec spring c'est parler de spring L'instance du bean est injectée dans l'instance de la machine d'état créée par le constructeur ;
  • StateMachineBuilder : Essentiellement un proxy dynamique créé par StateMachineBuilderFactory. L'implémentation par défaut de StateMachineBuilder proxy est StateMachineBuilderImpl, qui décrit en interne les détails de la création d'une instance de machine d'état, y compris l'état, l'événement, les informations de type de contexte, le constructeur, etc., et inclut également certaines ressources globales partagées de StateMachine, notamment StateConverter, EventConverter, MvelScript Manager, etc. StateMachineBuilder peut être réutilisé et peut être implémenté en tant que singleton en cours d'utilisation ;
  • StateMachineBuilderFactory : une instance de proxy dynamique créée pour StateMachineBuilder ;

4 Pratiquer le partage

4.1 Dépendance à l'environnement

<dependency>
<groupId>org.squirrelframework</groupId>
<artifactId>squirrel-foundation</artifactId>
<version>0.3.9</version>
</dependency>

4.2 Définition des éléments de la machine d'état : état, événement

// 店铺审核状态
public Enum ShopInfoAuditStatusEnum{
audit(0,"待审核"),
agree(1,"审核通过"),
reject(2,"审核驳回");
}
// 店铺审核事件
public Enum ShopInfoAuditEvent{
SUBMIT, // 提交
AGREE, // 同意
REJECT; // 驳回
}

 

4.3 Construire une instance StateMachineBuilder

/**
* StateMachineBuilder实例
*/
public class StateMachineEngine <T extends UntypedStateMachine, S, E, C> implements ApplicationContextAware{


private ApplicationContext applicationContext;


private static Map<String,UntypedStateMachineBuilder> builderMap = new HashMap<String,UntypedStateMachineBuilder>();

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}


@Transactional
public void fire(Class<T> machine, S state, E event, C context) {
StateMachineBuilder stateMachineBuilder = this.getStateMachineBuilder(machine);
StateMachine stateMachine = stateMachineBuilder.newStateMachine(state,applicationContext);
stateMachine.fire(event, context);
}


private StateMachineBuilder getStateMachineBuilder(Class<T> stateMachine){
UntypedStateMachineBuilder stateMachineBuilder = builderMap.get(stateMachine.getName());
if(stateMachineBuilder == null){
stateMachineBuilder = StateMachineBuilderFactory.create(stateMachine,ApplicationContext.class);
builderMap.put(stateMachine.getName(),stateMachineBuilder);
}
return stateMachineBuilder;

4.4 Créer une machine d'état de revue de statut de magasin spécifique

/**
* 店铺审核状态机
*/
@States({
@State(name = "audit"),
@State(name = "agree"),
@State(name = "reject")
})
@Transitions({
@Transit(from = "audit", to = "agree", on = "AGREE", callMethod = "agree"),
@Transit(from = "audit", to = "reject", on = "REJECT", callMethod = "reject"),
@Transit(from = "reject", to = "audit", on = "SUBMIT", callMethod = "submit"),
@Transit(from = "agree", to = "audit", on = "SUBMIT", callMethod = "submit"),
@Transit(from = "audit", to = "audit", on = "SUBMIT", callMethod = "submit"),
})
@StateMachineParameters(stateType=ShopInfoAuditStatusEnum.class, eventType=ShopInfoAuditEvent.class, contextType=ShopInfoAuditStatusUpdateParam.class)
public class ShopInfoAuditStateMachine extends AbstractUntypedStateMachine {


private ApplicationContext applicationContext;


public ShopInfoAuditStateMachine(){}


public ShopInfoAuditStateMachine(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}


// 审核通过业务逻辑
public void agree(ShopInfoAuditStatusEnum fromState, ShopInfoAuditStatusEnum toState, ShopInfoAuditEvent event, ShopInfoAuditStatusUpdateParam param) {
this.agree(fromState,toState,event,param);
}

// 审核驳回业务逻辑
public void reject(ShopInfoAuditStatusEnum fromState, ShopInfoAuditStatusEnum toState, ShopInfoAuditEvent event, ShopInfoAuditStatusUpdateParam param) {
this.reject(fromState,toState,event,param);
}

// 提交业务逻辑
public void submit(ShopInfoAuditStatusEnum fromState, ShopInfoAuditStatusEnum toState, ShopInfoAuditEvent event, ShopInfoAuditStatusUpdateParam param) {
this.submit(fromState,toState,event,param);
}

 

4.5 Appels clients

// 调用端
main{
StateMachineEngine stateMachineEngine = applicationContext.getBean(StateMachineEngine.class);
// 审核通过调case
stateMachineEngine.fire(ShopInfoAuditStateMachine.class,ShopInfoAuditStatusEnum.audit,ShopInfoAuditEvent.AGREE,param);
// 审核驳回case
stateMachineEngine.fire(ShopInfoAuditStateMachine.class,ShopInfoAuditStatusEnum.audit,ShopInfoAuditEvent.REJECT,param);
}

 

5 résumé

La machine d'état nous aide à gérer le flux d'états d'objets, la surveillance des événements et la réponse à divers événements externes. Du point de vue de la conception du code, un grand nombre de jugements logiques if-else/switch-case sont réduits, ce qui améliore la maintenabilité et l'évolutivité du code, et facilite la gestion et les tests.

{{o.name}}
{{m.name}}

Je suppose que tu aimes

Origine my.oschina.net/u/4090830/blog/6822669
conseillé
Classement