我目前对州设计模式的理解基本上是这样的:
封装对象中特定状态的对象的所有行为。将请求委托给“当前”状态对象。
我的问题是:处理状态转换的最佳方法是什么?在我的情况下,很可能“当前”状态对象将决定我们需要转换到的其他状态。我想到了实现这个的两种方法:
状态对象方法可以返回一些特定值,表示“我正在请求状态转换”。然后,主对象可以查询我们应该转换到的新状态的当前状态,调用ChangeState()
,然后将原始请求路由到新状态。
状态对象本身可以在父对象上调用ChangeState()
,然后自己将导致状态更改的请求传递给新对象。
场景2的优点是主对象只需要将请求委托给“当前”状态(它在内部将处理任何必要的状态转换)。它也许不太明显。
我希望有更好的方法来处理这种情况。你觉得怎么样?
答案 0 :(得分:3)
我首选state方法返回新的状态对象(它减少了耦合,更适合S.O.L.I.D.原则)。
这里的例子(这个想法在实际项目中使用):
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) {
//..
}
}
答案 1 :(得分:2)
我认为你可能只限于实现状态模式的对象(Context对象和State对象)。情况并非如此,并且还涉及其他对象(客户端)。持有对上下文对象的引用的客户端应该负责转换状态。
考虑这个例子:
// 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;
}
}
这应该是上下文对象的足够实现。请注意,colourState
和Paintbrush
类都不知道状态转换。这是为了减少责任的数量,以及提供更灵活的设计。
基本上,状态的变化可能是调用类的责任。如何在代码中实现这一点是实现细节,但重要的是要注意上下文对象和状态对象都不负责转换状态。
我正在努力确保我不使用Strawman论证,但我将继续使用该示例。在不同的点上说你想画出不同的图案,并且使用的颜色必须按照特定的顺序,你的客户会决定何时改变状态,如下所示:
public void paintRainbow() {
paintbrush.setColourState(new RedColourState());
// do painting...
// Change state to next colour
paintbrush.setColourState(new OrangeColourState());
// Chane state again, and so on...
}
你可以具有状态或上下文对象指定的颜色顺序,即。有一个Paintbrush
的子类叫RainbowPaintbrush
,它会选择下一个颜色。或者你的状态对象可以选择下一个状态,在这种情况下你必须有一个RedRainbowColourState
,它知道下一个状态是OrangeRainbowColourState
,依此类推。但是这两个示例的问题在于您必须进入并修改(通过扩展)上下文和状态对象以实现不同的转换集。但是,如果既不知道转换,也不知道调用类的责任,则可以在不更改状态或上下文对象的情况下完成。即
public void paintChessboard() {
paintbrush.setColourState(blackColourState);
// do painting...
// change state
paintbrush.setColourState(whiteColourState);
// etc...
}
这是一个简化的例子,但它通常都有。
快速阅读维基百科的example of the State pattern表明,各个州都知道下一个州,所以我认为这样做无效。我想总的来说,这是你想要控制的位置以及它如何适合你的问题的权衡。这就是如何使用具体的状态对象进行转换将适合我的蹩脚示例:
public class RedRainbowColourState implements ColourState {
public void doPaint(Paintbrush paintbrush) {
// do painting
ColourState nextStateInRainbow = new OrangePaintbrushColourState();
paintbrush.setColourState(nextStateInRainbow);
}
但请注意,使用这种方式转换所有状态所需的状态类的爆炸性增长。然而,这里的一个优点是客户可以免除责任和如何创建个别状态的知识。在您的情况下,这可能是更好的过渡方式。
总而言之,您可以让各个州执行转换,甚至是上下文对象。另一个选择是让客户端处理状态转换。