如何创建一个始终与自身实例相同并用于跟踪变量值的类
本文关键字:实例 用于 跟踪 变量值 创建 何创建 一个 | 更新日期: 2023-09-27 17:59:00
所以我想把所有重要的变量外包给一个新的类。一个不起作用的例子来展示我试图做的事情是:
public class GameState{
public bool ToggleA{ get; set; }
public bool ToggleB{ get; set; }
public int a{ get; set; }
public int b{ get; set; }
}
一旦设置了值,我如何"保持这个类的活力",并使所有内容都引用同一个实例?我在谷歌上的搜索让我找到了辛格尔顿模式(链接,但这并没有让我走得更远,要么我不知道如何正确地将我想做的事情实现到它们中,在这种情况下,一个深入的例子会很好,要么我需要使用其他东西?
使其成为一个静态类。
public static class GameState ...
静态类只有一个实例。你没有new
他们。您可以通过类名访问它们:
GameState.ToggleA = true;
DoStuff(GameState.b);
等等。
您的每个属性也必须是静态的:
public static bool ToggleA {get;set;} ...
在这种情况下,静态类本质上等同于Singleton模式。
实现这一点的最佳方式实际上是使用单例设计模式。它将允许您的代码保持可测试性。
给定以下接口:
public interface IGameState
{
bool ToggleA { get; set; }
bool ToggleB { get; set; }
int A { get; set; }
int B { get; set; }
}
以下是它的单例实现:
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; }
}
现在,您可以在任何需要的地方注入这个singleton,这将保持代码的测试能力。
public class SomeObject
{
private IGameState _gameState;
public SomeObject(IGameState gameState)
{
_gameState = gameState;
}
public void SomeOperationOnGameState()
{
_gameState.ToggleA = true;
}
}
编辑:更新以解释测试相关评论
想象一下,您的GameState对象evolution有一个用于执行计算的复杂方法,并且您希望确保在必要时调用该方法。如果您使用的是全局静态类,则无法验证此行为。然而,如果您正在对接口进行编程,则可以使用mocking框架来模拟这种依赖关系,并验证是否确实调用了复杂方法。
例如,我们将把IGameState
接口扩展到以下内容:
public interface IGameState
{
bool ToggleA { get; set; }
bool ToggleB { get; set; }
int A { get; set; }
int B { get; set; }
int ComplexStateAlteringMethod();
}
现在假设您有某种Controller类,用于管理按键:
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();
}
}
}
您要确保按下"A"键时,会调用IGameState.ComplexStateAlteringMethod()
。
在不解释mock的情况下,我将创建一个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;
}
}
现在您可以使用这个存根类来验证您正在寻找的行为(假设NUnit是测试框架):
[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);
}
}