Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Me and a mate have a discussion about what would be the best way to implement the pattern state for managing several screens for an application we are developing.

We have a ScreenManager (I guess the Context class according some books) which looks like this (some irrelevant code has been removed to ease understanding) :

public class ScreenManager : DrawableGameComponent
{

    #region Fields

    List<GameScreen> screens = new List<GameScreen> ();
    List<GameScreen> screensToUpdate = new List<GameScreen> ();

    InputState input = new InputState ();

    #endregion

    /// <summary>
    /// Constructs a new screen manager component.
    /// </summary>
    public ScreenManager (Game game)
        : base(game)
    {
        content = new ContentManager (game.Services, "Content");

        graphicsDeviceService = (IGraphicsDeviceService)game.Services.GetService (
                                                    typeof(IGraphicsDeviceService));

        if (graphicsDeviceService == null)
            throw new InvalidOperationException ("No graphics device service.");
    }

    public override void Update (GameTime gameTime)
    {
        // Read the keyboard and mouse.
        input.Update ();

        // Make a copy of the master screen list, to avoid confusion if
        // the process of updating one screen adds or removes others
        // (or it happens on another thread)
        screensToUpdate.Clear ();

        foreach (GameScreen screen in screens)
            screensToUpdate.Add (screen);

        while (screensToUpdate.Count > 0) {
            // Pop the topmost screen off the waiting list.
            GameScreen screen = screensToUpdate [screensToUpdate.Count - 1];

            screensToUpdate.RemoveAt (screensToUpdate.Count - 1);

            // Update the screen.
            screen.Update (gameTime);
            screen.HandleInput (input);
        }
    }

    public void AddScreen (GameScreen screen)
    {
        screen.ScreenManager = this;

        if ((graphicsDeviceService != null) &&
            (graphicsDeviceService.GraphicsDevice != null)) {
            screen.LoadContent ();
        }

        screens.Add (screen);
    }

    public void RemoveScreen (GameScreen screen)
    {
        screens.Remove (screen);
        screensToUpdate.Remove (screen);
    }
}

As you can see, the screenmanager has a list of GameScreens which are updated every time the Update method is called.

Then here we have a couple of screens + base Screen class. At the base class, we create a coupling between GameScreen and ScreenManager, while there also exist a coupling between ScreenManager and GameScreen:

public abstract class GameScreen
{
    ScreenManager screenManager;

    public ScreenManager ScreenManager {
        get { return screenManager; }
        internal set { screenManager = value; }
    }

    public virtual void HandleInput (InputState input)
    {
    }

    public virtual void LoadContent ()
    {
    }

    public virtual void UnloadContent ()
    {
    }

    public virtual void Update (GameTime gameTime)
    {
    }
}

public class TitleScreen : GameScreen
{
    public Texture2D titleScreen;

    public TitleScreen ()
    {
    }

    public override void HandleInput (InputState input)
    {
        if (input.MenuSelect) {
            ScreenManager.AddScreen (new PlayingScreen ());
    }

}


public class PlayingScreen : GameScreen
{
//...... Irrelevant implementation details for my question
}

As you can see there, TitleScreen knows about PlayingScreen, creates it and adds it to ScreenManager (creating a dependency between TitleScreen and PlayingScreen). Although this kind of implementation has been seen in books (as far as I've read), my companion proposes me another kind of implementation: He proposes to create an Observer approach, replacing in TitleScreen the whole PlayingScreen management with an event, which would then be suscribed by the ScreenManager, and then the ScreenManager would orchestrate all the management of screens.

With this approach, he says TitleScreen could be reused in other applications and decouple screens among them, but create a big ScreenManager class who would be coupled with everyone.

I'm not sure whether the State approach or the Observer approach is better for my specific case. Which would be the best implementation?

Thank you

share|improve this question

migrated from stackoverflow.com Dec 3 '13 at 2:19

This question came from our site for professional and enthusiast programmers.

4  
This is almost never not a mistake. Envisioning re-usability when you have no clear vision on what the next project is going to look like just creates a maintenance hassle. A God class most certainly is never a solution to anything. Don't do it. –  Hans Passant Dec 2 '13 at 14:51
    
So, are you suggesting that we should stick to the State Pattern approach I described instead of the observer one? –  David Jiménez Martínez Dec 2 '13 at 15:05

1 Answer 1

up vote 1 down vote accepted

I agree with Hans that observer can make the maintenance more nightmare. What I can suggest is separating the concern (delegating the responsibility) of opening playing screen into another class, to follow Single Responsibility Principle.

Currently, your title class has at least 2 responsibility, that is:

  • rendering the title page and menus
  • add screen related to menu selected
  • (handle input such as arrow keys, etc)?

The add screen responsibility can be delegated to another class. Let's say it TitleAddScreenHandler.

public class TitleAddScreenHandler{
    public TitleAddScreenHandler(ScreenManager screenManager){
        // property assignments
    }
    private ScreenManager screenManager;

    public void AddScreen(InputState input){
        if (input.MenuSelect) {
            screenManager.AddScreen (new PlayingScreen ());
        }
    }
}

Then in your TitleScreen, you can has one instance of TitleAddScreenHandler or injected in constructor. It will limit the dependency only to one class.

share|improve this answer
    
So, I would have to add a new attribute to titleScreen in order to handle the management of events for that screen, right? Sounds logical, I have keep the Single Responsability Principle in my mind. Thank you very much for the answers and help. –  David Jiménez Martínez Dec 3 '13 at 22:32
    
I don't quite understand about the new attribute. However your understanding about TitleScreen does not handle the management of events is true. It is being handled in other class now –  Fendy Dec 4 '13 at 1:28

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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