涉及 N 个状态以及它们之间的转换的设计模式问题

发布于 2024-08-17 21:25:09 字数 339 浏览 6 评论 0原文

我手头有一个问题,我不知道要使用哪种设计模式。 问题是这样的:

我必须构建一个具有“N”状态的系统,并且我的系统必须根据某些条件从任何状态转换到任何其他状态。 前任: 在条件 1 上,从状态 1 到 3 的移动,在条件 2 上从状态 1 到 4 的

移动。甚至可以在 2 个或更多不同的条件下完成从一种状态到另一种状态的转换。

例如,可以在以下情况下完成从状态 1 到状态 3 的转换:
条件 1:“今天是星期日”
条件2:“下雨了”
条件 3:“周日下雨”
在每种情况下,状态 3 的处理可能不同。

我希望我能够清楚地理解这个问题。请帮忙。

多谢

I have a problem at hand and I am not getting which design pattern to use.
The problem goes as such:

I have to build a system which has 'N' states and my system has to do a transition from any state to any other state depending on some conditions.
Ex:
On condition 1, movement from State 1 to 3 and on condition 2 from state 1 to 4.

Even the transition from one state to other state can be done on 2 or more different conditions.

For example, transition from State 1 to state 3 can be done when:
condition 1 : "Its a Sunday"
condition 2: "Its Raining"
condition 3: "Its Raining and Sunday"
In each condition, the processing at State 3 can be different.

I hope I was able to understand the problem legibly. Kindly help.

Thanks a lot

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

埖埖迣鎅 2024-08-24 21:25:09

这显然是有限状态机的情况,但最好组合条件,而不是为每个组合创建新条件。我不喜欢维基百科上状态模式的 Java 示例,因为状态了解其他状态,这在很多情况下没有意义。跟踪状态、适用的条件状态的转换表有助于解决该问题。

我的两分钱是面向对象的有限状态机。您可以在面向对象方面进行一些改进,但它可以传达想法。

class Transition {
    State from;
    Set<Condition> conditions;
    State to;
}

class State {
    String state;
}

class Condition {
    String condition;
}

状态机可以用上述类型来构造。没有错误检查,但如果在某些条件下找不到下一个状态,您可能会抛出异常或其他异常。

class StateMachine {
    List<Transition> transitions;
    State current;

    StateMachine(State start, List<Transition> transitions) {
        this.current = start;
        this.transitions = transitions;
    }

    void apply(Set<Condition> conditions) {
        current = getNextState(conditions);
    }

    State getNextState(Set<Condition> conditions) {
        for(Transition transition : transitions) {
            boolean currentStateMatches = transition.from.equals(current);
            boolean conditionsMatch = transition.conditions.equals(conditions);
            if(currentStateMatches && conditionsMatch) {
                return transition.to;
            }
        }
        return null;
    }
}

和测试运行:

编辑:根据您的评论,有更多的转换和新状态:

State one = new State("one");
State two = new State("two");
State three = new State("three");

Condition sunday = new Condition("Sunday");
Condition raining = new Condition("Raining");
Condition notSunday = new Condition("Not Sunday");
Condition notRaining = new Condition("Not Raining");

List<Transition> transitions = new ArrayList<Transition>();
transitions.add(one, new Set(sunday), three);
transitions.add(one, new Set(sunday), two); // <<--- Invalid, cant go to two and three
transitions.add(one, new Set(raining), three);
transitions.add(one, new Set(sunday, raining), three);
transitions.add(one, new Set(notSunday, notRaining), three);

StateMachine machine = new StateMachine(one, transitions);
System.out.print(machine.current); // "one"
machine.apply(new Set(sunday, raining));
System.out.print(machine.current); // "three

我在一个相当大的项目中使用状态机有过一段痛苦的经历。问题在于复合状态。就像您提到的复合条件(星期日和下雨)一样,从技术上讲,可能存在可以进一步分解为单位状态的复合状态。在您的情况下,这可能是也可能不是,但仍然值得一提。如果是这种情况,最好修改经典的有限状态机并使用一组状态而不是单个状态来表示起始状态和终止状态。如果你的 N 很大,这将有助于保持理智水平完好无损。想想 hotmail 文件夹与 Gmail 标签。转换表将表示为

Transition(Set<State> from, Set<Condition> conditions, Set<State> to)

Its clearly a case of a finite-state-machine but its better to combine the conditions rather than create a new condition for each combination. I didn't like the Java example for State pattern on Wikipedia as states know about other states which wouldn't make sense in a lot of scenarios. A transition table that keeps a track of the from state, applicable condition(s), and to state, helps take care of that problem.

My two cents for an object oriented-finite-state-machine. There are improvements you could do on the OO front, but it gets the idea across.

class Transition {
    State from;
    Set<Condition> conditions;
    State to;
}

class State {
    String state;
}

