2

This is a theory question for me just to try and write better code. I am pretty new so hopefully I am using terms like state in the correct way.

How I should be thinking about this problem? I am coding something that sort of works but whatever I do it seems complicated, hard to understand and hard to modify.

I'm playing a video clip with an id, I also want it to be able to dynamically switch to a thumbnail view of that video clip. I want to be able to set this video blank also and shut down any connections that are not needed, I'm trying to do all of this efficiently - not reconnecting to the server when I don't need to etc.

so I have-

connected -> on/off

video id -> a string

mode -> streaming video/thumbnail view/disabled

Hopefully you will see my dilemma with some examples-

Case 1.The user starts from scratch and wants to view a thumbnail of video "a"

-connect to server for "a", send request for thumbnail, turn thumbnail object on.

Case 2.The user starts is viewing a thumbnail of video "a" and wants to start watching a stream of video "b"

-compare strings "a" and "b"- see they are different. hide thumbnail object and clear its buffer. Disconnect from server for "a" and connect to "b" server. start streaming video, turn video object on, request thumbnail from the server so its loaded in memory in case the user wants to switch to thumbnail mode.

Case 3.the user is watching a stream of "b" and wants to view a thumbnail of "b"

-compare strings "b" and "b"- see they are the same and stay connected to the server, hide video object and stop streaming, turn thumbnail object on, send another request to server for the thumbnail...

All these options are doing my head in, I want it to choose the most efficient way to get from one state to another but all the different options are confusing me. I guess Im looking for help about whats the best way to structure this, because what Im doing at the moment seems very confusing, i end up with huge tree of nested ifs of lots of specific cases and then patching up where it goes wrong.

if (connected but used to be disconnected) { 
    if (mode streaming but used to be thumbnail) {...
    if (mode streaming but used to be streaming) {...

if (connected but used to be connected) {....

if (disconnected but used to be connected) {....

if (disconnected but used to be disconnected) {...

it goes on forever..

  • This kind of thing is reminiscent of MVC pattern as well. – Andyz Smith Aug 28 '13 at 0:02
6

Encapsulate each non-trivial state in a separate State class which knows how to transition from one state to the next. When a transition occurs, the state object changes. For instance, from "ConnectedState" to "DisconnectedState".

Model your problem as a state machine. I'm a big fan of the state pattern to solve these things.

  • FSM is indeed the way to go. – Deer Hunter Aug 6 '13 at 9:14
  • Thanks! I didnt even know the term "state machine" and now I do theres a whole wealth of information to sort through. Thanks for your help. – pjackson Aug 6 '13 at 23:45
  • Feel free to mark this answer as correct if that is the case. – Martin Wickman Aug 11 '13 at 9:14
2

Martin Wickman is correct in suggesting a state-machine.

It looks like you might benefit from nesting some of your state information (e.g. connection status) -- nesting means that your overarching states will have internal state-machines of their own -- in which case you might want to check out UML state machines.

UML state machines are more complex than regular finite state machines and, in my experience, fairly cumbersome to implement by hand. As an alternative, to clean up what you have now and move towards a more OOPish implementation, you could try this:

Split things into three or four orthogonal functions:

  • A next-state determination function -- this would take the machine's current state and its current input and determine what the next machine state should be
  • A transition output function -- this would look at what state transition was being taken, along with the input, and react to it (comparable to a Mealy machine's output)
  • A state output function -- this would look at the current state and output for it (comparable to a Moore machine's output)
  • A transition function -- this would call the other three functions and set the machine's state

Example:

func getNextState(input, curr_state)
{
    if (curr_state == STATE_FOO)
    {
        if (input == fizz)
            return STATE_FIZZ
        else
            return STATE_BUZZ
    }
    else if (curr_state == STATE_BAR)
    {
        ...
    }
    else
    {
        return STATE_DONE
    }
}

func outputForTransition(input, prev_state, next_state)
{
    if (prev_state == STATE_FIZZ && next_state == STATE_BUZZ)
    {
        print "Fizz Buzz"
    }
    else if (prev_state == STATE_FOO && next_state == STATE_BAR)
    {
        ...
    }
}

func outputForState(curr_state)
{
    switch(curr_state)
    {
        case STATE_FOO:
            foo()
        case STATE_BAR:
            bar()
        case STATE_FIZZ:
            fizz()
        case STATE_BUZZ:
            buzz()
    }
}

func transitionStates(input)
{
    prev_state = curr_state
    curr_state = getNextState(input, curr_state)

    // you could use either or both output functions:
    outputForTransition(input, prev_state, curr_state)
    outputForState(curr_state)
}

It may still look somewhat messy, but believe me it clears things up quite a bit.

(And obviously you'd want to implement the above after having come up with your state diagram.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.