用临时属性覆盖对象属性
本文关键字:属性 覆盖 对象 | 更新日期: 2023-09-27 18:25:17
我很难弄清楚如何构建它。
我有一个类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
。temp值在循环结束时被提交给常规值。
问题如下:
passengers = passengers - 1;
passengers += 1
变为:
_temp_passengers = _passengers - 1;
编辑:
为了进一步解释这个问题,想象10辆车影响车辆A,乘客增加1。每位乘客离开自己的车辆,登上车辆A.
因此,操作passengers += 1
会被调用10次,但它将像只调用了一次一样!
有没有设计模式可以解决这个问题?
我可以像这样将每个属性包装在一个类中吗?
我可以在
set{}
中添加+=
和-=
条件吗?
有什么想法吗?谢谢!:)
只需使用一种延迟执行
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);
让我们试试
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;
}
}
我想这就是你所需要的
作为对一个相当古老的问题的最后评论,我认为"重叠属性"不适合这里。您正试图将模型的两种不同状态混合到一个实例中。您已经报告了由此带来的一些问题。此外,代码将难以理解和维护。
相反,使用模型M
的两个版本,表示两个迭代n
和n+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]);
}