2012-11-01 49 views
1

我正在写一个java模拟应用程序,它有很多要模拟的实体。这些实体中的每一个在系统中随时都有一定的状态。对这种实体建模的一种可能的自然方法是使用state (or state machine)模式。问题是,如果有很多状态切换,它会在运行时创建大量对象,这可能会导致系统性能不佳。我有什么设计方案?我希望性能成为可维护性之后的主要标准。java中高效的状态机模式

感谢

+3

有多确定对象创建将成为模拟的瓶颈? – aioobe

+0

我在想enum + switch –

+4

“might”是你问题中的关键字:你创建了更多的对象,但你不希望这样的表现是不可接受的!在分析之前优化是一个坏主意;编码您的理想解决方案,然后优化。 – dasblinkenlight

回答

1

我的建议:
您是否可以配置“转换管理”(即通过XML)。

将XML加载到存储状态的存储库。
内部数据结构将是一个地图:

Map<String,Map<String,Pair<String,StateChangeHandler>>> transitions; 

原因我选择的是,这将是一个国家的名字
地图要地图“输入”,新规定:
每个地图定义可能的输入,并导致其由国家名称和StateChangeHandler我将详细阐述定义的新状态之间的映射,后来在库
改变状态的方法将有一个签名:

void changeState(StateOwner owner, String input)

通过这种方式,存储库在状态所有者使用它的意义上是无状态的,您可以复制一个副本
而不用担心线程安全问题。
StateOwner将成为您需要状态改变的类应该实现的接口。
我认为界面应该是这样的:

public interace StateOwner { 
    String getState(); 
    void String setState(String newState); 
} 

此外,你将有一个ChangeStateHandler接口:

public interface StateChangeHandler { 
    void onChangeState(StateOwner, String newState) { 
    } 
} 

当仓库的改变状态的方法被调用时,它会
检查在数据结构上,stateOwner的当前状态具有“输入”的映射。 如果它有这样一个映射,它将检查输入是否有一个新的状态改变,并调用onChangeState方法。
我会建议你有一个StateChangeHandler的默认实现,当然还有子类,它们会更明确地定义状态变化行为。

正如我前面提到的,所有这些都可以从XML配置中加载,并且使用反射可以基于它们的名称(如XML中提到的)立即对StateChangeHandler对象进行实时处理,并将保存在存储库中。


效率和良好的性能依赖和获得使用以下几点:
a。存储库本身是无状态的 - 不应该保留StateOwner的内部引用。
b。您在系统启动时加载一次XML,然后在内存数据结构中进行处理。
c。您只会在需要时提供特定的StateChangeHandler实现,默认实现应该基本不做任何事情。
d。没有必要实例化处理程序的新对象(因为它们应该是无状态的)

0

这个建议是不是普遍的,它不是UML compliantsimple thing, it's a simple mean

import java.util.HashMap; 
import java.util.Map; 

class Mobile1 
{ 
    enum State { 
     FIRST, SECOND, THIRD 
    } 

    enum Event { 
     FIRST, SECOND, THIRD 
    } 

    public Mobile1() {  // initialization may be done by loading a file 
     Map< Event, State > tr; 
     tr = new HashMap<>(); 
     tr.put(Event.FIRST, State.SECOND); 
     _fsm.put(State.FIRST, tr); 
     tr = new HashMap<>(); 
     tr.put(Event.SECOND, State.THIRD); 
     _fsm.put(State.SECOND, tr); 
     tr = new HashMap<>(); 
     tr.put(Event.THIRD, State.FIRST); 
     _fsm.put(State.THIRD, tr); 
    } 

    public void activity() {  // May be a long process, generating events, 
     System.err.println(_state);// to opposite to "action()" see below 
    } 

    public void handleEvent(Event event) { 
     Map< Event, State > trs = _fsm.get(_state); 
     if(trs != null) { 
     State futur = trs.get(event); 
     if(futur != null) { 
      _state = futur; 
      // here we may call "action()" a small piece of code executed 
      // once per transition 
     } 
     } 
    } 

