C# 这是什么设计模式?
很久以前我做过一次,当时我遵循了一种设计模式。现在,我需要再做一次,我真的不记得我以前是怎么做的,我想不出是什么样的模式帮了我 我有一个包含大量变量/属性的类。有些是基于其他属性计算的,这些属性之间存在各种交叉计算 当我第一次实例化时,一切都很好——所有的值和计算都很好。我的问题是,当一个值更改时,我希望从中派生的所有计算值根据新值自动更新自己。如果不需要的话,我也不想手动编写每个recalc——每当这个类被更新或添加到其中,试图跟踪所有需要传播任何更改的地方,这都会增加很多开销 我想你跟着我 不管怎样,谁能想到是什么样的模式使这成为可能?我发誓我以前知道。我想是变老了C# 这是什么设计模式?,c#,design-patterns,C#,Design Patterns,很久以前我做过一次,当时我遵循了一种设计模式。现在,我需要再做一次,我真的不记得我以前是怎么做的,我想不出是什么样的模式帮了我 我有一个包含大量变量/属性的类。有些是基于其他属性计算的,这些属性之间存在各种交叉计算 当我第一次实例化时,一切都很好——所有的值和计算都很好。我的问题是,当一个值更改时,我希望从中派生的所有计算值根据新值自动更新自己。如果不需要的话,我也不想手动编写每个recalc——每当这个类被更新或添加到其中,试图跟踪所有需要传播任何更改的地方,这都会增加很多开销 我想你跟着我
// Like this...
class foo
{
decimal A = 1233;
decimal B = 42;
decimal C = A / B; // I want this to update whenever
// the value of either A or B changes.
decimal D = 123;
decimal E = 321;
decimal F = D + E; // I don't want this one to change when
// A or B or even C for that matter changes,
// and I don't wan to have to cycle through
// all of the calculated values that don't
// need to change just for find the few that do.
}
观察员。您需要在模型上使用某种类型的
.Subscribe()
方法来注册回调—在您的特定情况下,这些函数只是接受新值并基于该值重新计算其他函数的函数。只要您的编程环境有实现,我强烈建议您坚持使用该实现。否则,您将因为多线程和内存泄漏而蒙受损失 我建议在这里避免过度设计。您作为示例展示的有6个成员,它们之间有简单的依赖关系,可以轻松地重新计算。我知道这只是一个简单的例子,所以让我们针对10-20个成员,以及不需要数据库查找或磁盘访问的依赖项(作为较重操作的示例)
您可以将所有依赖项放在一个方法中(我们称之为Update
),如果任何成员被修改,您将调用该方法。为了避免忘记调用Update()
,您将所有成员移动到一个单独的“state”类中:
你得到的是:
- 事情马上就清楚了。给任何一个碰巧遇到你的人 修改此代码李>
- 成员之间的所有依赖项都在一个方法中,易于阅读和修改。您的业务逻辑不会被这些细节所污染李>
- 您不能忘记重新计算您的从属成员李>
- 是的,您可以进行比严格要求更多的重新计算,因为即使修改了不相关的成员,您也可以重新计算所有从属成员。在我在真实文件中看到的大多数类似案例中,这都不是问题
- 如果您有循环依赖关系(这是另一种情况),这种方法就不起作用
我认为这种简单的方法没有名字。不要把它与“状态”模式混淆,这是一件有点不同的事情。我想不出任何模式。但是INotifyPropertyChanged在类本身注册更改事件以进行重新计算的地方可以工作。最大的危险是你可能会在一个infinite更新循环中结束:a改变B,B改变a。特别是对于浮点inprecision,这种危险是非常真实的。谢谢Christopher,我来看看这个。这样的计算不是乱伦的,所以没有无限循环的危险,但感谢提醒。这不是一种设计模式,但这符合可观测的描述。事件驱动架构模式?(埃达)艾米——看着观察到的东西,我的记忆又回来了——就是这样!谢谢你让一个老黑客动脑筋!观察员…听起来很熟悉。谢谢我会查一查,看看它是否管用。@KevinPaulTracy,它会管用的:它是专门为此设计的。只是不要自己实现它,而是采用
rxjs
或您的环境中现有的类似机制。有些平台,比如.NET,提供了默认的实现,对于简单的情况来说已经足够了。不要认为RXJS可以工作-这不是一个UI,它是一个后端解决方案。但这种模式看起来可能是这样的。我来看看,谢谢。网络有反应式扩展。在我看来,这太过分了,但功能非常强大。@KevinPaulTracy,它可以与UI和后端一起工作。由于现代UI的事件驱动起源,它与UI的配合更加自然。请检查您是否支持.NET。它几乎不可测试、不线程安全、几乎不可扩展、非泛型,并且依赖于隐式状态而不是干净的纯函数-1和-10,如果我能做到的话。我明白你的意思,但是这个解决方案仍然比我想要的更需要维护。但是谢谢!
class FooState
{
private int _a;
public int A
{
get { return _a; }
set
{
_a = value;
Update();
}
}
private int _b;
public int B
{
get { return _b; }
set
{
_b = value;
Update();
}
}
public double C { get; private set; }
// other members
private void Update()
{
C = A * B + 3;
// other updates
}
}
class Foo
{
private FooState _state;
public Foo()
{
_state.A = 1;
_state.B = 2;
Debug.Write($"C = {_state.C}");
}
}