圌ã¯1ã€ã®ããããããŠã³ããã¯ã¹ããå§ããã¢ãã¡ãŒã·ã§ã³ããã¹ããã100ïŒ ã®ã€ãŒãºã¢ãŠããèšå®ããçµæã楜ããã§ããŸãã ãããã圌ã¯ããã«ãã¡ãã¥ãŒã管çããããã«ãçŸåšã¡ãã¥ãŒãéããããŠãããã©ãããç¥ãããšãã§ããã°ããããšã«æ°ã¥ããŸãã ããã§ã¯çµéšè±å¯ãªããã°ã©ãã§ããããã©ã°ãè¿œå ããå¿ èŠãããããšããã¹ãŠç解ããŠããŸãã 質åã¯ãããŸããããã©ã°ããããŸãã
var opened = false;
ããŸãããããã§ãã ãã ãããã¿ã³ããã°ããã¯ãªãã¯ãããšãã¡ãã¥ãŒãç¹æ» ãå§ããéãããéãããããŠãããæçµç¶æ ã«æ»ããŸãã Vasyaã¯ã¢ãã¡ãŒã·ã§ã³ãã©ã°ãè¿œå ããŸãã ã³ãŒãã¯æ¬¡ã®ãšããã§ãã
var opened = false; var animating = false; function onClick(event) { if (animating) return; if (opened) close(); else open(); }
ãã°ãããããšãVasyaã¯ã¡ãã¥ãŒãå®å šã«ãªãã«ããŠéã¢ã¯ãã£ãã«ã§ãããšèšãããŸãã 質åãªãïŒ ç§ãã¡ã¯ããã§çµéšè±å¯ãªããã°ã©ããŒã§ãããå šå¡ãç解ããŠããŸã...ãã1ã€ã®ãã©ã°ãè¿œå ããå¿ èŠããããŸãïŒ ãããŠãéçºã®æ°æ¥åŸãã¡ãã¥ãŒã³ãŒãã¯ãã§ã«æ¬¡ã®ãããªäºéè¡IFã§æºããããŠããŸãã
if (enabled && opened && !animating && !selected && finishedTransition && !endOfTheWorld && ...) { ... }
Vasyaã¯è³ªåãéå§ããŸããã¢ãã¡ãŒã·ã§ã³å== trueãã€æå¹å== falseã«ããã«ã¯ã©ãããã°ããã§ããã ãªããã¹ãŠãæã ãã°ãããã®ã§ããã ã¡ãã¥ãŒã®ç¶æ ãã©ã®ããã«ç解ããããšãã§ããŸããïŒ ããïŒ ç¶æ ...ãããã«ã€ããŠããã«èª¬æããŸãã
ãã®Vasyaã«äŒããŸãããã
ç¶æ
Vasyaã¯ããã©ã°ã®å€ãã®çµã¿åãããæå³ããªããªãããšããã§ã«èªèãå§ããŠãããæ®ãã¯ãããšãã°Disabled ã Idle ã Animating ã Openedã®ãããªããã€ãã®åèªã§ç°¡åã«èª¬æã§ããŸãã ããã§ã¯ãã¹ãŠçµéšè±å¯ãªããã°ã©ãã§ãããã¹ããŒããã·ã³ã«ã€ããŠããã«èŠããŠããŸãã ããããVasyaã¯ããããäœã§ããããªãã§ãããã説æããå¿ èŠããããŸãã æ°åŠçšèªã®ãªãåçŽãªèšèªã
ããšãã°ãåè¿°ã®ã¡ãã¥ãŒãªã©ã®ãªããžã§ã¯ãããããŸãã ãªããžã§ã¯ãã¯åžžã«1ã€ã®ç¶æ ã«ãããããŸããŸãªã€ãã³ãã«åå¿ãããšããããã®ç¶æ éã§é·ç§»ããå¯èœæ§ããããŸãã éåžžãç¶æ ãã€ãã³ããããã³é·ç§»ã¯ãã®ãããªã¹ããŒã ã§ç°¡åã«èšè¿°ãããŸãïŒåæç¶æ ãšæçµç¶æ ã¯åã§ç€ºãããŸãïŒã
ãã®å³ããã Inactiveç¶æ ããActiveã«è³ããŸã§ã¯Beginã€ãã³ãã®ã¿ã§ååŸã§ãã Pausedç¶æ ããã¯ActiveãšInactiveã®äž¡æ¹ã«å°éã§ããããšãæããã§ãã äœããã®çç±ã§ããã®ãããªåçŽãªæŠå¿µã¯ãæéç¶æ æ©æ¢°ããŸãã¯ãæéç¶æ æ©æ¢°ããšåŒã°ããäžè¬ã®äººã ã«ãšã£ãŠéåžžã«æããã®ã§ãã
OOPå¥çŽã«ããã°ãç¶æ ã¯ãªããžã§ã¯ãã®å éšã«é ãããŠããªããã°ãªãããå€éšããã¯ã¢ã¯ã»ã¹ã§ããŸããã ããšãã°ããªããžã§ã¯ãã¯æäœäžã«20ã®ç°ãªãç¶æ ãæã€å ŽåããããŸãããå€éšAPIã¯ãå æ°ã§ããïŒããšãã質åã«çãããã®ãã¡19åã«ããã®ãããªããšã¯ãããŸã ãããšçãã ãã¹ãŠã®ããªããŒãæ éããããšãèªããŸãã
ã¹ããŒããã·ã³ã®æŠå¿µã«åŸã£ãŠããã®ãªããžã§ã¯ããŸãã¯ãã®ãªããžã§ã¯ããäœãã©ã®ããã«è¡ãããåžžã«æ確ã«ãªãããã«ãã³ãŒããéåžžã«ç°¡åã«æ§æã§ããŸãã ã·ã¹ãã ãçªç¶ãã®ç¶æ ããã¢ã¯ã»ã¹ã§ããªãç¶æ ã«ãªãããšããå ŽåãäœããããŸããããªãã£ãããšã¯åžžã«æããã§ãã ãããŠãçªç¶ééã£ãæéã«æ¥ãããšãæ¢ããŠããåºæ¥äºã¯å®å šã«ç¡èŠããããšãã§ããäœããå£ããããšãæããããšã¯ãããŸããã
äžçã§æãã·ã³ãã«ãªã¹ããŒããã·ã³
ä»ãVasyaãCïŒã§ãããžã§ã¯ããè¡ã£ãŠããã1çš®é¡ã®ãªããžã§ã¯ãã«åçŽãªã¹ããŒããã·ã³ãå¿ èŠã ãšããŸãã 圌ã¯æ¬¡ã®ããã«æžããŠããŸãã
private enum State { Disabled, Idle, Animating } private State state; void setState(State value) { state = value; switch (state) { case State.Disabled: ... case State.Idle: ... case State.Animating : ... break; } }
ãããŠãããã¯çŸåšã®ç¶æ ã«å¿ããŠã€ãã³ããåŠçããæ¹æ³ã§ãïŒ
void event1Handler() { switch (state) { case State.Idle: ... break; } }
ããããããã§ç§ãã¡ã¯çµéšè±å¯ãªããã°ã©ããŒã§ãããsetStateã¡ãœãããæçµçã«æ°åããŒãžã«æé·ããããšãç解ããŠããŸããããã¯ïŒæç§æžã«æžãããŠããããã«ïŒè¯ããããŸããã
ç¶æ ãã¿ãŒã³
æ°æéã°ãŒã°ã«ã§èª¿ã¹ãVasyaã¯ããã®ãããªç¶æ³ã§ã¯State Patternãçæ³çã§ãããšå€æããŸããã ããã«ãäžçŽããã°ã©ããŒã¯åžžã«ç«¶åããŠããã誰ãããå€ãã®ãã¿ãŒã³ãã¢ããªã«ããã·ã¥ããã®ã§ãVasyaã¯ããã¿ãŒã³ã¯éèŠãªãã®ã§ãããšå€æããŠããŸãã
ããšãã°ãç¶æ ãã¿ãŒã³ã®å Žåã IStateã€ã³ã¿ãŒãã§ã€ã¹ãäœæã§ããŸãã
public interface IState { void Event1(); void Event2(); }
ãããŠããã®ã€ã³ã¿ãŒãã§ãŒã¹ãå®è£ ããç¶æ ããšã«åå¥ã®ã¯ã©ã¹ã çè«çã«ã¯ãèŠãç®ã¯çŸãããæç§æžã®100ïŒ ã§ãã
ãããããŸããäžå¹žãªå°ããªç¶æ ãã·ã³ããšã«ãå€ãã®ã¯ã©ã¹ãäœæããå¿ èŠããããŸãããããèªäœã¯é«éã§ã¯ãããŸããã 第äºã«ãé ããæ©ãããå ±æããŒã¿ãžã®ã¢ã¯ã»ã¹ã«é¢ããåé¡ãçºçããŸãã ããããã©ãã«ä¿åããŸããïŒ ã¡ã€ã³ã¯ã©ã¹ã§ã¯ïŒ ãããŠãç¶æ ã¯ã©ã¹ã¯ã©ã®ããã«ãããã«ã¢ã¯ã»ã¹ããŸããïŒ ãããŠãç· ãåãã®15ååã«ã«ãŒã«ããã€ãã¹ããå°ããªããã¯ãã©ããã£ãŠååŸããã®ã§ããïŒ ãããŠãéçºãå€§å¹ ã«é ãããåæ§ã®çžäºäœçšã®åé¡ã
èšèªããŒã¹ã®å®è£
äžéšã®ããã°ã©ãã³ã°èšèªã§ã¯ãç¹å®ã®åé¡ãç°¡åã«è§£æ±ºã§ããŸãã ããšãã°ãRubyã«ã¯ãäžè¬ã«ã¹ããŒããã·ã³ãäœæããããã®DSLããããŸãïŒ1ã€ã§ã¯ãããŸããïŒã CïŒã§ã¯ããªãã¬ã¯ã·ã§ã³ã䜿çšããŠã¹ããŒããã·ã³ãç°¡çŽ åã§ããŸãã ãã®ãããªãã® ïŒ
- FiniteStateMachineã¯ã©ã¹ãç¶æ¿ãã
- stateName_eventNameïŒïŒãšããã¡ãœãããäœæããŸããããã¯ãç¶æ é·ç§»ããã³ã€ãã³ãåŠçæã«èªåçã«åŒã³åºãããŸã
æžãã³ãŒãã¯æ¬åœã«ãã£ãšå°ãªãã§ãã
äžèšã®ã·ã¹ãã ãå®è£ ããVasyaã¯ããã©ã¹ããããã€ãã¹ãå€ãããšãç解ããŠããŸãã
- FiniteStateMachineã¯ã©ã¹ããç¶æ¿ããå¿ èŠããããŸãã
- ã«ã¹ã¿ã ã€ãã³ããžã®åå¿ã§ã¯ã倧ããªã¹ã€ããã³ã³ã¹ãã©ã¯ããèšè¿°ããå¿ èŠããããŸãã
- ç¶æ ãå€åãããšãã«ãã©ã¡ãŒã¿ãŒãæž¡ãæ¹æ³ã¯ãããŸããã
æ çµã¿
äžæ¹ãVasyaã¯ã¹ããŒããã·ã³ã®çè«ãæãäžãå§ããAPIãä»ããŠããŸãã¯çè«çã«ã¯ã¯ãŒã«ã«èãããXMLãä»ããŠXMLãä»ããŠæ£åŒã«èšè¿°ã§ãããšãããšå€æããŸããã ããã§ã¯çµéšè±å¯ãªããã°ã©ããŒã§ãããç¬èªã®ãã¬ãŒã ã¯ãŒã¯ãäœæããå¿ èŠãããããšããã¹ãŠç解ããŠããŸãã ä»ã®äººã¯é©åã§ã¯ãªãã®ã¯ã圌ãã«ã¯ãã¹ãŠèŽåœçãªæ¬ é¥ãããããã§ãã
Vasyaã¯ããã¬ãŒã ã¯ãŒã¯ã®å©ããåããŠãå€ãã®äžå¿ èŠãªã³ãŒããèšè¿°ããããšãªããã¹ããŒããã·ã³ãè¿ éãã€ç°¡åã«äœæã§ãããšå€æããŸããã ãã¬ãŒã ã¯ãŒã¯ã¯ãéçºè ã«å¶éã課ããŸããã åšãã¯éœæ°ã§éœæ°ã§ãã
ç§ã¯ããŸããŸãªèšèªã§å€ãã®ãã¬ãŒã ã¯ãŒã¯ãè©ŠããŸããããèªåã§äŒŒããããªãã®ãããã€ãæžããŸããã ãããŠãåžžã«ããã¬ãŒã ã¯ãŒã¯ããŒã«ã䜿çšããŠæéç¶æ ãã·ã³ãèšè¿°ããã«ã¯ã åçŽãªäŸãããå€ãã®ã³ãŒããå¿ èŠã§ããã ãããã¯ãã¹ãŠäžå®ã®å¶éã課ããŠãããå€ãã®äººãäžåºŠã«å€ãã®ããšãããããšãããããåçŽãªã¹ããŒããã·ã³ã®äœææ¹æ³ãç解ããããã«ãããã¥ã¡ã³ããé·æé調ã¹ãå¿ èŠããããŸãã
ããšãã°ã ã¹ããŒãã¬ã¹ãã¬ãŒã ã¯ãŒã¯ã«ããã¹ããŒããã·ã³ã®èª¬æã次ã«ç€ºããŸãã
var phoneCall = new StateMachine<State, Trigger>(State.OffHook); phoneCall.Configure(State.OffHook) .Permit(Trigger.CallDialed, State.Ringing); phoneCall.Configure(State.Ringing) .Permit(Trigger.HungUp, State.OffHook) .Permit(Trigger.CallConnected, State.Connected); phoneCall.Configure(State.Connected) .OnEntry(() => StartCallTimer()) .OnExit(() => StopCallTimer()) .Permit(Trigger.LeftMessage, State.OffHook) .Permit(Trigger.HungUp, State.OffHook) .Permit(Trigger.PlacedOnHold, State.OnHold);
ãã ããã¹ããŒããã·ã³ã®äœæãå®äºãããšããã¬ãŒã ã¯ãŒã¯ãæäŸãã䟿å©ãªæ©èœãå©çšã§ããŸãã ããã¯äž»ã«ãé·ç§»ã®æ£ç¢ºæ§ãäŸåç¶æ ãã·ã³ãšãµãç¶æ ãã·ã³ã®åæãããã³ã°ãã«å¯Ÿããããããçš®é¡ã®ä¿è·ã®ãã§ãã¯ã§ãã
XML
XMLã¯å¥ã®æªã§ãã ãã€ãŠèª°ããããã䜿ã£ãŠèšå®ãæžãããšãèããŸããã javaéçºè ã®ã¬ãã³ã°ã¹ã®çŸ€ãã圌ã®ããã«é·ãéç¥ã£ãŠããŸããã ãããŠä»ã誰ããXMLã䜿çšããçç±ã誰ããŸã ç¥ããŸãããããããåãé€ãããšããŠãããã¹ãŠã®äººãæã¡è² ãããŠããŸãã
Vasyaã¯ããã¹ãŠãXMLã§æ§æã§ããã³ãŒãã1è¡ãæžããªããšããèããæã£ãŠããŸãïŒ ãã®çµæããã®ãã¬ãŒã ã¯ãŒã¯ã«ã¯ãããã次ã®å 容ã®XMLãã¡ã€ã«ãåå¥ã«å«ãŸããŸãã
<fsm name="Vending Machine"> <states> <state name="start"> <transition input="nickel" next="five" /> <transition input="dime" next="ten" /> <transition input="quarter" next="start" action="dispense" /> </state> <state name="five"> <transition input="nickel" next="ten" /> <transition input="dime" next="fifteen" /> <transition input="quarter" next="start" action="dispense" /> </state> <state name="ten"> <transition input="nickel" next="fifteen" /> <transition input="dime" next="twenty" /> <transition input="quarter" next="start" action="dispense" /> </state> ... </states> </fsm>
ã¯ã©ã¹ïŒ ããã°ã©ãã³ã°ã¯äžèŠã§ãã ããããããã§ç§ãã¡ã¯çµéšè±å¯ãªããã°ã©ããŒã§ãããããã°ã©ãã³ã°ã¯ã©ãã«ãè¡ã£ãŠããªãããšãçãç解ããŠããŸãã Vasyaã¯ãç¹æš©ã³ãŒãã宣èšã³ãŒãã«çœ®ãæãããã¬ãŒã ã¯ãŒã¯ã«XMLã€ã³ã¿ãŒããªã¿ãŒãè¿œå ããŸããããããã§ãæ°åè€éã«ãªããŸããã ãããŠãã³ãŒããç°ãªãèšèªã§ããããããžã§ã¯ãã®ãã¡ãã¡ã«æ£ãã°ã£ãŠãããšãã«ãããããŠã¿ãŠãã ããã
åæ
ãããŠãVasyaã¯ããããã¹ãŠã«ããããããäžçã§æãåçŽãªã¹ããŒããã·ã³ã«æ»ã£ãã 圌ã¯ãããå°ãããçŽãããã®äžã«ã³ãŒããæžãããã®ã«ãŒã«ãæãã€ããŸããã
æŽæ°ïŒ ã³ã¡ã³ããããããšãã å°ã説æããããŸããã§ããã
ããã€ãã®å·ããããŸãã ãããã®éã®é·ç§»ã¯ã¢ãããã¯æäœã®ãã©ã³ã¶ã¯ã·ã§ã³ã§ããã€ãŸãããããã¯åžžã«æ£ããé åºã§äžç·ã«çºçããä»ã®ã³ãŒãã¯ãããã®éãããã³ã§ç· ããããšãã§ããŸããã ç¶æ ãAããBã«å€ãããšã次ã®ããšãèµ·ãããŸããç¶æ Aããã®çµäºã³ãŒããå®è¡ãããç¶æ ãAããBã«å€ãããç¶æ Bã®ãšã³ããªã³ãŒããå®è¡ãããŸãã
ç¶æ Aã«åãæ¿ããã«ã¯ãstateAã¡ãœãããåŒã³åºãå¿ èŠããããŸãããã®ã¡ãœããã¯ãå¿ èŠãªããžãã¯ãå®è¡ããsetStateïŒAïŒãåŒã³åºããŸãã setStateïŒAïŒãèªåã§åŒã³åºãããšã¯éåžžã«æšå¥šãããŸããã
次ã®ããšãå€æããŸããã
/** * enum , enums. */ private enum State { Disabled, Idle, Animating } /** * . , . */ private State state; /** * state< >(). * . * setState(newValue) . */ void stateDisabled() { switch (state) { case State.Idle: break; } setState(State.Disabled); // State Disabled enter logic } /** * . * stateIdle(0); */ void stateIdle(int data) { setState(State.Idle); // State Idle enter logic } void stateAnimating() { setState(State.Animating); // State Animating enter logic } /** * setState * state = value; * prevState = state; . * , . */ void setState(State value) { switch ( state ) { case State.Animating: // state Animating exit logic break; // other states } state = value; } /** * , . */ void event1Handler() { switch (state) { case State.Idle: // state Idle logic break; // other states } }
æŽæ°ïŒ setStateïŒïŒã«ã¯ãç¶æ ãçµäºããããã®åºæã®ããžãã¯ãæžã蟌ãŸããstateBïŒïŒã«ã¯ãBã«ç§»åãããšãã«ç¶æ Aãçµäºããããã®ç¹å®ã®ããžãã¯ã䜿çšã§ããŸããããããéåžžã«ãŸãã«äœ¿çšãããŸãã
ã¹ããŒããã·ã³ãèšè¿°ããããã®åçŽãªèŠåã éåžžã«æè»ã§ã次ã®å©ç¹ããããŸãã
- ç¶æ ãå€æŽãããšãã®ã»ãšãã©ãã¹ãŠã®ããžãã¯ã¯stateAïŒïŒã¡ãœããã«ãããŸããããã«ããã setStateïŒïŒã®å·šå€§ãªã¹ã€ããã解é€ããŠã³ãŒããèªã¿ãããããããšãã§ããŸãã
- ç¶æ ã®å€æŽã¯ããããã°ã容æã«ããstateAïŒïŒã¡ãœãããéããŠã®ã¿çºçããŸãã
- ããšãã°ãæ¬ã«ããŒãžç¶æ ãããå Žåã statePageïŒ42ïŒãåŒã³åºããŠç¶æ ãå€æŽããã ãã§ãæ°ããããŒãžã«åãæ¿ããããšãã§ããŸãã
- ã€ãã³ããã³ãã©ãŒã§ã¯ãã©ã®ããžãã¯ãã©ã®ç¶æ ã§å®è¡ããããã¯åžžã«æ確ã§ãã
- ãã¹ãŠã®ããŒã ã¡ã³ããŒã¯ãç¶æ ãéå§ããã³çµäºããããã®ããžãã¯ãèšè¿°ããå Žæãç¥ã£ãŠããŸãã
- æéç¶æ ãã·ã³ã®ãã¬ãŒã ã¯ãŒã¯ãšäºåæ§æã¯å¿ èŠãããŸããã
- ã¬ãŒã«ãã¬ã³ãã«ãšã£ãŠçµ¶å¯Ÿã«äœã§ããªãå ŽåãæåŸã®ç¬éã«ãã¹ãŠãæ±ãå¯èœæ§ããããŸãã
å¥ã®éèªæãªå©ç¹ã¯ãåæãèšèªããç¬ç«ããŠããããšã§ãã ãããã©ãããã©ãŒã ããå¥ã®ãã©ãããã©ãŒã ã«ç§»è¡ããå Žåããæ°ã«å ¥ãã®ãã¬ãŒã ã¯ãŒã¯ãå¥ã®èšèªã«æžãçŽããããé©åãªãã¬ãŒã ã¯ãŒã¯ãæ¢ãããããå¿ èŠã¯ãããŸããã
ãã¹ãŠã®åæã«ããããã«ãäžéšã®ã³ãŒãã¯æåã«1ã€ã®å Žæã«ããå ŽåããããŸããããã®åŸãå¥ã®æå³ãæã€ããã©ããã«è€è£œãããããšãå€æããŸãã ãã®åŸãå¥ã®å Žæã«ç§»åã§ããŸãã 誰ãç§ãã¡ãçŠæ¢ããŠããŸããã ããã§ããã³ãŒãã¯ç³ã§åœ«ããããã®ã§ã¯ãªããïŒæãããïŒïŒãããžã§ã¯ãã®éçºã«äŒŽã£ãŠå€æŽãããå¯èœæ§ã®ããããã¹ãã§ãã
UPDATEïŒ ããã³setStateïŒïŒã¯ãæ確ã«ããããã«1ã€ã®ã»ãã¿ãŒã«å®å šã«çœ®ãæããããšãã§ããŸãã
ãããã«
ããã§ãã¹ããŒããã·ã³ã®äžçã§ã®Vasyaã®é åçãªåéºã¯çµããã§ãã ãããããŸã éåžžã«èå³æ·±ãããšããããŸãã å¥ã®ãããã¯ã§ã¯ããã©ã¬ã«ã¹ããŒããã·ã³ãšäŸåã¹ããŒããã·ã³ã«å€ããã ãã§ãã
ã¹ããŒããã·ã³ããŸã ã©ãã§ã䜿çšããŠããªãå Žåã¯ããã®èšäºãããªããè¯ãåŽã«åŒãå¯ããããšãé¡ã£ãŠããŸãã ã¹ããŒããã·ã³ãæäœããããã®uberframeworkãäœæãããšãæ°é®®ãªå€èŠ³ã§åŸããããã®ã確èªããã®ã«åœ¹ç«ã¡ãŸãã
ãã®èšäºããéçºè ããã¿ãŒã³ãšãã¬ãŒã ã¯ãŒã¯ãã©ãã§ããã€äœ¿çšããããèããå©ãã«ãªããã¹ããŒããã·ã³ã®èšèšã«é¢ãã説æãããåæã誰ãã«åœ¹ç«ã€ããšãé¡ã£ãŠããŸãã