class Condition {
    String condition;
}

The state machine can be constructed with the above types. There is no error checking, but you could throw an exception or something if no next state is found for some conditions.

class StateMachine {
    List<Transition> transitions;
    State current;

    StateMachine(State start, List<Transition> transitions) {
        this.current = start;
        this.transitions = transitions;
    }

    void apply(Set<Condition> conditions) {
        current = getNextState(conditions);
    }

    State getNextState(Set<Condition> conditions) {
        for(Transition transition : transitions) {
            boolean currentStateMatches = transition.from.equals(current);
            boolean conditionsMatch = transition.conditions.equals(conditions);
            if(currentStateMatches && conditionsMatch) {
                return transition.to;
            }
        }
        return null;
    }
}

And a test run:

Edit: With some more transitions and new states based on your comment:

State one = new State("one");
State two = new State("two");
State three = new State("three");

Condition sunday = new Condition("Sunday");
Condition raining = new Condition("Raining");
Condition notSunday = new Condition("Not Sunday");
Condition notRaining = new Condition("Not Raining");

List<Transition> transitions = new ArrayList<Transition>();
transitions.add(one, new Set(sunday), three);
transitions.add(one, new Set(sunday), two); // <<--- Invalid, cant go to two and three
transitions.add(one, new Set(raining), three);
transitions.add(one, new Set(sunday, raining), three);
transitions.add(one, new Set(notSunday, notRaining), three);

StateMachine machine = new StateMachine(one, transitions);
System.out.print(machine.current); // "one"
machine.apply(new Set(sunday, raining));
System.out.print(machine.current); // "three

I had a bitter experience with using a state machine for a fairly large project. The problem was with composite states. Just like the composite condition you mentioned (sunday and raining), there could technically be composite states which could further be broken down into unit states. This may or may not be the case in your situation, but still worth mentioning. If that is the case, it's best to modify the classical finite state machine and use a set of states instead of a single state to represent the from and to states. If your N is large, this will help keep sanity levels intact. Think hotmail folders vs gmail tags. The transition table would then be presented as

Transition(Set<State> from, Set<Condition> conditions, Set<State> to)
魂ガ小子 2024-08-24 21:25:09

这听起来像是有限状态机的典型用途

,简而言之,状态机描述了您的系统可以处于的各种状态,以及在什么条件下它可以从一个状态切换到另一个状态。状态机的描述与您的英语描述完全相同。它可以在代码中使用 状态图 进行正式描述,