    private final Map< 
     State, Map< 
     Event, State >> _fsm = new HashMap<>(); 
    private /* */ State _state = State.FIRST; 
} 

public class FSM_Test { 
    public static void main(String[] args) { 
     Mobile1 m1 = new Mobile1(); 
     m1.activity(); 
     m1.handleEvent(Mobile1.Event.FIRST); 
     m1.activity(); 
     m1.handleEvent(Mobile1.Event.SECOND); 
     m1.activity(); 
     m1.handleEvent(Mobile1.Event.FIRST); // Event not handled 
     m1.activity(); 
     m1.handleEvent(Mobile1.Event.THIRD); 
     m1.activity(); 
    } 
} 

输出:

FIRST 
SECOND 
THIRD 
THIRD 
FIRST 
+0

这当然很简单,但对于使用状态机的情况来说,这太过分了。有可能做得更好。 – duffymo

+0

我正在等待您的提议 – Aubin

+0

请参阅上文。由XML驱动的类。发布的代码过多。 “符合UML”是什么意思? UML与任何事情无关,更不用说这个问题了。 – duffymo

3

下面的代码将会给您提供高性能的(10ns的〜/事件)零运行GC状态机实现。只要系统或组件中具有状态概念,就可以使用显式状态机,这不仅使代码更加干净和可扩展,而且可以让人们(甚至程序员)立即看到系统的功能,而无需在众多回调中进行挖掘:

abstract class Machine { 
    enum State { 
     ERROR, 
     INITIAL, 
     STATE_0, 
     STATE_1, 
     STATE_2; 
    } 

    enum Event { 
     EVENT_0, 
     EVENT_1, 
     EVENT_2; 
    } 

    public static final int[][] fsm; 
    static { 
     fsm = new int[State.values().length][]; 
     for (State s: State.values()) { 
     fsm[s.ordinal()] = new int[Event.values().length]; 
     } 
    } 

    protected State state = State.INITIAL; 
    // child class constructor example 
    // public Machine() { 
    // // specify allowed transitions 
    // fsm[State.INITIAL.ordinal()][Event.EVENT_0.ordinal()] = State.STATE_0.ordinal(); 
    // fsm[State.STATE_0.ordinal()][Event.EVENT_0.ordinal()] = State.STATE_0.ordinal(); 
    // fsm[State.STATE_0.ordinal()][Event.EVENT_1.ordinal()] = State.STATE_1.ordinal(); 
    // fsm[State.STATE_1.ordinal()][Event.EVENT_1.ordinal()] = State.STATE_1.ordinal(); 
    // fsm[State.STATE_1.ordinal()][Event.EVENT_2.ordinal()] = State.STATE_2.ordinal(); 
    // fsm[State.STATE_1.ordinal()][Event.EVENT_0.ordinal()] = State.STATE_0.ordinal(); 
    // fsm[State.STATE_2.ordinal()][Event.EVENT_2.ordinal()] = State.STATE_2.ordinal(); 
    // fsm[State.STATE_2.ordinal()][Event.EVENT_1.ordinal()] = State.STATE_1.ordinal(); 
    // fsm[State.STATE_2.ordinal()][Event.EVENT_0.ordinal()] = State.STATE_0.ordinal(); 
    // } 

    public final void onEvent(Event event) { 
     final State next = State.values()[ fsm[state.ordinal()][event.ordinal()] ]; 
     if (next == State.ERROR) throw new RuntimeException("invalid state transition"); 
     if (acceptEvent(event)) { 
     final State prev = state; 
     state = next; 
     handleEvent(prev, event); 
     } 
    } 

    public abstract boolean acceptEvent(Event event); 
    public abstract void handleEvent(State prev, Event event); 
} 

如果fsm被大小为S * E的单目数组替代,它也将改善状态机的缓存接近度特性。

+0

本地数组分配新(零GC?),并查找你必须编写自己的“for”循环。性能?事件和国家不能是通用的,它们是具体的每个具体类。 – Aubin

+0

@Aubin - 运行时零GC。我已经演示了保证高性能和可扩展性的技术,SxN,类可以尽可能地泛化,转换表可以带到子类,等等。 – bobah