2

我无法弄清楚如何构建它。

我有一个类VehicleState,其属性包括passengers

public class VehicleState
{
    public int _temp_passengers;
    public int _passengers;
    public int passengers
    {
        set { _temp_passengers = value; }
        get { return _passengers; }
    }
    public void CommitState()
    {
        _passengers = _temp_passengers;
    }
}

有一个每 X 秒触发一次的循环。每辆车都会在模拟中影响另一辆车。

为了避免在每辆车影响其他车辆时破坏属性,我将它们存储在临时字段中,例如_passengers. 临时值在循环结束时被提交为常规值。


问题如下:

passengers = passengers - 1;
passengers += 1

变成:

_temp_passengers = _passengers - 1;

编辑:

为了进一步解释这个问题,假设有 10 辆车辆影响 A 车辆,乘客增加 1 人。每位乘客离开他们的车辆登上车辆 A。

所以该操作passengers += 1将被调用 10 次,但它就像该操作只被调用一次一样!


  • 有没有设计模式可以解决这个问题?

  • 我可以将这样的每个属性包装在一个类中吗?

  • 我可以在其中添加+=-=条件set{}吗?

有任何想法吗?谢谢!:)

4

3 回答 3

2

只需使用一种延迟执行

public class VehicleState
{
    List<Action> actionList = new List<Action>();

    public int passengers { get; set; }

    public void CommitState()
    {
        foreach (var action in actionList)
        {
            action();
        }
    }

    public void Execute(Action action)
    {
        actionList.Add(action);
    }
}

测试

    [TestMethod]
    public void MyTestMethod()
    {
        var vs = new VehicleState { passengers = 3 };
        vs.Execute(() => vs.passengers += 1);
        Assert.AreEqual(3, vs.passengers);
        vs.CommitState();
        Assert.AreEqual(4, vs.passengers);

    }

此解决方案的局限性

该解决方案仅提供延迟执行。根据您的情况,这可能有用或没有用。

var vs1 = new VehicleState { passengers = 3 };
var vs2 = new VehicleState { passengers = 3 };

vs1.Execute(() => vs1.passengers += vs2.passengers);
// vs2.Execute(() => vs2.passengers -= vs1.passengers); // does not work

// remember state before 
var beforeVs1passengers = vs1.passengers;
vs2.Execute(() => vs2.passengers -= beforeVs1passengers);  // that works

vs1.CommitState();  // order might be important, no common state, no stack
vs2.CommitState();
Assert.AreEqual(6, vs1.passengers);
Assert.AreEqual(0, vs2.passengers);
于 2013-07-30T06:38:33.090 回答
0

我们试试看

public class VehicleState
{
    public float _passengers;
    public float _CommitedPassengers;
    public float passengers
    {
        set { _passengers = value; }
        get { return _passengers; }
    }

    public float CommitedPassengers
    {
        get { return _CommitedPassengers; }
    }

    public void CommitState()
    {
        _CommitedPassengers = _passengers;

    }
} 

我想这就是你所需要的

于 2013-07-29T14:19:31.487 回答
0

作为对一个相当老的问题的最新评论 - 我认为“叠加属性”在这里不合适。您正在尝试将模型的两种不同状态混合到一个实例中。您已经报告了这带来的一些问题。此外,代码将难以理解和维护。

相反,使用模型的两个版本M,代表两次迭代的状态nn+1。您的计算将M[n]作为其输入并生成/修改M[n+1]作为其输出。

然后,您需要一种将新状态从您的复制nextModel到的方法currentModel

var currentModel = new Model();

for (var n in Enumerable.Range(0, 99))
{
    var nextModel = calculate(currentModel);

    currentModel.UpdateFrom(nextModel);
}

Model我指的是所有车辆的整体以及模拟中的任何其他内容,calculate我指的是在一次迭代中完成的所有计算的整体。

这与您所做的很接近,它只是收集您的“保留两个状态并稍后复制”逻辑,该逻辑分布在所有属性中,并放在一个名为UpdateFrom. 拥有两个模型实例可以让您非常清楚地了解计算所基于的模型状态:

nextModel.Vehicles[0].passengers =
    nextModel.Vehicles[0].passengers + currentModel.Vehicles[1].passengers

一旦您有多个实例,您还可以选择更多地转向函数式编程风格,在每次迭代中生成一个新模型并丢弃旧状态(或者如果需要,将其保留为记录):

var model = new Model[100];
model[0] = new Model();

for (var n in Enumerable.Range(0, 99))
{
    // either throw away old state and keep a reference to the new state only
    var currentModel = calculate(currentModel);

    // or keep all states
    model[n+1] = calculate(model[n]);
}
于 2014-06-10T07:26:13.887 回答