2010-01-20 17 views
6

Mi comprensión actual del patrón de diseño de estado es básicamente esto:¿Cuál es la mejor manera, utilizando el patrón de diseño "estatal", para cambiar los estados?

Encapsula todo el comportamiento de un objeto en un estado particular en un objeto. Delegar las solicitudes al objeto de estado "Actual".

Mi pregunta es: ¿Cuál es la mejor forma de manejar las transiciones de estado? En mi caso, es probable que el objeto de estado "actual" sea el que decida a qué otro estado necesitamos hacer la transición. He pensado en 2 formas de implementar esto:

1) Los métodos de objetos de estado pueden devolver un valor particular que significa "Estoy solicitando una transición de estado". El objeto principal puede consultar el estado actual para el nuevo estado al que debemos hacer la transición, llamar a "ChangeState()" y luego enrutar la solicitud original al nuevo estado.

2) El objeto de estado en sí mismo puede llamar a "ChangeState()" en el elemento principal, y luego pasar la solicitud que provocó el cambio de estado en el nuevo objeto.

El escenario 2 tiene la ventaja de que el objeto principal solo necesita delegar solicitudes al estado "Actual" (gestionará internamente cualquier transición de estado necesaria). También es quizás un poco menos obvio.

Espero que se conozcan mejores formas de manejar este escenario. ¿Qué piensas?

+0

Una de sus etiquetas está mal escrita. No puedo solucionarla porque no tengo suficiente reputación. –

+0

Como mencionaste que el estado 'actual' puede decidir cuál será el siguiente estado, entonces el segundo enfoque no solo es un mejor enfoque sino también la forma correcta de hacerlo. – Anurag

+0

FYI: patrones de diseño Mindmap: http://www.mindmeister.com/7008138/design-patterns – jldupont

Respuesta

2

creo que está quizá limitando a pensar sólo en términos de los objetos que implementan el modelo de estado (objeto Contexto y objetos del Estado). Este no es el caso, y hay otros objetos involucrados (Clientes). Es posible que el cliente, que tiene una referencia al objeto de contexto, tenga la responsabilidad del estado de transición.

considerar esta formada por ejemplo:

// 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; 
    } 
} 

Esto debería ser suficiente para la ejecución del objeto de contexto. Tenga en cuenta que ni colourState ni la clase Paintbrush tienen ningún conocimiento de las transiciones de estado. Esto es para reducir el número de responsabilidades, así como para proporcionar un diseño más flexible.

Básicamente, los cambios de estado podrían ser responsabilidad de la clase de llamada. Cómo se logra esto realmente en el código es el detalle de la implementación, pero lo importante es notar que ni el objeto de contexto ni el objeto de estado tienen la responsabilidad del estado de transición.

Estoy tratando de asegurarme de que no utilizo un argumento de Strawman, pero seguiré usando el ejemplo. Dicen en diferentes puntos que quería pintar diferentes patrones, y los colores utilizados deben estar en un orden específico, su cliente sería decidir cuándo cambiar de estado, así:

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

Usted podrían tener el orden de los colores especificado por el estado o el objeto de contexto, es decir. tener una subclase de Paintbrush llamada RainbowPaintbrush, y elegiría el siguiente color.O bien, los objetos de su estado podrían elegir el siguiente estado, en cuyo caso tendría que tener un RedRainbowColourState, que sabía que el siguiente estado era OrangeRainbowColourState y así sucesivamente. Pero el problema con estos dos ejemplos es que debe ingresar y modificar (por extensión) el contexto y los objetos de estado para lograr un conjunto diferente de transiciones. Sin embargo, si ninguno conoce las transiciones, y esa es la responsabilidad de la clase de llamada, esto se puede hacer sin cambiar el estado o el objeto de contexto. Es decir.

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

Este es un ejemplo simplificado, pero en general es válido.

Una lectura rápida de Wikipedia example of the State pattern muestra que los estados individuales tienen conocimiento del siguiente estado, por lo que no creo que no sea válido. Supongo que, en general, es una compensación de dónde quiere que esté el control y cómo encajará en su problema. Se trata de cómo el uso de los objetos de estado de transición concretas para encajaría en mi ejemplo cojo:

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

Pero tenga en cuenta la explosión de las clases de estado que serán necesarias para la transición a través de todos los estados que utilizan este camino. Sin embargo, una ventaja aquí es que el cliente puede ser relevado de la responsabilidad y el conocimiento de cómo crear los estados individuales. En su situación, esa puede ser una mejor forma de transición.


En resumen, puede dejar que los estados individuales realicen la transición, o incluso el objeto de contexto. Otra opción es dejar que el cliente maneje las transiciones de estado.

3

Prefiero que el método de estado devuelva un nuevo objeto de estado (reduce el acoplamiento y es más apropiado para los principios S.O.L. I.D.).

Aquí ejemplo (utiliza esta idea en proyecto real):

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

¿Puede explicar cómo esto está más alineado con los principios SOLIDOS y reduce el acoplamiento? Gracias – Deepak

Cuestiones relacionadas