user3488765
user3488765

Reputation: 443

How do I create a class that always is the same instance of itself and is used keep track of variable values?

So I want to outsource all important variables to a new class. A non working example to showcase what I'm trying to do would be this:

public class GameState{
    public bool ToggleA{ get; set; }
    public bool ToggleB{ get; set; }
    public int a{ get; set; }
    public int b{ get; set; }
}

How can I "keep this class alive" once a value was set and make everything refer to the same instance? My google searches led me Singleton patterns (Link, however that didn't bring me further, either I didn't understand how to implement what I want to do into them properly, in that case, an in-depth example would be neat, or I need to use something else?

Upvotes: 1

Views: 89

Answers (2)

Charles Graham
Charles Graham

Reputation: 1157

The best way to implement this is indeed using the singleton design pattern. It will allow your code to remain testable.

Given the following interface:

public interface IGameState
{
  bool ToggleA { get; set; }
  bool ToggleB { get; set; }
  int A { get; set; }
  int B { get; set; }
}

The following is a singleton implementation of it:

public class GameState : IGameState
{
  // This instance variable will only ever have one copy instantiated
  private static GameState _instance = new GameState();

  // Private constructor so the class cannot be instantiated outside of the class.
  // This ensures that no other class can create an instance of the class.
  private GameState() { }

  public static GameState Instance { get { return _instance; } }

  public bool ToggleA { get; set; }
  public bool ToggleB { get; set; }
  public int A { get; set; }
  public int A { get; set; }
}

You can now inject this singleton wherever you need it, which will maintain the test-ability of your code.

public class SomeObject
{
  private IGameState _gameState;
  public SomeObject(IGameState gameState)
  {
    _gameState = gameState;
  }

  public void SomeOperationOnGameState()
  {
    _gameState.ToggleA = true;
  }
}

EDIT: Updating to explain test related comments

Imagine that your GameState object evolves has a complex method for performing a calculation, and that you want to ensure that this method is called when necessary. If you are using a global static class, there is no way to verify this behavior. If you are programming to an interface however you can mock out this dependency using a mocking framework and verify that the complex method was indeed called.

For example, we are going to extend the IGameState interface to the following:

public interface IGameState
{
  bool ToggleA { get; set; }
  bool ToggleB { get; set; }
  int A { get; set; }
  int B { get; set; }

  int ComplexStateAlteringMethod();
}

Now imagine you have some sort of Controller class, that manages key presses:

public class Controller
{
  private IGameState _gameState;
  public Controller(IGameState gameState)
  {
    _gameState = gameState;
  }

  public void KeyPressed(string key)
  {
    // Implementation details go here, say you want to call the complex method when the 'A' key is pressed
    if (key == "A")
    {
      _gameState.ComplexStateAlteringMethod();
    }
  }
}

You want to ensure that when the 'A' key is pressed, the IGameState.ComplexStateAlteringMethod() is called.

Without explaining mocks, i'll create a Stub IGameState:

public class StubGameState : IGameState
{   
  public bool ToggleA { get; set; }
  public bool ToggleB { get; set; }
  public int A { get; set; }
  public int B { get; set; }

  public bool WasStateAlteringMethodCalled { get; private set; }
  public void ComplexStateAlteringMethod()
  {
    WasStateAltermingMethodCalled = true;
  }
}

Now you can use this stub class can be used to verify the behavior you are looking for (Assuming NUnit is the testing framework):

[TestFixture]
public class ControllerTests
{
  [Test]
  public void KeyPressed_WhenAIsPressed_ShouldCallStateAlteringMethod()
  {
    // Arrange
    var stub = new StubGameState();
    var controller = new Controller(stub);

    // Act
    controller.KeyPressed("A");

    // Assert
    Assert.IsTrue(stub.WasStateAlteringMethodCalled);
  }

  [Test]
  public void KeyPressed_WhenBIsPressed_ShouldNotCallStateAlteringMethod()
  {
    // Arrange
    var stub = new StubGameState();
    var controller = new Controller(stub);

    // Act
    controller.KeyPressed("B");

    // Assert
    Assert.IsFalse(stub.WasStateAlteringMethodCalled); 
  }
}

Upvotes: 1

K893824
K893824

Reputation: 1319

Make it a static class.

public static class GameState ...

Static classes only have a single instance. You don't new them. You access them via the class name:

GameState.ToggleA = true;
DoStuff(GameState.b);

etc.

Each of your properties have to be static too:

public static bool ToggleA {get;set;} ...

Static classes are essentially equivalent to the Singleton pattern in this case.

Upvotes: 2

Related Questions