2010-01-20 3 views
6

Ma compréhension actuelle du modèle de conception d'état est fondamentalement la suivante:Quelle est la meilleure façon, en utilisant le modèle de conception "État", de changer d'état?

Encapsule tout le comportement d'un objet dans un état particulier dans un objet. Déléguez des requêtes à l'objet d'état "Actuel".

Ma question est: Quelle est la meilleure façon de gérer les transitions d'état? Dans mon cas, il est probable que l'objet d'état "Actuel" soit celui qui décide à quel autre état nous devons passer. J'ai pensé à 2 façons d'implémenter ceci:

1) Les méthodes d'objets d'état peuvent renvoyer une valeur particulière qui signifie "Je demande une transition d'état". L'objet principal peut alors interroger l'état actuel pour quel nouvel état nous devons passer, appeler "ChangeState()", puis acheminer la requête d'origine vers le nouvel état.

2) L'objet d'état lui-même peut appeler "ChangeState()" sur le parent, puis passer lui-même la requête qui a provoqué la modification de l'état sur le nouvel objet.

Le scénario 2 présente l'avantage que l'objet principal doit uniquement déléguer des requêtes à l'état "Current" (il traitera en interne toutes les transitions d'état nécessaires). C'est peut-être aussi un peu moins évident. Je souhaite que l'on connaisse de meilleures façons de gérer ce scénario. Qu'est-ce que tu penses?

+0

L'un de vos tags est mal orthographié - Je ne peux pas le réparer car je n'ai pas assez de rep. –

+0

Comme vous l'avez mentionné que l'état 'current' arrive à décider quel sera le prochain état, alors la deuxième approche est non seulement une meilleure approche mais aussi la bonne façon de le faire. – Anurag

+0

FYI: Motifs de conception Mindmap: http://www.mindmeister.com/7008138/design-patterns – jldupont

Répondre

2

Je pense que vous êtes peut-être vous limiter à penser seulement en termes des objets de mise en œuvre du modèle d'état (objet Contexte et objets de l'État). Ce n'est pas le cas, et il y a d'autres objets impliqués (Clients). Il est possible que le client, qui détient une référence à l'objet de contexte, ait la responsabilité d'un état de transition.

Considérez ceci composé par exemple:

// Paintbrush is the context object 
class Paintbrush { 
    // The State object, ColourState would be the abstraction 
    private ColourState colourState; 

    // ... other class stuff 

    public paint() { 
     // Delegation to the state object 
     this.colourState.paintInYourSpecificColour(); 
    } 

    public void setColourState(ColourState newState) { 
     this.colourState = newState; 
    } 
} 

Cela devrait être suffisant pour la mise en œuvre de l'objet de contexte. Notez que ni la classe colourState ni la classe Paintbrush ne connaissent les transitions d'état. C'est pour réduire le nombre de responsabilités, ainsi que pour fournir une conception plus flexible.

Fondamentalement, les changements d'état pourraient être la responsabilité de la classe appelante. La manière dont cela est réellement réalisé dans le code est le détail de l'implémentation, mais il est important de noter que ni l'objet de contexte ni l'objet d'état ne sont responsables de l'état de transition. J'essaie de m'assurer que je n'utilise pas un argument Strawman, mais je vais continuer à fonctionner avec l'exemple ci-dessous. Dites à différents points que vous avez voulu peindre des motifs différents, et les couleurs utilisées doivent être dans un ordre précis, votre client déciderait quand changer d'état, comme celui-ci:

public void paintRainbow() { 
    paintbrush.setColourState(new RedColourState()); 
    // do painting... 
    // Change state to next colour 
    paintbrush.setColourState(new OrangeColourState()); 
    // Chane state again, and so on... 
} 

Vous pourrait avoir l'ordre des couleurs spécifié par l'état ou l'objet de contexte, à savoir. avoir une sous-classe Paintbrush appelée RainbowPaintbrush, et il choisirait la couleur suivante.Ou vos objets d'état pourraient choisir l'état suivant, auquel cas vous auriez besoin d'un RedRainbowColourState, qui savait que l'état suivant était OrangeRainbowColourState et ainsi de suite. Mais le problème avec ces deux exemples est que vous devez entrer et modifier (par extension) à la fois le contexte et les objets d'état pour obtenir un ensemble différent de transitions. Cependant, si ni l'un ni l'autre ne connaît les transitions, et c'est la responsabilité de la classe appelante, cela peut être fait sans changer l'état ou l'objet de contexte. C'est à dire.

public void paintChessboard() { 
    paintbrush.setColourState(blackColourState); 
    // do painting... 
    // change state 
    paintbrush.setColourState(whiteColourState); 
    // etc... 
} 

Ceci est un exemple simplifié, mais généralement valable.

Une lecture rapide de example of the State pattern de Wikipedia montre que les états individuels ont une connaissance de l'état suivant, donc je ne pense pas que cela soit invalide. Je suppose que dans l'ensemble, il s'agit d'un compromis entre l'endroit où vous voulez que le contrôle soit, et comment cela va tenir dans votre problème. Voici comment utiliser les objets d'état en béton à la transition cadrerait dans mon exemple boiteux:

public class RedRainbowColourState implements ColourState { 
    public void doPaint(Paintbrush paintbrush) { 
     // do painting 
     ColourState nextStateInRainbow = new OrangePaintbrushColourState(); 
     paintbrush.setColourState(nextStateInRainbow); 
    } 

Mais notez l'explosion des classes d'états qui seront nécessaires à la transition à travers tous les États qui utilisent cette façon. Cependant, un avantage ici est que le client peut être déchargé de la responsabilité et de la connaissance de la façon de créer les états individuels. Dans votre situation, cela pourrait être une meilleure façon de faire la transition.


En résumé, vous pouvez laisser les états individuels effectuer la transition, ou même l'objet de contexte. Un autre choix consiste à laisser le client gérer les transitions d'état.

3

Je préfère que la méthode d'état renvoie un nouvel objet d'état (il réduit le couplage et est plus approprié aux principes de S.O.L.I.D.).

Ici par exemple (cette idée utilise dans le projet réel):

class ExternalContext { 
    //... 
} 

class Entity 
{ 
    public Entity(ExternalContext context) 
    { 
     //Creating current state with factory method 
     state = EntityState.Create(context); 
    } 

    public void ChangeEntity(ExternalContext context) 
    { 
     state = state.Change(context); 
    } 

    private EntityState state; 
} 

abstract class EntityState 
{ 
    public abstract EntityState Change(ExternalContext externalContext); 
    public static EntityState Create(ExternalContext externalContext); 
} 
class EntityState1 : EntityState { 
    public override EntityState Change(ExternalContext externalContext) { 
     //.. 
    } 
} 
+2

Pouvez-vous s'il vous plaît expliquer comment cela est plus aligné sur les principes SOLID et réduit le couplage? Merci – Deepak

Questions connexes