的状态机:

 enum State { Init, ShowMenu, ShowMsg, DisplayVideo, Exit };
 State state = State.Init;

 while (state != State.Exit)
 {
      switch(state)
      {
           case State.Init:
                init();
                state = State.ShowMenu;
                break;
           case State.ShowMenu:
                if(lastMenuItemSelected==1) state = State.ShowMsg;
                if(lastMenuItemSelected==2) state = State.DisplayVideo;
                break;
           case State.ShowMsg:
                ....
                break;
           ....
 }

您可以制作这样 不确定我的 Java 语法是否正确...我更喜欢 C#

This sounds like the typical use for a finite state machine

in short, the state machine describes the various states in which your system can be, and under which conditions it can go from state to state. A state machine is described exactly as your English description. And it can be formally described using state diagrams

in code you could make a state machine like this:

 enum State { Init, ShowMenu, ShowMsg, DisplayVideo, Exit };
 State state = State.Init;

 while (state != State.Exit)
 {
      switch(state)
      {
           case State.Init:
                init();
                state = State.ShowMenu;
                break;
           case State.ShowMenu:
                if(lastMenuItemSelected==1) state = State.ShowMsg;
                if(lastMenuItemSelected==2) state = State.DisplayVideo;
                break;
           case State.ShowMsg:
                ....
                break;
           ....
 }

I'm not sure if I got the exact syntax correct for Java...I'm more into C#

鹤仙姿 2024-08-24 21:25:09

状态模式不会完成这项工作吗?

won't the state pattern do the work?

太阳哥哥 2024-08-24 21:25:09

正如其他人所说,状态机可以用带有开关的过程代码或带有状态模式的 OO 代码来建模,这可能就是您所追求的。

然而,第三种方法是将其实际编码为图,其中状态作为节点,条件作为有向边。然后可以使用访问者模式将图应用于不同的用途。这特别适合于状态和/或转换可以由用户定义的设计,但可能比其他答案中描述的硬编码状态机更加占用内存。

As others have said a state machine can be modelled in procedureal code with a switch or in OO code with the state pattern, which is probably what you were after.

However a 3rd way is to actually code it as a graph, with states as nodes and conditions as directed edges. The visitor pattern can then be used to apply the graph to different uses. this would lend itself particularly well to designs where the states and/or the transitions could be user defined, but would probably be more memory intensive then the hard coded state machines described in the other answers.

花落人断肠 2024-08-24 21:25:09

关于你的例子,我注意到的第一件事是 State 3 = (State 1 == true && State 2 == true)。随着更多可能的国家参与其中,这种规模不会很好地扩展。如果您只考虑是否下雨或是否是星期日,您可以有一个像这样的枚举,有 4 种可能的类型:

enum State { CLEAR_OTHER_DAY, RAINING_OTHER_DAY, CLEAR_SUNDAY, RAINING_SUNDAY }

这将允许您在编码时在 switch 块中清晰地陈述条件。但如果您还必须考虑外面是否温暖,则必须向该枚举添加 4 个以上值以捕获所有可能的条件。在项目后期,您的代码可能需要捕获比您当前设想的更多的条件。

至于设计模式,状态模式及其 Wikipedia 上的 Java 示例 看起来像很好的起点。

维基百科的示例有一个 StateContext 类,其中包含一个名为 setState 的方法,该方法接受名称。我考虑过建议您在此处添加状态确定逻辑,但这将使您的 StateContext 类需要过于接近其他类的实现细节。最好将一种用于确定系统状态的方法放在一个类中,该类可以很容易地知道从一种状态转到另一种状态的条件。这样,如果您的项目将来需要更改,并且您要么需要跟踪更多状态,要么需要不同的条件,则只需在一处维护逻辑即可。

The first thing I noticed about your example was that State 3 = (State 1 == true && State 2 == true). This will not scale very well as more possible states become involved. If you are only considering whether it is raining or whether it is Sunday, you can have an enumeration like this, with 4 possible types:

enum State { CLEAR_OTHER_DAY, RAINING_OTHER_DAY, CLEAR_SUNDAY, RAINING_SUNDAY }

This would allow you to state conditions cleanly in a switch block when it is time to code. But if you have to also consider whether it is warm outside, you have to add 4 more values to that enum to capture all possible conditions. And later in your project, your code may need to capture more conditions than you currently envision.

As for a design pattern, the State pattern and its Java example on Wikipedia look like a good place to start.

Wikipedia's example has a StateContext class with a method called setState that takes in a name. I thought about suggesting that you add the state determination logic here, but that would make your StateContext class need to get too close to the implementation details of your other classes. It would be better to put a method for determining the system's state in a class that would easily know the conditions for going from one state to another. This way, if your project needs to change in the future and you either have more states to keep track of or different conditions, you only need to maintain the logic in one place.

梦幻的味道 2024-08-24 21:25:09

状态设计模式基于状态更改的概念。整个流程生命周期可以分为多个阶段。每个阶段完成后,流程就会从一种状态退出并进入另一种状态。

例如,在 JSF 框架中,整个 Web 请求响应生命周期分为六个阶段:

每个阶段完成后,流程退出一个状态并进入另一个状态。例如,在 RestoreValuePhase 之后,我们可以说 ViewRestored 为退出状态,而 RequestApply 为进入状态。

因此,要实现状态设计模式,需要将整个流程划分为多个阶段,每个阶段退出都定义一个状态更改。

现在让我们通过下面的代码来理解这一点。

任何项目生命周期都可以分为多个阶段,例如

requirementAssessment
Design
Development
QualityAssessment
Deploy
Closure

以下示例规则中使用的阶段

  1. 我们需要定义一个类,在其中存储流程的当前状态。下面代码中的 NextPhase 类就是这样做的。

  2. 我们需要定义一个接口,其中我们可以提供将在每个阶段实现的联系方法。在下面的代码中,ProjectPhase 正在执行此操作。

    我们需要定义一个

在此处了解有关状态设计模式的更多信息 - 状态设计模式

http://efectivejava.blogspot.in/2013/09/java-state-design-patten-oops-state.html?utm_source=BP_recent

State design pattern works on the concept of state change. Entire process life-cycle can be divided in multiple phases.With completion of each phase process exits from one state and enters in to another state.

For example In JSF framework entire web request response lifecycle is divided in six phases:

After completion of every phase process exits from a state and enters into another state. For example after RestoreValuePhase we can say ViewRestored as exit state and RequestApply as entering state .

So to implement State design pattern It is required to divide entire process in such a way that It can be processed in multiple phases with every phase exit defining a state change.

Now let's understand this with below code.

Any project lifecycle can be divided in multiple phases like

requirementAssessment
Design
Development
QualityAssessment
Deploy
Closure

So these are the phases used in below example

Rules :

  1. We need to define a class where we can store the current state of the process. NextPhase class in below code is doing that.

  2. We need to define an Interface wherein we can provide the contact method that would be implemented in each phase.In below code ProjectPhase is doing that.

Learn more about State design pattern here -- State Design Pattern

http://efectivejava.blogspot.in/2013/09/java-state-design-patten-oops-state.html?utm_source=BP_recent

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文